从 UI 线程调用工作线程上的方法

本文关键字:线程 方法 调用 UI 工作 | 更新日期: 2023-09-27 17:56:28

使用

C# 在 WinForms 中工作,我有一个主窗体,可以在单独的线程上创建第二个 UI 窗体。

viewThread = new Thread( ( ) => 
{ 
  views = new Views.Views( displayRotators, screenLocationLeft, screenLocationTop, screenHeight, screenWidth );
  Application.Run( views );
} );
viewThread.SetApartmentState( ApartmentState.STA );
viewThread.Start( );

在第二个 UI 窗体上,我现在需要调用一个方法来启动一个显示循环,该循环将一直运行到我终止线程为止。 我花了大约三个小时试图找到一种方法来做到这一点,但我能找到的只是从工作线程调用主 UI 线程上的方法的示例,而不是从主 UI 线程调用工作线程上的方法。 谁能告诉我我该怎么做?

谢谢。

从 UI 线程调用工作线程上的方法

在极少数情况下,运行多个 UI 线程真正有意义。 除非您有非常令人信服的理由这样做,否则我会回到单个 UI 线程。

假设您必须有多个 UI 线程,黄金法则是控件只能从创建它们的 UI 线程更新。 如果要调用一般方法,则根本不需要封送它们。 但是,如果这些方法反过来与 UI 控件交互,则只需封送该调用,方式与调用来自不属于该控件的 UI 线程的任何其他线程完全相同

如果你可能有类似的东西

btnOnForm1OnUIThread1_Click(...)
{
    UpdateForm2OnUIThread2();
}
UpdateForm2OnUIThread2()
{
    if (control.InvokeRequired)
    {
      // Syntax of this line may be slightly off as I'm writing from memory ... 
      // I normally use an extension method
      control.Invoke(UpdateForm2OnUIThread2); 
    }
    else
    {
      control.Text = "Blah";
    }    
}

a. 如果您知道自己在做什么,那么使用多个 UI 线程并没有错。

b. 调用 UI 线程工作线程是不正确的和令人困惑的 - UI 线程 #2 与 #1 相同从开发人员的角度来看。一旦你意识到这一点 - 许多问题就会自行解决。

c. 如果要调用 view2。SomeMethod() [在 UI 线程 #2 中运行] 从 view1 [在 UI 线程 #1 中运行] - 在视图 2 上调用 BeginInvoke。

下面的代码很容易采用。 button1 - 启动第二个 UI 线程。 button2 - 从 UI 线程 2 中的窗体上的 UI 线程 1 调用方法

    Form2 form;
    private void button1_Click(object sender, EventArgs e)
    {
        Thread viewThread = new Thread(() =>
        {
            form = new Form2();
            Application.Run(form);
        });
        viewThread.SetApartmentState(ApartmentState.STA);
        viewThread.Start();
        label1.Text = Thread.CurrentThread.ManagedThreadId.ToString();
    }
    private void button2_Click(object sender, EventArgs e)
    {
        if (form != null)
        {
            form.BeginInvoke(new Action(() => 
                {form.Method("Form1 is calling...");}));
        }
    }

在形式 2 中:

    public void Method(string s)
    {
        label1.Text = string.Format("{0} '{1}'", 
                        Thread.CurrentThread.ManagedThreadId, s);
    }

您将看到线程编号不同,但字符串已正常交叉它们。