从后台线程在UI线程上打开一个窗体

问题描述:

我想从后台线程(我认为)打开窗体,因为当我调用formName.Show();被冻结的形式(不是主要形式)。从后台线程在UI线程上打开一个窗体

目标

当用户接收到新的消息时,弹出一个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

从主(UI)线程打开窗体。 –

+1

使用您可访问的任何控件/表单的Invoke或BeginInvoke。看看这个:http://*.com/questions/6708765/how-to-invoke-when-i-have-no-control-available – Gusman

+0

PLease不回答问题中的意见。经过一段时间的评论被删除后,用户也无法将评论标记为答案 – Stralos

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

var invokingForm = Application.OpenForms[0]; 

所以,你可以改变你的方法的代码这样获得Form

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(); 
    } 
} 

请注意,我说assumend是S22.Xmpp.Im.MessageEventArgsSystem.EventArgs继承。

+0

谢谢,这种方法正在工作! –

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

在Winforms检查是否在正确的线程访问UI对象是用Control.InvokeRequired完成。如果这返回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(); 
    } 
} 
+0

你怎么知道OP的方法是在'Form'类中声明的?他只表明这是一种_static_方法。所以你忽略了哪个'Control',他应该调用'Invoke'。 –

+0

应用程序中的任何'Control'都可以。他们都应该在UI线程上。你的方法'Application.OpenForms [0]'很好。 – bigtlb

+0

是的,这就是为什么我认为找到控件是问题的一部分。 –