C#中带单声道的交叉线程形式

C#中带单声道的交叉线程形式,c#,mono,multithreading,C#,Mono,Multithreading,我正在创建一个使用.Net和Mono的应用程序,它使用跨线程表单,因为我的子窗口响应不好 我用两个表单创建了一个测试程序:第一个表单(form1)有一个按钮(button1),第二个表单(form2)为空,代码片段如下 void openForm() { Form2 form2 = new Form2(); form2.ShowDialog(); } private void button1_Click(object sender, EventArgs e) { Thre

我正在创建一个使用.Net和Mono的应用程序,它使用跨线程表单,因为我的子窗口响应不好

我用两个表单创建了一个测试程序:第一个表单(form1)有一个按钮(button1),第二个表单(form2)为空,代码片段如下

void openForm()
{
    Form2 form2 = new Form2();
    form2.ShowDialog();
}
private void button1_Click(object sender, EventArgs e)
{
    Thread x = new Thread(openForm);
    x.IsBackground = true;
    x.Start();
}
这在.Net中运行良好,但在Mono中,当您单击第一个窗口(标准的.ShowDialog()行为)而不是.Net使用的.Show()行为时,第一个窗口将不会获得焦点

当我在.Net和Mono上使用.Show()时,窗口会闪烁然后消失。如果我将“MessageBox.Show()”放在“form2.Show()”之后,它将保持打开状态,直到您单击“确定”

我是在代码中遗漏了什么,还是Mono不支持?(我使用的是Mono 2.8.1)

提前谢谢你,阿德里安


编辑:我意识到我忘记了'x.IsBackground=true;'在上面的代码中,子窗口将与主窗口一起关闭。

如果使用Winforms控件,则应始终在主UI线程中“触摸”对象

至少,在新线程中调用new Form.ShowDialog()没有意义

编辑: 如果希望轻松使用Invoke/BeginInvoke,可以使用扩展方法:

public static class ThreadingExtensions {
    public static void SyncWithUI(this Control ctl, Action action) {
        ctl.Invoke(action);
    }
}
// usage:
void DoSomething( Form2 frm ) {
    frm.SyncWithUI(()=>frm.Text = "Loading records ...");

    // some time-consuming method
    var records = GetDatabaseRecords();
    frm.SyncWithUI(()=> {
        foreach(var record in records) {
            frm.AddRecord(record);
        }
    });

    frm.SyncWithUI(()=>frm.Text = "Loading files ...");

    // some other time-consuming method
    var files = GetSomeFiles();
    frm.SyncWithUI(()=>{
        foreach(var file in files) {
            frm.AddFile(file);
        }
    });

    frm.SyncWithUI(()=>frm.Text = "Loading is complete.");
}

在Windows应用程序中,让多个线程与共享同一消息的一个或多个窗口进行对话几乎从来都不是正确的做法

而且很少需要有一个以上的消息泵

正确的方法是使用“Invoke”方法手动将工作线程中的所有内容封送回窗口,或者使用BackgroundWorker之类的方法,为您隐藏详细信息

总之:

  • 不要为了耗时的计算或I/O而阻塞UI线程
  • 不要从多个线程与UI对话

正如我在第一篇文章中提到的,我使用独立线程的唯一原因是为了性能,我曾考虑过使用独立线程而不是表单来制作其他所有内容,但这需要大量重写代码,我可能最终会这样做,但我希望它能像这样工作。那么Mono不支持像.Net那样的功能吗?或者有什么方法可以做到这一点?我不会从不同的线程访问任何创建它们的对象,我认为调用.ShowDialog()也没有意义,但这正是我在搜索时发现的所有站点所使用的。你也应该在UI线程中创建其他Winforms对象。但在您的代码中,您以并行线程创建并显示新的表单。这不是个好主意,因为在这种情况下,将所有调用保持在正确的线程中要困难得多。正确的线程是创建对象的线程(调用构造函数的线程)。我需要表单独立于其他所有线程运行,所以我应该将它放在同一个线程中,但将所有耗时的函数放在一个单独的线程中吗?我之所以避免这样做,是因为它需要所有的.Invoke。是的,你应该在同一个(UI)线程中显示表单,所有其他耗时的工作都应该在并行线程中完成。如果你不熟悉Invoke/BeginInvoke,你可以使用扩展方法来获得更好的API。看看我的编辑。