【问题标题】:Thread safe call show form with owner form带有所有者表单的线程安全调用显示表单
【发布时间】:2014-05-12 07:45:34
【问题描述】:

我有一个静态类,其中包含所有正在运行的表单和许多程序变量,如果我需要知道任何程序变量,我会调用它们。我想从单独的线程打开新表单并将其中一个静态表单设置为新表单的所有者。我的代码看起来像这样(简化):

namespace ThreadSafeTest
{
    public partial class Form1 : Form
    {
        public Form1()
        { 
            InitializeComponent(); 
            ProgramState.MainForm = this; 
        }

        private void button1_Click(object sender, EventArgs e)
        { 
            Thread t = new Thread(ThreadStartMethod); 
            t.Start(); 
        }

        private void ThreadStartMethod(object obj)
        { 
            new Form2().Show(ProgramState.MainForm); 
        }
    }

    public static class ProgramState
    { 
        public static Form1 MainForm; 
    }
}

在调用ThreadStartMethod 之后,我得到了这个异常:

System.Windows.Forms.dll 中出现“System.InvalidOperationException”类型的未处理异常
附加信息:跨线程操作无效:控件“Form1”从创建它的线程以外的线程访问。

我需要使用来自ProgramState 的静态Form1 作为参数调用.Show(Form1_Instance)。或者在ProgramState 中创建一些方法来执行此操作。有可能吗?..

我读到这个:C# calling form.show() from another thread 但我不知道如何将此解决方案应用于我的案例。如何获取Form1 的线程安全实例以调用Show for Form2(来自单独的线程)?

【问题讨论】:

  • 您几乎肯定不想创建多个 UI 线程。它会让你的生活变得更加艰难。你想拥有一个 UI线程。
  • 好的,那么以所有者表单为中心显示“带有消息的子表单”的正确方法是什么..但来自单独的线程(在此线程所有者表单中存在于静态类中)?
  • 我对@Servy 的评论赞不绝口。我相信框架本身会在你这样做时抛出异常。
  • 不要。正确的做法是使用同一个线程,而不是第二个线程。这就是我评论的重点。您只想使用 一个 UI 线程。
  • 好的,所以如果我想从单独的线程调用新表单,我可以在 Form1 中创建连接到 Method 的 EventHandler(它使用存储在静态类中的数据创建 Form2),然后从其他线程引发此事件吗?或者这仍然是线程不安全的?

标签: c# multithreading forms thread-safety


【解决方案1】:

您的表单是在构造函数中创建的,因此主线程拥有它。如果不先调用回主线程,就无法生成线程并从线程访问。

这里有更多细节:

http://msdn.microsoft.com/en-us/library/vstudio/ms171728(v=vs.100).aspx

 namespace ThreadSafeTest
 {
 public partial class Form1 : Form
 {
    public Form1()
    { 
        InitializeComponent(); 
        ProgramState.MainForm = this; 
    }

    private void button1_Click(object sender, EventArgs e)
    { 
        Thread t = new Thread(ThreadStartMethod); 
        t.Start(); 
    }

    private void ThreadStartMethod(object obj)
    { 
        Invoke(() => 
        { 
            ProgramState.MainForm.Show(); 
        });
    }
}

public static class ProgramState
{ 
    public static Form1 MainForm; 
}
}

【讨论】:

  • 好的,我知道如何调用控件(在第一个表单上更改标签中的文本或颜色),但我不知道如何应用它来调用 Show 以表单作为参数以确保安全。您能否将此详细信息应用于我的代码并编写如何使用所有者 Form1(哪个实例在静态类 ProgramState 中)调用 Form2?
  • 除了Invoke 回到主线程之外,创建一个新线程没有任何意义。
  • 我更新了它,虽然这只是在主线程中生成它。除了显示的表单之外,您是否将生成的线程用于其他任何事情?您是否要让表单在另一个线程上生成?
【解决方案2】:

你可以尝试将下面的代码放到Form2 Class的构造函数中或者任何需要显示MainForm实例的地方。

if (ProgramState.MainForm.InvokeRequired)
{   
    this.Invoke(() => { ProgramState.MainForm.Show(); });
}
else
{
    ProgramState.MainForm.Show();
}

【讨论】:

  • 除了Invoke 回到主线程之外,创建一个新线程没有任何意义。
  • 谢谢,但我想从线程显示 Form2,所有者定义为 Form1 .. 问题出在:当我从单独的线程调用 Form2 的 .Show() 时设置所有者。
猜你喜欢
  • 1970-01-01
  • 2013-07-26
  • 2020-07-17
  • 2014-11-10
  • 1970-01-01
  • 1970-01-01
  • 2014-02-17
  • 1970-01-01
  • 2013-12-18
相关资源
最近更新 更多