使用任务工厂传递方法参数(组合框文本)
本文关键字:组合 文本 参数 方法 任务 工厂 | 更新日期: 2023-09-27 18:21:32
所以我在这里有点困惑。我的代码如下:
task1 = Task.Factory.StartNew(() => dataTabel_b1 = ConverteerRoutines.GetDataTableVanDatabase(Properties.Settings.Default.connectionString_b1, cbSqlTabel_b1.Text));
第二个参数(cbSqlTabel_b1)是GUI上的一个组合框。当我运行这个代码时,我得到一个无效的操作exception。我会得到这样的消息:它不允许通过进程的不同线程进入:它被授予从与创建元素的线程不同的线程访问控件cbSqlTabel_b1的权限当我这样做的时候,效果很好:
String tableName = cbSqlTabel_b1.Text;
task1 = Task.Factory.StartNew(() => dataTabel_b1 = ConverteerRoutines.GetDataTableVanDatabase(Properties.Settings.Default.connectionString_b1, tableName));
所以我用一个文本框做了同样的尝试。看起来如下:
task1 = Task.Factory.StartNew(() => dataTabel_b1 = ConverteerRoutines.GetDataTableVanDatabase(Properties.Settings.Default.connectionString_b1, textBox1.Text));
这也很好用。有人知道为什么我不能用comboBox做同样的事情吗?提前感谢!
文本框的Text
属性实现自动封送至UI线程以访问文本框。组合框的实现不适合您,因此您需要确保自己从UI线程访问它,而不是依赖Text
属性从非UI线程工作。最好的方法是,如您所示,在开始新任务之前从UI中提取值。
访问UI元素时需要使用Control.Invoke
,并且您不在UI线程上。由于您创建的Task在一个单独的线程上运行,因此需要使用Control.Invoke
。
在第二个例子中:
String tableName = cbSqlTabel_b1.Text;
task1 = Task.Factory.StartNew(() => dataTabel_b1 = ConverteerRoutines.GetDataTableVanDatabase(Properties.Settings.Default.connectionString_b1, tableName));
如果它在UI线程上运行(例如,它是从UI事件中激发的),它就会工作,因为您正在从UI线程中调用cbSqlTabel_b1
。
我不知道为什么你的第三个文本框示例有效,也许比我更有经验的人可以回答这个问题。
正如你在提到的评论中发现的和Servy一样,你可以在创建任务之前,在UI线程中获取值来修复它(这更有效,因为下面的内容意味着你一直在跳线程)。
无论如何,为了让它在你的任务中发挥作用,我建议在你的UI类/窗体中创建一个单独的方法来获取控件的文本,这会让你忘记再次尝试执行ControlInvoke
来访问某些内容。
模式如下:
private string GetCbSqlTabel_B1Text()
{
if(this.InvokeRequired)
{
return (string)this.Invoke(new Func<string>(() => GetCbSqlTabel_B1Text()));
}
else
{
return cbSqlTabel_B1.Text;
}
}
InvokeRequired
照它说的做,它会告诉你是否需要使用Control.Invoke
。当从某个随机线程调用此方法时,它将从UI线程内调用自己,此时它知道可以直接访问您需要的控件。
一旦你有了这种方法,你只需要改变你的任务来使用它:
Task.Factory.StartNew(() =>
{
ConverteerRoutines.GetDataTableVanDatabase(Properties.Settings.Default.connectionString_b1, GetCbSqlTabel_B1Text()));
});
我所知道的这种模式的唯一缺点是,你可能最终需要创建很多这样的方法,但它们确实很好地工作。它们也很好地将事物分配给控件,例如:
private void SetCbSqlTabel_B1Text(string text)
{
if(this.InvokeRequired)
{
this.Invoke(new Action(() => SetCbSqlTabel_B1Text(text)));
}
else
{
cbSqlTabel_B1.Text = text;
}
}
这一次我们不需要返回任何内容,所以我们只使用Action
而不是Func
。