收到MSMQ消息后处理事件(线程问题?)

时间:2013-10-13 12:49:49

标签: c# multithreading events msmq

我在C#中创建了两个使用MSMQ进行通信的独立Windows窗体应用程序。这是它的工作原理,但它看起来很简单:

  • App1向App2发送详细信息请求。
  • App2创建一个事件来打开窗口。
  • App2打开“详细信息”窗口。

我遇到的唯一问题是,收到邮件后,“详情”窗口会在出现后冻结。

当我处理使用线程的对象中的MSMQ消息处理时,我怀疑问题来自那里......但我没有处理应用程序各部分之间的MSMQ消息或特定事件处理的经验。

这是我用于App2的代码的一部分:

/*Class declared in the Core namespace*/
public class TaskMessageQueueHandler
{
    public TaskMessageQueueHandler()
    {
        this.Start();
    }

    private Thread m_thread;
    private ManualResetEvent m_signal;
    public event System.EventHandler messageReceived;
    public void Start()
    {
        m_signal = new ManualResetEvent(false);
        m_thread = new Thread(MSMQReceiveLoop);
        m_thread.Start();
    }

    public void Stop()
    {
        m_signal.Set();
    }

    protected virtual void SendEvent(object sender, EventArgs e)
    {
        if (messageReceived != null)
            messageReceived(this.message, e);
    }

    public string message;

    private void MSMQReceiveLoop()
    {
        bool running = true;
        MessageQueue queue = new MessageQueue(@".\Private$\queue1");

        while (running)
        {
            try
            {
                var message = queue.Receive();
                message.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
                this.message = message.Body.ToString();
                string m = this.message;
                SendEvent(m, System.EventArgs.Empty);
                if (m_signal.WaitOne(10))
                {
                    running = false;
                }
            }
            catch
            {
                Console.WriteLine("ERROR");
                running = false;
            }
        }
    }
}

/*Main process, in the Program namespace*/
[...]
Core.TaskMessageQueueHandler tmqh = new Core.TaskMessageQueueHandler();

EventListener el = new EventListener();
tmqh.messageReceived += new System.EventHandler(el.ShowDetails);
[...]
/* Class in the Program namespace */
class EventListener
{
    public void ShowDetails(object sender, EventArgs e)
    {
        int numero = int.Parse(sender as string);
        Details details = new Details(numero);
        details.Show();
    }
}

我哪里出错了?我哪去哪儿了?

非常感谢, Stephane.P

编辑:如果MSMQ处理程序在事件发送的任何地方停止并且Stop(),则会出现详细信息窗口,然后立即消失...

EDIT2:在Slugart给出的解决方法之后,我成功完成了这项工作:

class EventListener
{
    Main control;

    public EventListener(Main main)
    {
         control = main;
    }

    public void ShowDetails(object sender, EventArgs e)
    {
        int numero = int.Parse(sender as string);
        control.Invoke((Action)(() => ShowDetails(numero)));
    }

    private void ShowDetails(int numero)
    {
        Details details = new Details(numero);
        details.Show();
    }
}

使用方法如下:

Core.TaskMessageQueueHandler tmqh = new Core.TaskMessageQueueHandler();
EventListener el = new EventListener(this);
tmqh.messageReceived += new System.EventHandler(el.ShowDetails);

1 个答案:

答案 0 :(得分:3)

您正在主GUI线程以外的线程上创建并显示表单Details,而不是STA线程。

您的EventListener应该引用正在运行的表单(也许是您的主表单),然后在其上调用form.Invoke()

class EventListener
{
    Control control; // A valid running winforms control/form created on an STA thread.

    public void ShowDetails(object sender, string message)
    {
        int numero = int.Parse(message);
        control.Invoke(() => ShowDetails(numero))
    }

    private void ShowDetails(int numero)
    {
        Details details = new Details(numero);
        details.Show();
    }
}

同时发送您的事件数据作为发件人并不是真正遵循放在您面前的事件模式。您想为此使用EventArgs参数,请使用EventHandler委托(在您的情况下为EventHandler)。