Wpf TextBox.Text可以通过绑定在另一个线程中更新

时间:2016-11-10 17:55:30

标签: c# wpf multithreading binding async-await

通常,如果我们有FrameworkElement,我们就无法从其他Thread更新其属性。例如,如果TextBox名为MyTextBox,我们就无法执行此操作:

public async void Button_Click(object sender, RoutedEventArgs e)
{
    await Task.Run(() => { MyTextBox.Background = new SolidBrushColor(Colors.Yellow); }
}

因为它会抛出Exception

  

调用线程无法访问此对象,因为另一个线程拥有它。

我们都无法修改BackgroundBinding(在另一个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}}属性。

这是一个错误,还是由设计制造出来的?为什么?

1 个答案:

答案 0 :(得分:3)

  

我们都不能通过绑定修改背景(在另一个中)   螺纹)

事实并非如此。 WPF Binding自动将值封送回调度程序线程(除非他们使用ObservableCollection<T>,但这是另一个主题。)

您在尝试通过InvalidOperationException设置Background属性时获得Binding的原因是您创建了SolidColorBrush后台线程并尝试在调度程序线程上使用它。在返回之前调用该画笔上的Freeze()(在Task中),并且您不再获得任何例外,因为&#34;冻结&#34;任何线程都可以使用Freezable

此外,这就是为什么多线程Binding用于示例中所有其他属性的原因。