【问题标题】:C# Func Delegate throws Thread ExceptionC# Func Delegate 抛出线程异常
【发布时间】:2011-08-03 02:07:29
【问题描述】:

所以,也许我误解了 Func 的用法,但是

Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();

从我的 Workerthread 调用 getCurrentValue(cb_message_type) 时创建线程错误。 获得组合框的选定值的最佳解决方案是什么?

非常感谢,
雷特

编辑
MSDN

“lambda 表达式的底层类型是通用 Func 委托之一。这使得可以将 lambda 表达式作为参数传递,而无需显式地将其分配给委托。”

【问题讨论】:

    标签: c#


    【解决方案1】:

    由于 windows 控件具有线程关联性,因此您有 2 个选项:

    1. 在执行线程代码之前查询此数据,例如将其作为状态传递给工作线程
    2. 通过 Control.Invoke 在工作器中查询它

    由于第一个是微不足道的,我将举一个使用捕获变量的第二个示例:

    object value = null;
    yourCombo.Invoke((MethodInvoker) delegate {value=yourCombo.SelectedValue;});
    string s = value.ToString();
    

    delegate {...} 内部的位发生在 UI 线程上,即使它周围的代码在工作线程上。您可以在 inside func 中混合上述内容,或者在切换线程后调用整个 func。

    【讨论】:

      【解决方案2】:

      您需要使用该委托调用Control.Invoke - 或让委托自己调用它。 使用 lambda 表达式不会改变 Windows 窗体的线程要求 - 它只是使创建委托更容易。

      您可能想创建一个方便的方法来执行此操作:

      // (Untested)
      public static Func<TControl, TResult> WrapInvocation(Func<TControl,TResult> func)
          where TControl : Control
      {
          return control => {
              return (TResult) control.Invoke(func);
          };
      }
      

      用作:

      Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();
      getCurrentValue = WrapInvocation(getCurrentValue);
      

      然后你可以从任何线程调用getCurrentValue(comboBox)

      【讨论】:

        【解决方案3】:

        问题是UI控件只能在UI线程上使用,

        你需要在另一个线程中调用Invoke方法,像这样:

        Func<ComboBox, string> getCurrentValue =
            s => s.Invoke(new Func<object>(() => s.SelectedValue)).ToString();
        

        Invoke 方法接受一个委托并在 UI 线程上执行它。

        【讨论】:

          【解决方案4】:

          一般来说,您不能从创建它们的线程之外的线程访问 UI 控件。为了克服这个问题,您要么必须检查有问题的控件和分支上的ISynchronizeInvoke.InvokeRequired,调用委托等,要么使用SynchronizationContext。第一个选项非常麻烦,而第二个选项非常优雅:

          var synchronizationContext = WindowsFormsSynchronizationContext.Current;
          string currentValue = "";    
          
          synchronizationContext.Send(
              () => currentValue = getCurrentValue(comboBox), 
              null);
          

          【讨论】:

            【解决方案5】:

            如果线程只是读取 ComboBox,如果可行,最好的选择可能是在线程上设置一个事件处理程序,该处理程序在 ComboBox 值发生变化时获取它,然后通过可以读取的属性公开该值任何线程。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-01-06
              • 2018-09-18
              • 1970-01-01
              • 1970-01-01
              • 2010-10-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多