Wpf 使用ItemsControl进行双向绑定

Wpf 使用ItemsControl进行双向绑定,wpf,binding,itemscontrol,Wpf,Binding,Itemscontrol,我正在尝试编写一个具有ItemsControl的用户控件,它的ItemsTemplate包含一个允许双向绑定的文本框。但是,我的代码中肯定有错误,因为绑定似乎只在Mode=OneWay的情况下工作。这是我的项目的一个相当简化的摘录,但它仍然包含以下问题: <UserControl x:Class="ItemsControlTest.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati

我正在尝试编写一个具有ItemsControl的用户控件,它的ItemsTemplate包含一个允许双向绑定的文本框。但是,我的代码中肯定有错误,因为绑定似乎只在Mode=OneWay的情况下工作。这是我的项目的一个相当简化的摘录,但它仍然包含以下问题:

<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);
        }
    }
}
使用系统;
使用System.Windows;
使用System.Windows.Controls;
使用System.Collections.ObjectModel;
命名空间项控件测试
{
/// 
///UserControl1.xaml的交互逻辑
/// 
公共部分类UserControl1:UserControl
{
公共可观测集合MyCollection
{
get{return(ObservableCollection)GetValue(MyCollectionProperty);}
set{SetValue(MyCollectionProperty,value);}
}
//使用DependencyProperty作为MyCollection的备份存储。这将启用动画、样式、绑定等。。。
公共静态只读DependencyProperty MyCollectionProperty=
DependencyProperty.Register(“MyCollection”,
类型(可观测采集),
类型(用户控制1),
新的UIPropertyMetadata(新的ObservableCollection());
公共用户控制1()
{
对于(int i=0;i<6;i++)
MyCollection.Add(“字符串”+i.ToString());
初始化组件();
myItemsControl.DataContext=this.MyCollection;
}
私有无效按钮\u单击(对象发送者,路由目标e)
{
//在MyCollection的第三个元素后插入字符串
MyCollection.插入(3,“插入项”);
//在消息框中显示MyCollection的内容
字符串str=“”;
foreach(MyCollection中的字符串s)
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>

好了,就这些。我不知道为什么编辑文本框。窗口中的文本属性似乎不会更新代码背后绑定的源属性,即MyCollection。点击按钮几乎会导致问题直视我;)请帮助我理解我的错误所在

塔克斯


Andrew

好的,我认为导致此问题的原因是您直接绑定到
字符串。字符串在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;
    }
}


现在,
TextBox
被绑定到
TestItem
上的
Name
路径,这个绑定可以正常工作并按预期修改集合。

这太棒了,Charlie,看起来你成功了。你的建议很有效!
<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>