TwoWay Binding With ItemsControl

I am trying to write a user control that has an ItemsControl element whose ItemTemplate contains a text box that will allow TwoWay to bind. However, I have to make a mistake somewhere in my code, because the binding only works as if Mode = OneWay. This is a pretty simplified excerpt from my project, but it still contains a problem:

<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> 

Here is the code for the above control:

 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); } } } 

And finally, here is the xaml for the main window:

 <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> 

Well, that's all. I am not sure why editing the TextBox.Text properties in the window does not seem to update the source property for the code binding, namely MyCollection. Pressing the button pretty much makes the problem look me in the face;) Please help me understand what I'm wrong about.

Thanx!

Andrew

+6
wpf binding itemscontrol
source share
1 answer

Good. I believe the cause of this problem is that you are binding directly to String . Lines are immutable in C #, and so when changing text, it cannot change the main line in an ObservableCollection . What you can do to get around this problem is to simply create a model class to hold the string data, and then bind TextBox.Text to the property inside this class. Here is an example:

 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; } } 

Note that I changed the dependency property to a standard property - there is no reason to make the collection's dependency property. In addition, the only difference is the inclusion of the TestItem wrapper TestItem to store string data.

 <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> 

Now the TextBox bound to the Name path on TestItem , and this binding works and modifies the collection as expected.

+7
source share

All Articles