我刚刚注意到,当我在后台工作线程中更改我的ViewModel
(MVVM)中的绑定属性时,我没有收到任何异常,并且视图正确更新。这是否意味着我可以放心地依赖于wpf数据绑定将ViewModel
中的所有更改传递到UI线程?我想我曾经在某个地方读到过,应该确保在ViewModel
中(on the UI thread)触发INotifyPropertyChanged.PropertyChanged
。这在3.5版中是否已更改或其他什么情况?
我刚刚注意到,当我在后台工作线程中更改我的ViewModel
(MVVM)中的绑定属性时,我没有收到任何异常,并且视图正确更新。这是否意味着我可以放心地依赖于wpf数据绑定将ViewModel
中的所有更改传递到UI线程?我想我曾经在某个地方读到过,应该确保在ViewModel
中(on the UI thread)触发INotifyPropertyChanged.PropertyChanged
。这在3.5版中是否已更改或其他什么情况?
对于标量是可以的,对于集合则不行。对于集合,你需要使用专门的集合来进行组合处理,或者手动通过 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>
我认为,在2.0和之前的.NET版本中,因线程亲和性而执行上述示例会导致InvalidOperationException异常(由bitbonk张贴的链接是2006年的)。
现在,使用3.5,WPF似乎会将后台线程属性更改代理到调度程序。
所以,简言之,这取决于您正在针对的.NET版本。希望这能消除任何困惑。
我的一个Lab49同事在2007年在此处进行了博客记录:
ObservableCollection
) - Merlyn Morgan-Graham