AmbujKN
AmbujKN

Reputation: 121

Calling UI method from a separate thread with no reference to UI controls

I have a class that exposes a public Event. There are various controls on the GUI that can register their event handlers with this Event to make changes to the controls such as text or back color etc. However, the class that exposes the Event does not keep any references of the UI controls those may have added their event handlers.

During the execution, a separate foreground thread executes a method that will invoke (fire) the public Event. This calls the event handlers that have registered with the event.

The problem is that the event handlers are called on the foreground thread and not on UI thread. How do I marshall the call to the UI thread without the reference of the UI controls?

Upvotes: 2

Views: 1666

Answers (3)

Leonardo
Leonardo

Reputation: 2235

If your concern is to marshall the event call to your (unique) UI thread the ISynchronizeInvoke is all you need.

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    Form mainForm = new MyForm();

    // Initialize the service.
    MyService service = new MyService(mainForm);

    Application.Run(mainForm);
}


public class MyService
{
    public event EventHandler MyEvent;

    private readonly ISynchronizeInvoke synchronizeInvoke;

    public MyService(ISynchronizeInvoke synchronizeInvoke)
    {
        this.synchronizeInvoke = synchronizeInvoke;
    }

    private void OnMyEvent()
    {
        if (MyEvent != null)
        {
            if (synchronizeInvoke.InvokeRequired)
            {
                synchronizeInvoke.BeginInvoke(new Action(() => MyEvent(this, EventArgs.Empty)), null);
            }
            else
            {
                MyEvent(this, EventArgs.Empty);
            }
        }
    }
}

Upvotes: 3

Casperah
Casperah

Reputation: 4554

You can get an open form using Application.OpenForms().

Form form = System.Windows.Forms.Application.OpenForms().FirstOrDefault();
if (form != null)
    form.Invoke((MethodInvoker)delegate(){ event(); });

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1502156

You need to decide what's going to do the marshalling: the event raiser, or the event handlers. If you don't want the event raiser to know anything about threading - e.g. via ISynchronizeInvoke or SynchronizationContext - then make the event handlers do the marshalling instead.

Basically either the event raiser should guarantee that it will raise all events in a particular context (which could be given to it on construction via SynchronizationContext) or it should make it clear that it's not doing so, and put the onus on the handlers. The latter is the more flexible approach - it means that if you have several handlers with different needs, each can do the appropriate thing for its own needs.

Upvotes: 3

Related Questions