WPF数据绑定是否会更改UI线程?

时间:2009-08-24 09:48:14

标签: wpf multithreading data-binding mvvm

我刚注意到,当我从后台工作线程更改ViewModel(MVVM)中的绑定属性时,我没有得到任何异常,并且视图已正确更新。这是否意味着我可以放心地依赖于wpf数据绑定将ViewModel中的所有更改编组到UI线程中?我想我已经读过某个地方应该确保(在ViewModel中)在{i}}线程上触发INotifyPropertyChanged.PropertyChanged。这有什么改变在3.5或什么?

2 个答案:

答案 0 :(得分:14)

对于标量是的,对于集合没有。对于集合,您需要一个专门为您编组的集合,或者通过Dispatcher自行编组到UI线程。

您可能已经读过INotifyCollectionChanged.CollectionChanged必须触发UI线程,因为INotifyPropertyChanged.PropertyChanged根本不是这样。下面是一个非常简单的示例,证明了WPF为您调整属性更改。

Window1.xaml.cs

using System.ComponentModel;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
    public partial class Window1 : Window
    {
        private CustomerViewModel _customerViewModel;

        public Window1()
        {
            InitializeComponent();
            _customerViewModel = new CustomerViewModel();
            DataContext = _customerViewModel;

            var thread = new Thread((ThreadStart)delegate
            {
                while (true)
                {
                    Thread.Sleep(2000);
                    //look ma - no marshalling!
                    _customerViewModel.Name += "Appended";
                    _customerViewModel.Address.Line1 += "Appended";
                }
            });

            thread.Start();
        }
    }

    public abstract class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class CustomerViewModel : ViewModel
    {
        private string _name;
        private AddressViewModel _address = new AddressViewModel();

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

        public AddressViewModel Address
        {
            get { return _address; }
        }
    }

    public class AddressViewModel : ViewModel
    {
        private string _line1;

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

Window1.xaml

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TextBox Text="{Binding Name}"/>
        <TextBox Text="{Binding Address.Line1}"/>
    </StackPanel>
</Window>

答案 1 :(得分:1)

我相信,使用2.0和以前的.NET版本,在执行上述示例时,由于线程关联性,您将收到InvalidOperationException(bitbonk发布的链接日期为2006年)。

现在,使用3.5,WPF似乎确实将后台线程属性更改封送到调度程序中。

因此,简而言之,取决于您所针对的.NET版本。希望能够解决任何混乱。

我的一位Lab49同事在2007年在这里写了博客:

http://blog.lab49.com/archives/1166