因此,我将一个方法移动到后台工作程序的DoWork事件中,以便在访问远程资源时不会终止UI。我完全清楚我正在这样做,因为该方法访问表单上的一些控件而不是线程友好的事情,因此需要进行一些重构。令我惊讶的是,不,它运行得很好。奇怪,但我没有质疑,虽然它仍然在我脑海中嘎嘎作响。奇怪。
然后我添加了另一个控件,一个用于时区选择的ComboBox。我将该行添加到DoWork方法以访问该值并且BAM ...交叉线程操作无效。
private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundWorker1.ReportProgress(0, new Status("Initializing...", StatusState.Initializing));
Query query = new Query();
query.Hostname = textBoxHostname.Text; // Valid...
query.Port = Int32.Parse(textBoxPort.Text); // Valid...
query.Point = Int32.Parse(textBoxPoint.Text); // Valid...
query.Start = dateTimePickerStart.Value; // Valid...
query.End = dateTimePickerEnd.Value; // Valid...
query.Sampling = Sampling.Parse(textBoxSampling.Text); // Valid...
query.Timezone = (TimeZoneInfo)comboBoxTimezone.SelectedValue; // Not Valid!
// Run query
}
那么为什么在另一个线程上创建的控件的所有其他调用都很好,但是这个调用会爆炸吗?我的猜测是.NET方面的某种缓存,以便其他人永远不会实际访问底层控件。如果没有回复,可能需要尽快深入了解一些参考资料。
我想我应该补充说,我已经通过简单地构建Query对象并将其传递给BackgroundWorker.RunWorkerAsync()
调用来修复错误。我真的在寻找解释而不是解决方案。
答案 0 :(得分:0)
我真的在寻找和解释
微软在这方面简直不一致。你知道你不应该从另一个线程访问TextBox,但无论如何。某些控件允许您从其他线程读取其值,而其他控件则不允许。无论如何,你不应该首先做到这一点。 ;)
作为将所有内容传递到RunWorkerAsync()
的替代方法,您可以执行以下操作:
Query query = new Query();
this.Invoke((MethodInvoker)delegate {
query.Hostname = textBoxHostname.Text; // Valid...
query.Port = Int32.Parse(textBoxPort.Text); // Valid...
query.Point = Int32.Parse(textBoxPoint.Text); // Valid...
query.Start = dateTimePickerStart.Value; // Valid...
query.End = dateTimePickerEnd.Value; // Valid...
query.Sampling = Sampling.Parse(textBoxSampling.Text); // Valid...
query.Timezone = (TimeZoneInfo)comboBoxTimezone.SelectedValue; // Not Valid!
});