与ItemsControl的双向绑定 [英] TwoWay Binding With ItemsControl
问题描述
我正在尝试编写一个具有ItemsControl的用户控件,该控件的ItemsTemplate包含一个允许TwoWay绑定的TextBox.但是,我肯定在我的代码中的某个地方犯了一个错误,因为绑定似乎仅在Mode = OneWay的情况下起作用.这是我的项目的相当简化的摘录,但仍然包含问题:
I'm trying to write a user control that has an ItemsControl, the ItemsTemplate of which contains a TextBox that will allow for TwoWay binding. However, I must be making a mistake somewhere in my code, because the binding only appears to work as if Mode=OneWay. This is a pretty simplified excerpt from my project, but it still contains the 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's the code behind 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);
}
}
}
最后,这是主窗口的xaml:
And finally, here's 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>
好,这就是全部.我不确定为什么在窗口中编辑TextBox.Text属性似乎没有更新后面代码(即MyCollection)中绑定的源属性.单击按钮几乎会导致问题盯着我;)请帮助我了解我要去哪里.
Well, that's everything. I'm not sure why editing the TextBox.Text properties in the window does not seem to update the source property for the binding in the code behind, namely MyCollection. Clicking on the button pretty much causes the problem to stare me in the face;) Please help me understand where I'm going wrong.
感谢!
安德鲁
推荐答案
好吧,我相信导致此问题的原因是您直接绑定到String
.字符串在C#中是不可变的,因此,当您更改文本时,它不能更改ObservableCollection
中的基础字符串.要解决此问题,您可以做的只是创建一个模型类来保存字符串数据,然后将TextBox.Text
绑定到该类中的属性.这是一个示例:
Ok I believe what is causing this problem is that you are binding directly to a String
. Strings are immutable in C# and thus when you change the text, it cannot change the underlying string in the ObservableCollection
. What you can do to get around this problem is simply create a model class to hold the string data, and then bind the TextBox.Text
to a property inside that 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;
}
}
请注意,我已将您的依赖项属性更改为标准属性-没有理由将集合设为依赖项属性.除此之外,唯一的区别是包含包装器类TestItem
来保存字符串数据.
Notice that I changed your dependency property to a standard property- there is no reason to make the collection a dependency property. Besides that the only difference is the inclusion of the wrapper class TestItem
to hold the 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>
现在TextBox
已绑定到TestItem
上的Name
路径,并且此绑定可以正常工作并按预期修改集合.
Now the TextBox
is bound to the Name
path on TestItem
, and this binding works and modifies the collection as expected.
这篇关于与ItemsControl的双向绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!