2016-11-10 75 views
0

通常,如果我们有一个FrameworkElement,我们无法从另一个Thread更新其属性。因为它抛出一个ExceptionWpf TextBox.Text通过绑定在另一个线程中更新

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

:例如,给定一个名为TextBoxMyTextBox,我们不能这样做,因为不同的线程拥有它

调用线程不能访问该对象。

无论我们可以通过修改Background通过Binding(在另一个Thread

<TextBox Name="MyTextBox" Background="{Binding BoundBackground}"/> 

在视图模型设置它:

public async void SomeOperation() 
{ 
    await Task.Run(() => { BoundBackground = new SolidBrushColor(Colors.Yellow); } 
} 

因为同样的Exception被抛出。

现在,这里是“奇怪的”行为。如果你想直接从另一个Thread更新Text属性,像这样:

public async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    await Task.Run(() => { MyTextBox.Text = "new text"; } 
} 

它抛出同样的预期Exception,但如果你绑定Text属性是这样的:

<TextBox Text="{Binding BoundText}"/> 

,并更新它从另一个Thread由ViewModel:

public async void SomeOperation() 
{ 
    await Task.Run(() => { BoundText = "new text"; } 
} 

它神奇地工作KS。

我注意到这种行为也为ProgressBarValue属性。

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

+0

我只能想象它的财产变更通知为你工作。 BoundText的类型是什么? – sellotape

+0

@sellotape它显然是一个字符串,否则我怎样才能分配“新文本”值并将其绑定到Text属性? –

回答

3

无论我们可以通过绑定(在另一个线程 )

这是不正确的修改背景。 WPF Binding会自动将该值封送回调度员线程(除非他们使用ObservableCollection<T>,但这是另一个话题)。

为什么你会得到一个InvalidOperationException,而试图通过Binding设置Background属性的原因,是您创建一个后台线程SolidColorBrush并尝试使用它的调度线程的事实。在返回之前,请在该画笔上拨打Freeze()(在您的Task中),并且您不会再有任何异常,因为任何线程都可以使用“冻结”Freezable

此外,这就是为什么多线程Binding s为您的示例工作的所有其他属性。