简体   繁体   中英

Handling events after receiving a MSMQ message (thread issue?)

I created two separate Windows Forms applications in C# that use MSMQ for communicating. Here's how it works, it looked simple enough though:

  • App1 sends a details request to App2.
  • App2 creates an event to open the window.
  • App2 opens a "details" window.

The only problem I have is that when received the message, the "details" window freezes after appearing.

As I handle MSMQ messages handling in an object that uses threads, I suspect the problem comes from there... But I have no experience in handling MSMQ messages or specific events handling between parts of an application.

Here's part of the code I use for 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();
    }
}

Where did I go wrong? Where did I go right?

Thanks a lot, Stephane.P

EDIT: if the MSMQ handler is stopped with Stop() anywhere around the event sending, the details window appears then disappears right away...

EDIT2: After the workaround given by Slugart, I managed to make this work:

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

Which is used like:

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

You're creating and displaying a form Details on a thread other than the main GUI thread and not an STA thread at that.

Your EventListener should have a reference to a running form (your main form perhaps) and then call form.Invoke() on it.

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

Also sending your event data as the sender is not really following the Event pattern that has been put in front of you. You want to use the EventArgs parameter for this, use the EventHandler delegate (EventHandler in your case).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM