来自不同线程的 WPF NotifyPropertyChange

WPF NotifyPropertyChange from different thread

我的 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();
    }

您的应用有一个 UI 主线程(通常 ManagedThreadId==1)。如果你想从一个在其他线程上拉取的事件更新 UI,你必须使用调度程序。这里一个有用的测试是 Dispatcher.CheckAccess() 方法,如果代码在 UI 线程上,return 为真,如果在其他线程上,则为假。典型的调用类似于:

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));
    }));
}

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

Dispatcher.BeginInvoke(...

如果您在其他环境中,例如视图模型,则使用:

Application.Current.Dispatcher.BeginInvoke(  

调用与 BeginInvoke
如果您希望当前线程等到 UI 线程处理完调度代码,请使用 Invoke,或者如果您希望当前线程继续而不等待操作在 [=55] 上完成,请使用 BeginInvoke =]线程。

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

CurrentDispatcher 与 Current.Dispatcher!
请注意 Dispatcher.CurrentDispatcher,因为我对此的理解是 return 当前线程的 Dispatcher 而不是 UI 线程。一般来说,您是否对 UI 线程上的调度程序感兴趣 - Application.Current.Dispatcher 总是 returns this.

补充说明:
如果您发现您必须经常检查调度程序 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));
});