来自不同线程的WPF NotifyPropertyChange

时间:2015-07-23 10:45:51

标签: c# wpf refresh

我的VM实现了INotifyPropertyChanged接口。我创建了另一个线程T来填充我绑定到Xaml的列表。填充列表后,我在线程T中调用PropertyChanged,我的UI得到了正确的刷新。

我的问题是在什么情况下我需要使用Dispatcher?为什么我不需要在我的情况下使用Dispatcher?我想当其他线程中的代码想要通过将更改排入UI刷新队列来通知UI线程的更改时使用Dispatcher,例如从另一个线程向ObservableCollection添加项,然后UI线程将从队列中提取数据。

private List<string> _ListData;

public List<String> ListData
{
    get
    {
        if (_ListData == null)
              Initialise( () => ListData = ReturnSlow());

        return _ListData;
    }
    set { _ListData = value; }
}

private List<string> ReturnSlow()
{
    List<string> Test = new List<string>();

    Test.Add("1");
    Test.Add("2");

    Thread.Sleep(2000);
    return Test;

 }

    public void Initialise(Action initialiser)
    {
        Task t = new Task(() =>
        {
            initialiser();
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("ListData"));
        });

        t.Start();
    }

1 个答案:

答案 0 :(得分:2)

您的应用有一个主UI线程(通常是ManagedThreadId==1)。如果要从某个其他线程获取的事件更新UI,则必须使用调度程序。这里有用的测试是Dispatcher.CheckAccess()方法,如果代码在UI线程上,则返回true,如果在其他线程上则返回false。典型的通话类似于:

using System.Windows.Threading; // For Dispatcher.

if (Application.Current.Dispatcher.CheckAccess()) {
    network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}
else {
    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>{
        network_links.Add(new NetworkLinkVM(link, start_node, end_node));
    }));
}

如果您在主窗口中,可以使用:

Dispatcher.BeginInvoke(...

如果你在另一个上下文中,例如视图模型,那么使用:

Application.Current.Dispatcher.BeginInvoke(  

调用vs BeginInvoke
如果希望当前线程等到UI线程处理了调度代码,请使用Invoke;如果希望当前线程继续而不等待UI线程上的操作完成,请使用BeginInvoke

MessageBox,Dispatchers和Invoke / BeginInvoke:
Dispatcher.Invoke将阻止您的线程,直到MessageBox被解雇 Dispatcher.BeginInvoke将允许您的线程代码继续执行,而UI线程将阻止MessageBox调用,直到它被解除。

CurrentDispatcher vs Current.Dispatcher!
Dispatcher.CurrentDispatcher的商品,因为我对此的理解是,它将返回当前线程而不是UI线程的Dispatcher。通常,您对UI线程上的调度程序感兴趣 - Application.Current.Dispatcher始终返回此内容。

附加说明:
如果您发现必须经常检查调度程序CheckAccess,那么有用的辅助方法是:

public void DispatchIfNecessary(Action action) {
    if (!Dispatcher.CheckAccess())
        Dispatcher.Invoke(action);
    else
        action.Invoke();
}

可以称为:

DispatchIfNecessary(() => {
    network_links.Add(new NetworkLinkVM(link, start_node, end_node));
});