C# 绑定到列表<;字符串>;不更新相应的字符串
我有以下XAML代码:C# 绑定到列表<;字符串>;不更新相应的字符串,c#,wpf,data-binding,C#,Wpf,Data Binding,我有以下XAML代码: <Window x:Class="WpfApplication1.MainWindow" x:Name="window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schem
<Window x:Class="WpfApplication1.MainWindow"
x:Name="window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="327" Width="213"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Strings}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=., UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Grid.Row="1" Text="{Binding TheString}" />
<Button Click="ButtonBase_OnClick" Grid.Row="2">Check strings</Button>
</Grid>
</Window>
检查字符串
很简单。下面是我的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
public List<string> Strings { get; } = new List<string> { "Hello world1", "Hello world2", "Hello world3" };
public string TheString { get; set; } = "Helloo";
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Join("\n", this.Strings) + $"\n\n{this.TheString}");
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
this.InitializeComponent();
}
公共列表字符串{get;}=新列表{“Hello world1”、“Hello world2”、“Hello world3”};
公共字符串字符串{get;set;}=“Helloo”;
private void按钮base_OnClick(对象发送方,RoutedEventTarget e)
{
Show(string.Join(“\n”,this.Strings)+$”\n\n{this.TheString});
}
}
问题是,如果我从UI更新Strings
列表中的字符串值,当我单击按钮时,它永远不会更新。我做错了什么?我已将
列表框
的项资源
正确绑定到字符串
列表。我还在项目模板
中正确绑定了文本框
变化
public List<string> Strings { get; } = new List<string> { "Hello world1", "Hello world2", "Hello world3" };
公共列表字符串{get;}=新列表{“Hello world1”、“Hello world2”、“Hello world3”};
到
公共列表字符串{get;set;}=新列表{“Hello world1”、“Hello world2”、“Hello world3”};
如果没有setter,即使绑定了该属性,也无法更新该属性。我认为您的问题在于绑定的列表类型。尝试改用ObservableCollection
public ObservableCollection<string> Strings { get; } = new ObservableCollection<string> { "Hello world1", "Hello world2", "Hello world3" };
public observetecollection Strings{get;}=new observetecollection{“Hello world1”、“Hello world2”、“Hello world3”};
也许这会奏效。您遇到的问题是关于
字符串的不变性。更改文本框中的文本时,创建新的字符串
,旧字符串不会更改。因此,列表始终包含相同的值
要更新它,您应该将其包装在实现INotifyPropertyChanged的类中,并在setter中触发PropertyChanged事件。此外,还应更改对此新属性的绑定。例如:
public class Wrapper : INotifyPropertyChanged
{
private string _value;
public string Value
{
get { return _value; }
set
{
_value = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
}
}
//INotifyPropertyChanged implementation...
}
你的名单应该是:
public List<MyClass> Strings { get; } = new List<MyClass>
{
new Wrapper { Value = "Hello world1" },
new Wrapper { Value = "Hello world2" },
new Wrapper { Value = "Hello world3" }
};
<TextBox Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}" />
公共列表字符串{get;}=新列表
{
新包装器{Value=“Hello world1”},
新包装器{Value=“Hello world2”},
新包装器{Value=“Hello world3”}
};
其约束力应为:
public List<MyClass> Strings { get; } = new List<MyClass>
{
new Wrapper { Value = "Hello world1" },
new Wrapper { Value = "Hello world2" },
new Wrapper { Value = "Hello world3" }
};
<TextBox Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}" />
这里有两个问题
首先,您的UI永远不会知道是否用新列表替换列表,因为如果列表被重新实例化,它将不会收到通知
其次,对列表中项目的任何更改,无论是替换值还是添加/删除值,都不会引起注意,因为列表不会引发更改通知
您的最佳解决方案是@qqw2和@Lorek给出的答案的组合
将所有数据从窗口类中移出,并将其放入实现INotifyPropertyChanged的另一个类中。将字符串集合更改为ObservableCollection。
并且还可以在任何属性的setter中引发PropertyChanged事件,尽管这对于ObservableCollection可能不是必需的,只要您只在构造函数中实例化,并且只在需要删除所有条目时调用clear
public class DataViewModel : INotifyPropertyChanged
{
private string _theString;
public DataViewModel()
{
Strings = new ObservableCollection<string>();
}
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<string> Strings { get; set; }
public string TheString
{
get
{
return _theString;
}
set
{
_theString = value;
NotifyPropertyChanged(nameof(TheString));
}
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
并添加一个新属性:
public DataViewModel ViewModel { get; set; }
并将窗口标记上的DataContext绑定更改为指向ViewModel属性
其他信息:
在视图模型上,添加以下方法
public void AddString()
{
Strings.Add(TheString) ;
TheString = string.Empty;
}
然后从按钮点击处理程序调用它 是的,我也面临着这个问题!它似乎与字符串类型的不可变行为有关。我还写了一篇关于解决方案的文章
希望有帮助:)A reach但将mode=twoway添加到TextBox默认的TextBox模式是twoway,但是您的列表没有setter。如果没有Setter,我认为您的集合将是只读的,因此您无法更新它。@Bearcat9425,我不是更新集合本身,而是更新它的成员,这也可以通过getter-only属性完成。您是否尝试在网格上不使用DataContext?如果集合是只读的,那么它的成员也是只读的。试一试推杆;在那个里,看看它是否适合你们。字符串是RW。列表字符串未更新-仅更新项目。仍然值得一试。我实际上是在更新字符串,而不是更改集合。我试了一下,但还是不行。对不起。如果VS现在在前面,我就不在前面,否则我会先测试它。这里有一个理论…当你的文本属性改变时,它们会设置一个新的字符串值,这意味着它们会创建一个新的字符串实例。绑定指向该新字符串,该字符串不是原始列表的成员。该新字符串仅由TextBox的绑定引用。似乎只有将“.”对象绑定到UI容器,然后将子UI元素绑定到该对象上的属性时,集合绑定的简写形式才有用。对于超级简单的情况,它失败了。即使没有INotifyPropertyChanged,它也能工作。但我觉得很奇怪,因为它仍然在做同样的事情,字符串仍然是不可变的,只是包装在另一个类中。我们仍然在更改字符串本身,现在是对这个类的整个引用。它是否与绑定的编写方式有关<代码>{Binding Path=.}
?如果从代码更新字符串并希望文本框显示更新的值,则需要使用INotfiyPropertyChanged
部分。如果你愿意,可以省略它。对于绑定部分,如果更改TextBox中的值,则始终会创建一个新字符串。但是,要更新列表,必须删除旧值并添加新值,这不是绑定的工作方式。当您有一个包装器类时,它只是将您的字符串设置为新值并丢弃旧值(您不能使用列表