WPF C# ObservableCollection 不更新 GUI
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22176288/
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 C# ObservableCollection Not updating GUI
提问by Daniel Lane
Thanks to the advice of tencntraze this question has been solved.
感谢tencntraze的建议,这个问题已经解决了。
See the bottom of this question and tencntraze's answer for the solution.
请参阅此问题的底部和tencntraze 的答案以获取解决方案。
I have a rather strange bug in my program that I'm currently wrestling with.
我的程序中有一个相当奇怪的错误,我目前正在处理这个错误。
I'm developing an MVVM application, and I have a simple ListBox in my View with its ItemsSource bound to an ObservableCollection of strings. Whenever I add an item to this collection, it /does/ fire an event to notify that the collection has changed, yet this isn't reflected on the GUI during run-time unless I attempt to manually resize the window as the program is running, almost as if a resizing the window forces the GUI to refresh.
我正在开发一个 MVVM 应用程序,我的视图中有一个简单的 ListBox,它的 ItemsSource 绑定到一个 ObservableCollection 的字符串。每当我向这个集合添加一个项目时,它/确实/会触发一个事件来通知集合已更改,但这不会在运行时反映在 GUI 上,除非我尝试在程序运行时手动调整窗口大小,几乎就像调整窗口大小会强制刷新 GUI。
The XAML for the relevant control is as follows
相关控件的XAML如下
<ListBox ItemsSource="{Binding Path=LogWindow}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0,0,0,0" />
Which as you can see is perfectly normal. In my ViewModel for this view, I have a public property called LogWindow defined as follows
如您所见,这是完全正常的。在此视图的 ViewModel 中,我有一个名为 LogWindow 的公共属性,定义如下
public ObservableCollection<string> LogWindow
{
get
{
return _logWindow;
}
set
{
_logWindow = value;
OnPropertyChanged("LogWindow");
}
}
The private member for this is as follows
私有成员如下
private ObservableCollection<string> _logWindow;
In the ViewModel constructor I initialize _logWindow and wire up LogWindow CollectionChanged event to a handler which in turn fires a PropertyChanged notification.
在 ViewModel 构造函数中,我初始化 _logWindow 并将 LogWindow CollectionChanged 事件连接到一个处理程序,该处理程序依次触发 PropertyChanged 通知。
My code for this is as follows
我的代码如下
public MainWindowViewModel(IDialogService dialogService)
{
... skipped for brevity
LogWindow = new ObservableCollection<string>();
LogWindow.CollectionChanged += LogWindow_CollectionChanged;
...
}
The CollectionChanged event handler is as follows
CollectionChanged 事件处理程序如下
void LogWindow_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged("LogWindow");
}
And finally when my View receives notification that it has received a new message from the Model, I add a new string to the observable collection as follows
最后,当我的视图收到通知,它已收到来自模型的新消息时,我将一个新字符串添加到可观察集合中,如下所示
LogWindow.Add(_vehicleWeightManager.SerialMessage);
When LogWindow.Add happens, my event listener fires and my breakpoint is hit to confirm the code gets that far as illustrated below


当 LogWindow.Add 发生时,我的事件侦听器会触发并命中我的断点以确认代码达到了如下所示的程度


After this my code calls the OnPropertyChanged function which is inherited from my ViewModelBase, this functions fine for my other GUI elements such as labels and the like, so that almost certainly isn't the issue.
在此之后,我的代码调用从我的 ViewModelBase 继承的 OnPropertyChanged 函数,该函数适用于我的其他 GUI 元素,例如标签等,因此几乎可以肯定这不是问题。
I applied a watch to LogWindow to keep track that the collection was indeed being added to, and it is as illustrated below

我在 LogWindow 上应用了一个 watch 来跟踪集合确实被添加到了,如下图所示

So at this stage I'm at a loss. My GUI will only update if I resize the window in some way, otherwise there is no visual update. The data is present in the bound property, and afaik the GUI is alerted when a new item is added to the property... Does anyone have any insight that may help?
所以在这个阶段我不知所措。我的 GUI 只会在我以某种方式调整窗口大小时更新,否则没有视觉更新。数据存在于绑定属性中,并且当向属性添加新项目时,GUI 会收到警报......有没有人有任何可能有帮助的见解?
Thanks to the advice of tencntraze and kallocain this has been solved.
多亏了tencntraze和kallocain的建议,这已经解决了。
The problem was caused by another thread attempting to add to the LogWindow collection which was causing erroneous behaviour. Rather than use Dispatcher as suggested, I used a TaskFactory code as follows.
该问题是由另一个线程试图添加到导致错误行为的 LogWindow 集合引起的。我没有按照建议使用 Dispatcher,而是使用了 TaskFactory 代码,如下所示。
TaskFactory uiFactory;
...
...
public MainWindowViewModel(IDialogService dialogService)
{
...
_logWindow = new ObservableCollection<string>();
uiFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
}
...
...
void _vehicleWeightManager_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
...
if (e.PropertyName == "VehicleWeight")
{
// Marshal the SerialMessage property to the GUI thread.
uiFactory.StartNew(() => LogWindow.Add(_vehicleWeightManager.SerialMessage.Replace("\n", ""))).Wait();
}
}
Further reading for the above method can be found here
可以在此处找到有关上述方法的进一步阅读
采纳答案by Matt
If you're receiving the message on another thread, you'll need to invoke it back to the UI thread, otherwise there can be unpredictable behavior. Sometimes this is an exception, other times it works out to do nothing.
如果您在另一个线程上接收消息,则需要将其调用回 UI 线程,否则可能会出现不可预测的行为。有时这是一个例外,其他时候它什么都不做。
this.Dispatcher.BeginInvoke(new Action(() =>
{
LogWindow.Add(_vehicleWeightManager.SerialMessage);
}));

