【发布时间】:2011-08-16 14:08:26
【问题描述】:
为了解释这个问题,我将所需的一切都放入一个小示例应用程序中,希望能解释这个问题。我真的试图把所有的东西都推得尽可能少,但在我的实际应用中,这些不同的演员彼此不认识,也不应该认识。因此,像“将变量放在上面几行并对其调用 Invoke”这样简单的答案是行不通的。
让我们从代码开始,然后再做一些解释。一开始有一个实现 INotifyPropertyChanged 的简单类:
public class MyData : INotifyPropertyChanged
{
private string _MyText;
public MyData()
{
_MyText = "Initial";
}
public string MyText
{
get { return _MyText; }
set
{
_MyText = value;
PropertyChanged(this, new PropertyChangedEventArgs("MyText"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
所以没什么特别的。这里的示例代码可以简单地放入任何空的控制台应用程序项目中:
static void Main(string[] args)
{
// Initialize the data and bindingSource
var myData = new MyData();
var bindingSource = new BindingSource();
bindingSource.DataSource = myData;
// Initialize the form and the controls of it ...
var form = new Form();
// ... the TextBox including data bind to it
var textBox = new TextBox();
textBox.DataBindings.Add("Text", bindingSource, "MyText");
textBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
textBox.Dock = DockStyle.Top;
form.Controls.Add(textBox);
// ... the button and what happens on a click
var button = new Button();
button.Text = "Click me";
button.Dock = DockStyle.Top;
form.Controls.Add(button);
button.Click += (_, __) =>
{
// Create another thread that does something with the data object
var worker = new BackgroundWorker();
worker.RunWorkerCompleted += (___, ____) => button.Enabled = true;
worker.DoWork += (___, _____) =>
{
for (int i = 0; i < 10; i++)
{
// This leads to a cross-thread exception
// but all i'm doing is simply act on a property in
// my data and i can't see here that any gui is involved.
myData.MyText = "Try " + i;
}
};
button.Enabled = false;
worker.RunWorkerAsync();
};
form.ShowDialog();
}
如果您将运行此代码,您将通过尝试更改 MyText 属性来获得跨线程异常。这会导致MyData 对象调用PropertyChanged,这将被BindindSource 捕获。然后,根据Binding,这将尝试更新TextBox 的Text 属性。这显然导致了异常。
我最大的问题来自MyData 对象不应该知道关于 gui 的任何信息(因为它是一个简单 数据对象)。此外,工作线程对 gui 也一无所知。它只是作用于一堆数据对象并对其进行操作。
恕我直言,我认为BindingSource 应该检查接收对象在哪个线程上,并执行适当的Invoke() 以获得它们的值。不幸的是,这不是内置的(或者我错了吗?),所以我的问题是:
如果数据对象和工作线程知道任何关于正在监听其事件以将数据推送到 gui 的绑定源的信息,如何解决此跨线程异常。
【问题讨论】:
标签: c# .net winforms multithreading