gpt4 book ai didi

c# - BindingSource 和跨线程异常

转载 作者:太空狗 更新时间:2023-10-29 20:14:35 25 4
gpt4 key购买 nike

为了解释这个问题,我把所有需要的东西都放到了一个小的示例应用程序中,希望能解释这个问题。我真的试图尽可能减少所有内容,但在我的实际应用程序中,这些不同的 Actor 彼此不认识,也不应该。因此,像“在上面几行中获取变量并对其调用 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,尝试更新 TextBoxText 属性。这显然会导致异常。

我最大的问题是 MyData 对象不应该知道有关 gui 的任何信息(因为它是一个简单 数据对象)。此外,工作线程对图形用户界面一无所知。它只是作用于一堆数据对象并对其进行操作。

恕我直言,我认为 BindingSource 应该检查接收对象在哪个线程上,并执行适当的 Invoke() 以获得它们的值。不幸的是,这不是内置的(或者我错了吗?),所以我的问题是:

如果数据对象或工作线程都知道正在监听其事件以将数据推送到 gui 中的绑定(bind)源,如何解决此跨线程异常。

最佳答案

下面是上面例子中解决这个问题的部分:

button.Click += (_, __) =>
{
// Create another thread that does something with the data object
var worker = new BackgroundWorker();

worker.DoWork += (___, _____) =>
{
for (int i = 0; i < 10; i++)
{
// This doesn't lead to any cross-thread exception
// anymore, cause the binding source was told to
// be quiet. When we're finished and back in the
// gui thread tell her to fire again its events.
myData.MyText = "Try " + i;
}
};

worker.RunWorkerCompleted += (___, ____) =>
{
// Back in gui thread let the binding source
// update the gui elements.
bindingSource.ResumeBinding();
button.Enabled = true;
};

// Stop the binding source from propagating
// any events to the gui thread.
bindingSource.SuspendBinding();
button.Enabled = false;
worker.RunWorkerAsync();
};

所以这不会再导致任何跨线程异常。此解决方案的缺点是您不会在文本框中显示任何中间结果,但总比没有好。

关于c# - BindingSource 和跨线程异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7079474/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com