1

I am using signalR to push messages up to server and down to specific clients.

When I send a message, the receiving client is sent a ReceiveMessage function call from my signalR server, which maps to a static class function in my app. The static class then tries to do new Chat() (my messaging window class) to open a message window on the receiving side.

This throws calling thread must be STA, because many UI components require this.

I have worked with delegates before on simple form elements (like changing a textbox), but I don't understand how to apply that in this situation. When I read about Invoke, it is called on a form object of some sort, which does not exist in my situation?

TLDR; how do I create and show a new instance of a form from a static class function call

Julien
  • 212
  • 1
  • 18
  • 53

3 Answers3

5

Use the current GUI's thread dispatcher. Then call invoke. Par example:

Application.Current.Dispatcher.Invoke(() => { 
      var win = new Window();
      win.show(); 
});
SynerCoder
  • 12,493
  • 4
  • 47
  • 78
  • 1
    Note that you should be aware of the differences between BeginInvoke() vs Invoke() methods - the former will asynchronously perform an action on another thread, while the later synchronously performs an action. Invoke calls, because they are synchronous, can cause deadlocks in certain situations, so should be used only when appropriate. See http://stackoverflow.com/questions/229554/whats-the-difference-between-invoke-and-begininvoke – CrimsonX Jul 30 '12 at 18:01
2

Easiest: make use of App.MainWindow.Dispatcher to perform the create on the GUI thread:

App.MainWindow.Dispatcher.BeginInvoke((Action)(() => { new Chat(); }));

Harder: create a new STA thread, and create the new Window on it.

The latter option is harder because you'll have multiple GUI threads and need to ensure you keep track of operations so the right thread is used in each case. Unless you have a specific reason to have multiple GUI threads stick with the easy option.

Richard
  • 106,783
  • 21
  • 203
  • 265
0

You have to invoke your code in the UI thread. To do this you need a reference to the syncronization context. Suppose you invoked the following code from UI thread:

SynchronizationContext syncContext = SynchronizationContext.Current;

Hereby you got a reference to the context.

Then in the callback method(after receiving a message in the background thread(not UI)) you can do the following:

syncContext.Post((state) =>
                {
                    Window w = new Window(); 

                }, ...);

The code in lambda expression is executed on behalf of UI thread. As far as I know this is what actually happens behind the scene in both "Control.Invoke" and "Dispatcher.Invoked" approaches.

Tony Kh
  • 1,512
  • 11
  • 8