WPF C# ObservableCollection 不更新 GUI

Dan*_*ane 5 c# wpf user-interface observablecollection mvvm

感谢tencntraze的建议,这个问题已经解决了。

请参阅此问题的底部和 tencntraze 的答案以获取解决方案。

我的程序中有一个相当奇怪的错误,我目前正在努力解决它。

我正在开发一个 MVVM 应用程序,我的视图中有一个简单的 ListBox,其 ItemsSource 绑定到字符串的 ObservableCollection。每当我向此集合添加一个项目时,它都会触发一个事件来通知集合已更改,但这在运行时不会反映在 GUI 上,除非我尝试在程序运行时手动调整窗口大小,几乎就像调整窗口大小会强制 GUI 刷新一样。

相关控件的XAML如下

<ListBox ItemsSource="{Binding Path=LogWindow}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0,0,0,0" />
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,这是完全正常的。在此视图的 ViewModel 中,我有一个名为 LogWindow 的公共属性,定义如下

public ObservableCollection<string> LogWindow
    {
        get
        {
            return _logWindow;
        }

        set
        {
            _logWindow = value;
            OnPropertyChanged("LogWindow");
        }
    }
Run Code Online (Sandbox Code Playgroud)

其私人成员如下

private ObservableCollection<string> _logWindow;
Run Code Online (Sandbox Code Playgroud)

在 ViewModel 构造函数中,我初始化 _logWindow 并将 LogWindow CollectionChanged 事件连接到处理程序,该处理程序进而触发 PropertyChanged 通知。

我的代码如下

public MainWindowViewModel(IDialogService dialogService)
        {
            ... skipped for brevity
            LogWindow = new ObservableCollection<string>();
            LogWindow.CollectionChanged += LogWindow_CollectionChanged;
            ...
        }
Run Code Online (Sandbox Code Playgroud)

CollectionChanged事件处理程序如下

void LogWindow_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnPropertyChanged("LogWindow");
        }
Run Code Online (Sandbox Code Playgroud)

最后,当我的视图收到来自模型的新消息的通知时,我将一个新字符串添加到可观察集合中,如下所示

LogWindow.Add(_vehicleWeightManager.SerialMessage);
Run Code Online (Sandbox Code Playgroud)

当 LogWindow.Add 发生时,我的事件侦听器将触发,并且我的断点被命中以确认代码达到了如下所示的程度 将新字符串添加到集合时遇到断点... 通知集合已更改事件参数

在此之后,我的代码调用从 ViewModelBase 继承的 OnPropertyChanged 函数,该函数对于我的其他 GUI 元素(例如标签等)来说效果很好,因此几乎可以肯定不是问题。

我对 LogWindow 应用了一个监视来跟踪集合确实被添加到,如下图所示 日志窗口监视

所以现阶段我很茫然。仅当我以某种方式调整窗口大小时,我的 GUI 才会更新,否则没有视觉更新。数据存在于绑定的属性中,据我所知,当将新项目添加到属性中时,GUI 会收到警报...有人有任何可能有帮助的见解吗?

感谢 tencntraze 和 kallocain 的建议,这个问题已经解决。

该问题是由另一个线程尝试添加到 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();
            }
        }
Run Code Online (Sandbox Code Playgroud)

有关上述方法的进一步阅读可以在这里找到

Mat*_*att 5

如果您在另一个线程上接收消息,则需要将其调用回 UI 线程,否则可能会出现不可预测的行为。有时这是一个例外,有时却什么也不做。

this.Dispatcher.BeginInvoke(new Action(() =>
{
    LogWindow.Add(_vehicleWeightManager.SerialMessage);
}));
Run Code Online (Sandbox Code Playgroud)