C# 更改集合时 WPF 组合框不更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19566505/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF Combobox not updating when collection is changed
提问by Ganesh Satpute
I am new to WPF.
我是 WPF 的新手。
I am trying to bind collection of string to combobox.
我正在尝试将字符串集合绑定到组合框。
public ObservableCollection<string> ListString {get; set;}
Binding and datacontext are set as follows
绑定和数据上下文设置如下
<Window
x:Class="Assignment2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:validators="clr-namespace:Assignment2"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}">
<Grid>
<ComboBox Height="23" HorizontalAlignment="Left" Margin="109,103,0,0" Name="StringComboBox" VerticalAlignment="Top" Width="120" SelectionChanged="StringComboBox_SelectionChanged">
<ComboBox.ItemsSource>
<Binding Path="ListString" BindsDirectlyToSource="True" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"></Binding>
</ComboBox.ItemsSource>
</ComboBox>
I came to know that this is happening because collection is updating. If I write
我开始知道这是因为收藏正在更新。如果我写
public MainWindow()
{
InputString = "";
ListString = new ObservableCollection<string>();
ListString.Add("AAA");
ListString.Add("BBB");
ListString.Add("CCC");
InitializeComponent();
}
It does work but if I am move InitializeComponent()
above at first line as follows, it doesn't work.
它确实有效,但如果我InitializeComponent()
按如下方式在第一行上方移动,则它不起作用。
public MainWindow()
{
InitializeComponent();
InputString = "";
ListString = new ObservableCollection<string>();
ListString.Add("AAA");
ListString.Add("BBB");
ListString.Add("CCC");
}
What Should I do??
我该怎么办??
采纳答案by Ganesh Satpute
Solved the problem. Implemented INotifyPropertyChanged as follows
解决了问题。实现 INotifyPropertyChanged 如下
public partial class MainWindow : Window, INotifyPropertyChanged
modified the accessors as follows
修改了访问器如下
private ObservableCollection<string> listString;
public ObservableCollection<string> ListString
{
get
{
return listString;
}
set
{
listString = value;
NotifyPropertyChanged("ListString"); // method implemented below
}
}
and added the following event and method to raise the event
并添加了以下事件和方法来引发事件
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(name));
}
}
and it works B)
它有效 B)
回答by blindmeis
what happens if you change your code to
如果您将代码更改为
<Window
x:Class="Assignment2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:validators="clr-namespace:Assignment2"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox Height="23" HorizontalAlignment="Left" Margin="109,103,0,0" Name="StringComboBox" VerticalAlignment="Top" Width="120" SelectionChanged="StringComboBox_SelectionChanged"
ItemsSource="{Binding ListString, Mode=OneWay}"/>
cs.
CS。
public MainWindow()
{
InitializeComponent();
InputString = "";
ListString = new ObservableCollection<string>();
ListString.Add("AAA");
ListString.Add("BBB");
ListString.Add("CCC");
this.DataContext=this;
}
btw: setting the ItemsSource with mode=twoway makes no sense to me. your combobox will never "create a new itemssource" for your viewmodel.
顺便说一句:使用 mode=twoway 设置 ItemsSource 对我来说毫无意义。您的组合框永远不会为您的视图模型“创建新的项目源”。
EDIT: i think your first solution works because of setting the DataContext in xaml. i assume that DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}" is execute when calling InitializeComponent(); and because your ListString property is just an autoproperty and not implement INotifyPropertyChanged - your mainwindowview does not get notified that your ctor creates a new ListString property.
编辑:我认为您的第一个解决方案有效,因为在 xaml 中设置了 DataContext。我假设 DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}" 在调用 InitializeComponent() 时执行;并且因为您的 ListString 属性只是一个自动属性而不是实现 INotifyPropertyChanged - 您的 mainwindowview 不会收到您的 ctor 创建一个新的 ListString 属性的通知。
public ObservableCollection<string> ListString {get{return _list;}; set{_list=value; OnPropertyChanged("ListString");}}
should work with both of your approaches, but you have to implement INotifyPropertyChanged for your MainWindow class.
应该适用于您的两种方法,但您必须为 MainWindow 类实现 INotifyPropertyChanged。
回答by Jason
You can set the item source for combobox in code behind or set datacontext again after your list is populated or you can go with inotifychanged to raise property change.
您可以在后面的代码中设置组合框的项目源或在填充列表后再次设置数据上下文,或者您可以使用 inotifychanged 来引发属性更改。
public MainWindow()
{
InitializeComponent();
InputString = "";
ListString = new ObservableCollection<string>();
ListString.Add("AAA");
ListString.Add("BBB");
ListString.Add("CCC");
StringComboBox.ItemsSource = ListString;
}
回答by Assimilater
Seems to me the problem was "newing up" ListString
. Making it a property (the selected answer) is one way around that. Alternatively inlining the instantation, or putting it before InitializeComponent
I believe would be ok.
在我看来,问题是“更新” ListString
。使它成为一个属性(选定的答案)是解决这个问题的一种方法。或者内联实例化,或者将它放在InitializeComponent
我认为可以的之前。
If newing up is expected to occur often it might be helpful to encapsulate the ObservableCollection
in a manager class. I found this question after troubleshooting my own issues with such a setup. I got it working by implementing INotifyCollectionChanged
and forwarding the event like so
如果预计经常更新,将 封装ObservableCollection
在管理器类中可能会有所帮助。我在使用这种设置解决了我自己的问题后发现了这个问题。我通过INotifyCollectionChanged
像这样实现和转发事件来让它工作
/// <summary>
/// Maintains an observable (i.e. good for binding) collection of resources that can be indexed by name or alias
/// </summary>
/// <typeparam name="RT">Resource Type: the type of resource associated with this collection</typeparam>
public class ResourceCollection<RT> : IEnumerable, INotifyCollectionChanged
where RT : class, IResource, new()
{
public event NotifyCollectionChangedEventHandler CollectionChanged
{
add { Ports.CollectionChanged += value; }
remove { Ports.CollectionChanged -= value; }
}
public IEnumerator GetEnumerator() { return Ports.GetEnumerator(); }
private ObservableCollection<RT> Ports { get; set; }
private Dictionary<string, RT> ByAlias { get; set; }
private Dictionary<string, RT> ByName { get; set; }
}