c#与Mono的交叉线程窗体



我正在创建一个使用。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()行为。

当我使用。show()时,在。net和Mono上,窗口只是闪烁然后消失。如果我在form2.Show()后面加上一个MessageBox.Show(),它会一直打开,直到你点击OK。

我错过的东西在代码或Mono只是不支持?(我使用Mono 2.8.1)

谢谢你,Adrian

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

在Windows应用程序中,让多个线程与一个窗口或多个共享相同消息泵的窗口对话几乎从来都不是正确的事情。

并且很少需要有多个消息泵。

正确的方法是使用'Invoke'方法手动将工作线程中的所有内容封送回窗口,或者使用类似BackgroundWorker的方法,它会为您隐藏细节。

在简介:

  • 不要阻塞UI线程以进行耗时的计算或I/O
  • 不要从多个线程与UI对话。

如果你使用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.");
}

最新更新