使用任务工厂传递方法参数(组合框文本)

本文关键字:组合 文本 参数 方法 任务 工厂 | 更新日期: 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