我们应该在UI线程中调用OnPropertyChanged吗?

时间:2018-09-13 07:31:27

标签: wpf mvvm thread-safety

在这个简单的示例中,我们可以在任何线程中读取Property StrTestExample。

我在同一篇文章中看到,它说OnPropertyChanged事件自动封送给UI线程。因此,我们可以在任何线程中设置StrTestExample,并且UI可以更新。另外还有一篇文章说,我们应该负责在UI线程中调用OnPropertyChaned。

这是哪里?

是否有来自msdn或其他地方的任何文件证明这一点?

public class ViewModelBase : INotifyPropertyChanged
    {

        private volatile string _strTestExample;

        public string StrTestExample
        {
            get { return _strTestExample; }
            set
            {
                if (_strTestExample != value)
                {
                    _strTestExample = value;
                    OnPropertyChanged(nameof(StrTestExample));
                }
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var propertyChanged = PropertyChanged;
            propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }


    }

1 个答案:

答案 0 :(得分:2)

  

我在同一篇文章中看到,它说OnPropertyChanged事件自动封送给UI线程。因此,我们可以在任何线程中设置StrTestExample,并且UI可以更新。另外还有其他文章说,我们应该负责在UI线程中调用OnPropertyChaned。这是哪里?

前者。您可以调用OnPropertyChanged并从任何线程引发属性的PropertyChanged事件。该框架将为您处理编组。

您可以轻松地自己确认,例如启动Task并在后台线程执行的操作中设置属性,例如:

public class ViewModelBase : INotifyPropertyChanged
{
    public ViewModelBase()
    {
        Task.Run(()=> 
        {
            for(int i = 0; i < 5; ++i)
            {
                StrTestExample = i.ToString();
                Thread.Sleep(2000);
            }
        });
    }
    private string _strTestExample;
    public string StrTestExample
    {
        get { return _strTestExample; }
        set
        {
            if (_strTestExample != value)
            {
                _strTestExample = value;
                OnPropertyChanged(nameof(StrTestExample));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

请注意,从后台更新源集合是另一回事。