通常,如果我们有FrameworkElement
,我们就无法从其他Thread
更新其属性。例如,如果TextBox
名为MyTextBox
,我们就无法执行此操作:
public async void Button_Click(object sender, RoutedEventArgs e)
{
await Task.Run(() => { MyTextBox.Background = new SolidBrushColor(Colors.Yellow); }
}
因为它会抛出Exception
:
调用线程无法访问此对象,因为另一个线程拥有它。
我们都无法修改Background
到Binding
(在另一个Thread
中)
<TextBox Name="MyTextBox" Background="{Binding BoundBackground}"/>
在ViewModel中设置它:
public async void SomeOperation()
{
await Task.Run(() => { BoundBackground = new SolidBrushColor(Colors.Yellow); }
}
因为抛出相同的Exception
。
现在,这是“奇怪”的行为。如果您尝试直接从另一个Text
更新Thread
属性,请执行以下操作:
public async void Button_Click(object sender, RoutedEventArgs e)
{
await Task.Run(() => { MyTextBox.Text = "new text"; }
}
它会抛出相同的预期Exception
,但如果你像这样绑定Text
属性:
<TextBox Text="{Binding BoundText}"/>
您可以通过ViewModel从另一个Thread
更新它:
public async void SomeOperation()
{
await Task.Run(() => { BoundText = "new text"; }
}
它神奇地起作用。
我也注意到此行为也适用于Value
的{{1}}属性。
这是一个错误,还是由设计制造出来的?为什么?
答案 0 :(得分:3)
我们都不能通过绑定修改背景(在另一个中) 螺纹)
事实并非如此。 WPF Binding
自动将值封送回调度程序线程(除非他们使用ObservableCollection<T>
,但这是另一个主题。)
您在尝试通过InvalidOperationException
设置Background
属性时获得Binding
的原因是您创建了SolidColorBrush
后台线程并尝试在调度程序线程上使用它。在返回之前调用该画笔上的Freeze()
(在Task
中),并且您不再获得任何例外,因为&#34;冻结&#34;任何线程都可以使用Freezable
。
此外,这就是为什么多线程Binding
用于示例中所有其他属性的原因。