从后台线程打开UI线程上的表单

时间:2016-01-06 18:58:00

标签: c# multithreading winforms

我试图从后台线程(我认为)打开一个Form,因为当我调用formName.Show();形式冻结(不是主要形式)。

目标

当用户收到新消息时,弹出带有新消息的newMessageFrm进行回复。

问题

新表单锁定。

以下是我正在使用的代码:

static void OnNewMessage(object sender, S22.Xmpp.Im.MessageEventArgs e)
        {
            if(CheckIfFormIsOpen(e.Jid.ToString(), e.Message.ToString()) == true){

            } else
            {
                newMessageFrm tempMsg = new newMessageFrm(e.Jid.ToString());

                tempMsg._msgText = e.Jid.ToString() + ": " + e.Message.ToString();
                tempMsg.frmId = e.Jid.ToString();
                tempMsg.Show(); //This locks up the application
            }


        }

我正在使用Visual Studio 2015,C#和S22.Xmpp(正如您从代码中看到的那样。)

当此事件触发时,表单会弹出,但随后会锁定。

如果您需要更多信息,请与我们联系。

2 个答案:

答案 0 :(得分:2)

不幸的是,我不知道在没有任何现有表格的情况下如何做到这一点。但我相信你有一些你可以访问的主要形式。或者您可以使用

获取Form
var invokingForm = Application.OpenForms[0];

所以你可以改变你的方法代码:

static void OnNewMessage(object sender, S22.Xmpp.Im.MessageEventArgs e)
{
    var invokingForm = Application.OpenForms[0]; // or whatever Form you can access
    if (invokingForm.InvokeRequired)
    {
        invokingForm.BeginInvoke(new EventHandler<S22.Xmpp.Im.MessageEventArgs>(OnNewMessage), sender, e);
        return; // important!!!
    }

    // the rest of your code goes here, now running
    // on the same ui thread as invokingForm
    if(CheckIfFormIsOpen(e.Jid.ToString(), e.Message.ToString()) == true)
    {
    }
    else
    {
        newMessageFrm tempMsg = new newMessageFrm(e.Jid.ToString());
        tempMsg._msgText = e.Jid.ToString() + ": " + e.Message.ToString();
        tempMsg.frmId = e.Jid.ToString();
        tempMsg.Show();
    }
}

请注意,我保留S22.Xmpp.Im.MessageEventArgs继承自System.EventArgs

答案 1 :(得分:2)

在WinForms中,仍然需要UI对象需要位于带有消息泵的线程上。这通常是主应用程序线程,也称为UI线程。

在Winforms中检查您是否在使用Control.InvokeRequired访问UI对象的正确线程上。如果返回true,则表示您没有使用正确的线程,并且需要使用Invoke操作。

既然你知道自己是一个不同的主题,你就不需要检查,你只需要调用。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        ThreadPool.QueueUserWorkItem(BadBackgroundLaunch);
        ThreadPool.QueueUserWorkItem(GoodBackgroundLaunch);
    }

    private void GoodBackgroundLaunch(object state)
    {
        this.Invoke((Action) (() =>
        {
            var form2 = new SecondForm();
            form2.Text = "Good One";
            form2.Show();
        }));
    }

    private void BadBackgroundLaunch(object state)
    {
        var form2 = new SecondForm();
        form2.Text = "Bad one";
        form2.Show();
    }
}