确保在MVVM WPF应用程序中的UI线程上调用OnPropertyChanged()

在我使用MVVM模式编写的WPF应用程序中,我有一个后台进程来完成这件事,但需要从UI中获取状态更新。

我使用MVVM模式,所以我的ViewModel几乎不知道向用户展示模型的视图(UI)。

假设我在ViewModel中有以下方法:

public void backgroundWorker_ReportProgress(object sender, ReportProgressArgs e)
{
    this.Messages.Add(e.Message);
    OnPropertyChanged("Messages");
}

在我看来,我有一个ListBox绑定到ViewModel的Messages属性( List<string> )。 OnPropertyChanged通过调用PropertyChangedEventHandler来实现INotifyPropertyChanged接口的角色。

我需要确保在UI线程上调用OnPropertyChanged - 我该如何做到这一点? 我试过以下内容:

public Dispatcher Dispatcher { get; set; }
public MyViewModel()
{ 
    this.Dispatcher = Dispatcher.CurrentDispatcher;
}

然后将以下内容添加到OnPropertyChanged方法中:

if (this.Dispatcher != Dispatcher.CurrentDispatcher)
{
    this.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(delegate
    {
        OnPropertyChanged(propertyName);
    }));
    return;
}

但这不起作用。 有任何想法吗?


WPF自动将属性更改编组到UI线程。 但是,它不编组收集更改,所以我怀疑您添加一条消息导致失败。

您可以自己手动编辑添加(请参阅下面的示例),或者使用类似于我以前写博客的技术。

手动编组:

public void backgroundWorker_ReportProgress(object sender, ReportProgressArgs e)
{
    Dispatcher.Invoke(new Action<string>(AddMessage), e.Message);
    OnPropertyChanged("Messages");
}

private void AddMessage(string message)
{
    Dispatcher.VerifyAccess();
    Messages.Add(message);
}

我真的很喜欢杰里米的回答:在Silverlight中调度

概要:

  • 在ViewModel中放置分派器似乎不够高雅

  • 创建一个Action <Action>属性,将其设置为仅在VM构造函数中运行该操作

  • 从V中使用VM时,请设置Action属性以调用Dispatcher

  • 本周我也有类似的情况(这里也是MVVM)。 我有一个单独的类来完成它的事情,报告事件处理程序的状态。 事件处理程序正在按预期方式调用,并且我可以看到使用Debug.WriteLine正确返回的结果。

    但是对于WPF,不管我做了什么,UI都不会更新,直到过程完成。 该过程完成后,UI将按预期进行更新。 就好像它正在获取PropertyChanged一样,但是在一次完成UI更新之前等待线程完成。

    (很让我沮丧的是,Windows.Forms中的代码与DoEvents和.Refresh()的工作方式类似。)

    到目前为止,我通过在自己的线程上启动进程来解决这个问题:

    //hook up event handler
    myProcess.MyEvent += new EventHandler<MyEventArgs>(MyEventHandler); 
    
    //start it on a thread ...
    ThreadStart threadStart = new ThreadStart(myProcess.Start);
    
    Thread thread = new Thread(threadStart);
    
    thread.Start();
    

    然后在事件处理程序中:

    private void MyEventHandler(object sender, MyEventArgs e) { 
    ....
    Application.Current.Dispatcher.Invoke(
                    DispatcherPriority.Send,
                    (DispatcherOperationCallback)(arg =>
                    { 
             //do UI updating here ...
            }), null);
    

    我不推荐这段代码,因为我仍然试图理解WPF线程模型,Dispatcher是如何工作的,以及为什么在我的情况下,即使事件处理程序按预期方式调用,过程完成之前UI也不会更新通过设计?)。 但到目前为止,这对我来说已经奏效。

    我发现这两个链接很有用:

    http://www.nbdtech.com/blog/archive/2007/08/01/Passing-Wpf-Objects-Between-Threads-With-Source-Code.aspx

    http://srtsolutions.com/blogs/mikewoelmer/archive/2009/04/17/dealing-with-unhandled-exceptions-in-wpf.aspx

    链接地址: http://www.djcxy.com/p/56207.html

    上一篇: Making sure OnPropertyChanged() is called on UI thread in MVVM WPF app

    下一篇: WPF: Why does CommandBindings only use RoutedCommand which breaks MVVM?