WPF C#ObservableCollection不更新GUI

时间:2014-03-04 15:36:18

标签: c# wpf user-interface mvvm observablecollection

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

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

我的程序中有一个相当奇怪的错误,我正在挣扎。

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

相关控制的XAML如下

<ListBox ItemsSource="{Binding Path=LogWindow}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0,0,0,0" />

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

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

        set
        {
            _logWindow = value;
            OnPropertyChanged("LogWindow");
        }
    }

此私人会员如下

private ObservableCollection<string> _logWindow;

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

我的代码如下

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

CollectionChanged事件处理程序如下

void LogWindow_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnPropertyChanged("LogWindow");
        }

最后,当我的View收到来自Model的新消息的通知时,我将一个新字符串添加到observable集合中,如下所示

LogWindow.Add(_vehicleWeightManager.SerialMessage);

当LogWindow.Add发生时,我的事件监听器触发并且我的断点被点击以确认代码到达那么远,如下图所示 Break Point is Hit upon Adding a new string to the collection... Notification Collection Changed Event args

在此之后我的代码调用从我的ViewModelBase继承的OnPropertyChanged函数,这对我的其他GUI元素(如标签等)运行良好,因此几乎可以肯定不是问题。

我将一块手表应用于LogWindow以跟踪该集合确实被添加到了,它如下图所示 LogWindow watch

所以在这个阶段我很茫然。如果我以某种方式调整窗口大小,我的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();
            }
        }

可以找到上述方法的进一步阅读here

1 个答案:

答案 0 :(得分:4)

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

this.Dispatcher.BeginInvoke(new Action(() =>
{
    LogWindow.Add(_vehicleWeightManager.SerialMessage);
}));