从工作线程更新ViewModel会引发跨线程问题

Tru*_*ver 1 c# task worker-thread winforms c#-4.0

最近,我一直在进行类型绑定的测试,该绑定实现INotifyPropertyChanged了工作线程抛出跨线程问题并更新了属性。

这是示例代码:

public class MyViewModel : INotifyPropertyChanged
    {
        private string _name;

        public string Name
        {
            get { return _name; }
            set
            {
                if (_name != value)
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {

            PropertyChangedEventHandler hanlder = PropertyChanged;
           if(hanlder != null)
                hanlder(this, new PropertyChangedEventArgs(propertyName));

        }
    }
Run Code Online (Sandbox Code Playgroud)

上面的viewmodel已与Windows窗体中的标签文本绑定,并从工作线程更新标签值。

从辅助线程更新label1文本会导致跨线程问题:

public partial class MainForm : Form
{
    private MyViewModel _myViewModel = new MyViewModel();
    public MainForm()
    {
        InitializeComponent();
        Btn1.Click += Btn1_Click;
        label1.DataBindings.Add("Text", _myViewModel, "Name");

    }

    private void Btn1_Click(object sender, EventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            _myViewModel.Name = "Updating from worker thread!"; It causes cross thread issue
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我可以相信这是由于从工作线程更新UI所致。是否有任何变通办法可以使其在不更改按钮单击方法的情况下保持线程安全,即可能在viewmodel中使线程安全。

Jcl*_*Jcl 5

抓取UI SynchronizationContextSynchronizationContext.Current例如,在应用启动时使用UI线程),并将其存储在某个静态变量中(我称之为uiSynchronizationContext)。

然后对您OnPropertyChanged执行以下操作:

protected virtual void OnPropertyChanged(string propertyName)
{
   uiSynchronizationContext.Post(
        o => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName))
       ,null
     );
}
Run Code Online (Sandbox Code Playgroud)

或者,也可以使用Send而不是Post希望该操作同步(与启动send / post操作的线程同步,在UI线程上始终“同步”)

我特别不喜欢在多线程时进行直接数据绑定(我更喜欢使用带有更改的图形对象在UI线程上使用计时器进行轮询),但这应该可以解决问题。

我承认还没有测试