【问题标题】:Thread Control.Invoke线程控制.调用
【发布时间】:2018-12-03 20:36:44
【问题描述】:

我有一个函数

public void ShowAllFly()
{  
        cbFly.Items.Clear();
        cbFly.Items.Add("Uçuş Seçiniz...");

        dsFlyTableAdapters.tblFlyTableAdapter _t=new KTHY.dsFlyTableAdapters.tblFlyTableAdapter();
        dsFly _mds = new dsFly();
        _mds.EnforceConstraints = false;
        dsFly.tblFlyDataTable _m = _mds.tblFly;
        _t.Fill(_m);
        foreach (DataRow _row in _m.Rows)
        {
            cbFly.Items.Add(_row["FlyID"].ToString()+"-"+_row["FlyName"].ToString() + "-" + _row["FlyDirection"].ToString() + "-" + _row["FlyDateTime"].ToString());
        }
        _Thread.Abort();
        timer1.Enabled = false;
        WaitPanel.Visible = false;
}

在Form_Load函数中这样;

{
    _Thread = new System.Threading.Thread(new System.Threading.ThreadStart(ShowAllFly));
    _Thread.Start();
    _Thread.Priority = System.Threading.ThreadPriority.Normal;
}

但是当我运行它时;

在 ShowAllFly 函数中

cbFly.Items.Clear(); ----  HERE Gives ERROR  LIKE  Control.Invoke must be used to interact with controls created on a separate thread.

有什么问题?

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

    在 Windows 窗体中线程有两条黄金法则:

    • 除了创建控件“句柄”的线程(通常只有一个 UI 线程)之外,不要触摸任何线程中的任何控件属性或方法(明确列出为正常的除外)
    • 不要长时间阻塞 UI 线程,否则会导致应用程序无响应

    为了从不同的线程与 UI 交互,您需要“编组”对 UI 线程的调用,使用委托并调用 Control.Invoke/BeginInvoke。您可以测试您是否需要使用InvokeRequired 属性调用Invoke,但这些天我个人倾向于这样做 - 调用时不会有太大的惩罚需要。

    C# 3 中的 Lambda 表达式(或 C# 2 中的匿名方法)也使这更令人愉快。

    例如,您可以使用:

    cbFly.Invoke((MethodInvoker)(() => cbFly.Items.Clear()));
    

    所有的括号都有点碍事,所以如果你使用 C# 3,你可能想添加这样的扩展方法:

    public static void Invoke(this Control control, MethodInvoker action)
    {
        control.Invoke(action);
    }
    

    那么你可以这样做:

    cbFly.Invoke(() => cbFly.Items.Clear());
    

    这要简单得多。通常,您可以通过捕获您需要在委托中访问的任何变量来避免使用MethodInvoker

    请参阅my threading tutorialJoe Albahari's 了解更多详情。

    作为次要问题,我看到您正在使用Thread.Abort - 实际上是在您自己的线程上,尽管它之后还有其他调用。为什么?中止除您自己之外的任何线程其他是“仅限紧急情况”类型调用(通常应该在应用程序被卸载之后),我看不出有任何理由中止当前线程之后还有工作要做……

    【讨论】:

      【解决方案2】:

      需要像这样调用另一个 (ui) 线程中控件的交互:

      public delegate void ProcessResultDelegate(string result);
      void ProcessResult(string result)
      {
          if (textBox1.InvokeRequired)
          {
              var d = new ProcessResultDelegate(ProcessResult);
              d.Invoke(result);
          }
          else
          {
              textBox1.Text = result;
          }
      }
      

      【讨论】:

      • 很好的解决方案;我建议使用框架中的Action<T>,而不是自己滚动(和维护)。
      • 是的.. 这几乎是执行此操作的标准方法。需要这样做的原因是 textBox1.Text 只能在创建文本框的线程上更改 - 调用是用于返回该线程的进程。
      • @Fredrik:你说得对,但这个例子出现的频率更高,很大程度上是因为它存在的时间更长。任何一种方法都可以。
      【解决方案3】:

      我一直发现 this article 对这个特定问题很有帮助。

      在您的示例中,您尝试从未创建控件的线程修改各种控件。要根据您的示例解决此问题,请改为执行此操作(假设 ShowAllFly() 方法是您表单上的方法):

      public void ShowAllFly()
      {
          Invoke((MethodsInvoker) delegate {
              cbFly.Items.Clear();
              cbFly.Items.Add("Uçuş Seçiniz...");
              dsFlyTableAdapters.tblFlyTableAdapter _t =
                  new KTHY.dsFlyTableAdapters.tblFlyTableAdapter();
              dsFly _mds = new dsFly();
              _mds.EnforceConstraints = false;
              dsFly.tblFlyDataTable _m = _mds.tblFly;
              _t.Fill(_m);
              foreach (DataRow _row in _m.Rows)
              {
                  cbFly.Items.Add(_row["FlyID"].ToString() + "-" +
                                  _row["FlyName"].ToString() + "-" +
                                  _row["FlyDirection"].ToString() + "-" +
                                  _row["FlyDateTime"].ToString());
              }
              //_Thread.Abort(); // WHY ARE YOU TRYING TO DO THIS?
              timer1.Enabled = false;
              WaitPanel.Visible = false;
          } );
      }
      

      为了强调@Jon Skeet 的观点,我已经注释掉了中止线程的调用。线程将自行结束。没有理由以这种方式中止它。

      【讨论】:

      • 因为他是最好的,所以我给了他一个赞,在我之前没有人有过(提示,提示)。
      【解决方案4】:

      它必须被调用......但是调用必须等待主线程我的意思是你不会这样得到错误但是如果你想同时进行多个进程,这不是完全并行工作只需创建一个以上线程

      Thread thread = new Thread(new delegate_method(method));//you must create delegate before
      thread.start ();
      Thread thread2 = new Thread(new delegate_method(method2));//you must create delegate before
      thread.start ();
      

      同时处理两个进程

          void method ()
      {
      //do something here -- working background Remember can not control any UI control from here
      finish_thread()
      }
      
      void method2 ()
      {
      //do something here -- working background Remember can not control any UI control from here
      finish_thread()
      }
      
      void finish_thread()
      {
      if(invoke.Required)
      {
      //Here you have to call delegate method here with UI
      BeginInvoke(new delegate_method(finish_thread));
      }
      else
      {
      //Now you can control UI thread from here and also you finished background work
      //Do something working with UI thread
      textBox.Text = "";
      }
      }
      

      【讨论】:

        【解决方案5】:

        这是线程中控件工作的最佳方式。

        首先你必须使用单线程单元线程。

        ...
        Thread th = new Thread(yourThreadStart);
                    th.SetApartmentState(ApartmentState.STA);
        th.Start();
        ...
        

        接下来在你的代码之间复制这个方法!

        public static void SetControlThreadSafe(Control control, Action<object[]> action, object[] args)
        {
              if (control.InvokeRequired)
                    try { control.Invoke(new Action<Control, Action<object[]>, object[]>(SetControlThreadSafe), control, action, args); } catch { }
              else action(args);
        }
        

        最后,您的控件更改必须按如下方式完成:

        ...
        
            SetControlThreadSafe(textbox1, (arg) =>
                  {
                        textbox1.Text = "I`m Working in a Thread";
                  }, null);
        ...
        

        享受...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-14
          • 2012-07-10
          • 1970-01-01
          • 1970-01-01
          • 2018-11-02
          • 1970-01-01
          相关资源
          最近更新 更多