2010-05-06 3 views
6

Я пытаюсь написать элемент управления пользователя, который имеет ItemControl, ItemTemplate которого содержит текстовое поле, которое позволит привязку TwoWay. Тем не менее, я должен ошибаться где-то в своем коде, потому что привязка только работает, как будто Mode = OneWay. Это довольно упрощенная выдержка из моего проекта, но он все еще содержит проблему:TwoWay Binding With ItemsControl

<UserControl x:Class="ItemsControlTest.UserControl1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="300" Width="300"> 
    <Grid> 
     <StackPanel> 
      <ItemsControl ItemsSource="{Binding Path=.}" 
          x:Name="myItemsControl"> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <TextBox Text="{Binding Mode=TwoWay, 
               UpdateSourceTrigger=LostFocus, 
               Path=.}" /> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 
      <Button Click="Button_Click" 
        Content="Click Here To Change Focus From ItemsControl" /> 
     </StackPanel> 
    </Grid> 
</UserControl> 

Вот код позади для вышеупомянутого управления:

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Collections.ObjectModel; 

namespace ItemsControlTest 
{ 
    /// <summary> 
    /// Interaction logic for UserControl1.xaml 
    /// </summary> 
    public partial class UserControl1 : UserControl 
    { 
     public ObservableCollection<string> MyCollection 
     { 
      get { return (ObservableCollection<string>)GetValue(MyCollectionProperty); } 
      set { SetValue(MyCollectionProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for MyCollection. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty MyCollectionProperty = 
      DependencyProperty.Register("MyCollection", 
             typeof(ObservableCollection<string>), 
             typeof(UserControl1), 
             new UIPropertyMetadata(new ObservableCollection<string>())); 

     public UserControl1() 
     { 
      for (int i = 0; i < 6; i++) 
       MyCollection.Add("String " + i.ToString()); 

      InitializeComponent(); 

      myItemsControl.DataContext = this.MyCollection; 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      // Insert a string after the third element of MyCollection 
      MyCollection.Insert(3, "Inserted Item"); 

      // Display contents of MyCollection in a MessageBox 
      string str = ""; 
      foreach (string s in MyCollection) 
       str += s + Environment.NewLine; 
      MessageBox.Show(str); 
     } 
    } 
} 

И, наконец, вот XAML для главного окна :

<Window x:Class="ItemsControlTest.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:src="clr-namespace:ItemsControlTest" 
     Title="Window1" Height="300" Width="300"> 
    <Grid> 
     <src:UserControl1 /> 
    </Grid> 
</Window> 

Ну, это все. Я не уверен, почему редактирование свойств TextBox.Text в окне, похоже, не обновляет свойство source для привязки кода, а именно MyCollection. Нажатие на кнопку в значительной степени заставляет проблему смотреть мне в лицо;) Пожалуйста, помогите мне понять, в чем я ошибаюсь.

Thanx!

Эндрю

ответ

7

Хорошо, я считаю, что является причиной этой проблемы является то, что вы связывание непосредственно к String. Строки равны неизменяемым в C#, и поэтому при изменении текста он не может изменить основную строку в ObservableCollection. Что вы можете сделать, чтобы обойти эту проблему, просто создайте класс модели для хранения строковых данных, а затем привяжите TextBox.Text к свойству внутри этого класса. Вот пример:

public partial class BindingToString : Window 
{ 
    public BindingToString() 
    { 
     MyCollection = new ObservableCollection<TestItem>(); 

     for (int i = 0; i < 6; i++) 
      MyCollection.Add(new TestItem("String " + i.ToString())); 

     InitializeComponent(); 

     myItemsControl.DataContext = this.MyCollection; 
    } 

    public ObservableCollection<TestItem> MyCollection 
    { 
     get; 
     set; 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     // Display contents of MyCollection in a MessageBox 
     string str = ""; 
     foreach (TestItem s in MyCollection) 
      str += s.Name + Environment.NewLine; 
     MessageBox.Show(str); 
    } 
} 

public class TestItem 
{ 
    public string Name 
    { 
     get; 
     set; 
    } 

    public TestItem(string name) 
    { 
     Name = name; 
    } 
} 

Обратите внимание, что я изменил свою собственность зависимости к стандартной собственность- нет никаких причин, чтобы сделать коллекцию свойства зависимостей. Кроме того, единственное различие заключается в том, что класс оболочки TestItem содержит строковые данные.

<Window x:Class="TestWpfApplication.BindingToString" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Title="BindingToString " Height="300" Width="300"> 
<Grid> 
    <StackPanel> 
     <ItemsControl ItemsSource="{Binding}" 
         x:Name="myItemsControl"> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
     <Button Click="Button_Click" 
       Content="Click Here To Change Focus From ItemsControl" /> 
    </StackPanel> 
</Grid> 

Теперь TextBox привязан к Name пути на TestItem, и это переплетные работы и изменяет коллекцию, как и ожидалось.

+0

Это замечательно, Чарли, похоже, вы прибили его. Вы предлагаете хорошо работать! – Andrew