I have the following classes:
using System;
using System.Windows.Forms;
namespace FastEyeControl
{
public partial class ConnectView : Form, IConnectView
{
private IConnectPresenter m_Presenter;
public ConnectView()
{
InitializeComponent();
m_Presenter = new ConnectPresenter(this);
}
public string Hostname
{
get
{
return m_Hostname.Text;
}
}
public int Port
{
get
{
return Convert.ToInt32(m_Port.Text);
}
}
public void ShowMessage(string message)
{
MessageBox.Show(message,
"Success",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
public void ShowError(string message)
{
MessageBox.Show(message,
"ERROR!",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
private void m_ConnectButton_Click(object sender, EventArgs e)
{
m_Presenter.ConnectButtonPressed();
}
}
}
The presenter class:
using System;
using System.Collections.Generic;
namespace FastEyeControl
{
public class ConnectPresenter : IConnectPresenter
{
private IConnectView m_View;
private IConnectModel m_Model;
public ConnectPresenter(IConnectView view)
{
m_View = view;
m_Model = FastEyeClient.Instance;
}
public void ConnectButtonPressed()
{
m_Model.Connect(m_View.Hostname, m_View.Port);
}
private void ConnectionComplete(object sender, ConnectionEventArgs e)
{
// Code here indicating whether connection was successful and informing the view.
// i.e...
if (e.IsConnected)
{
m_View.ShowMessage("Successfully connected.");
}
else
{
m_View.ShowError("Unable to connect.");
}
}
}
}
The model code runs in another thread. The problem is that when I call m_Model.Connect(), I’m calling code that’s usually running in another thread within the main thread still (the UI thread). This is not a database connection. This is a TCP/IP connection to a server. If I set a variable within the model, then I am doing this from the UI thread which is not thread safe.
I know that with user controls, they have InvokeRequired and Invoke/BeginInvoke operations that will handle this situation. But that is for user controls only. I know you can’t just interrupt another thread in the middle of its execution and tell it to call another method instead. I basically want the non-UI thread to call the Connect code somehow.
Just as a test, I tried using a delegate (fire off an event whenever I want to connect) and when I look in the debugger, the Connect code is still running in the UI thread.
I need a multi-threaded event queue essentially. What’s the best way to achieve what I want to do here? Thanks!
This will, no question, use a background thread from the ThreadPool to do the work. Maybe you had tried to call the delegate directly, or called Invoke() on it; that will execute the delegate synchronously.
Now, BeginInvoke is simple to set up, but it has its limitations; you cannot cancel execution of the background thread, and if it throws an exception you cannot catch it in the invoking thread.