Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass a WPF object that was created in thread X, to thread Y?

I create a SolidColorBrush on some non-GUI thread, and want to pass it to a GUI thread to display it, but I get InvalidOperationException: The calling thread cannot access this object because a different thread owns it. (even if I try to Freeze(); it). How do I pass object that was created in thread X to thread Y ?

I know I can create this SolidColorBrush object in the GUI thread with Dispatcher, but that would complicate everything... I want to create it in the worker thread.


Additional details:

I initialize some static delegate in some static class, to allow sending messages from business layer to GUI:

public static class Gui{
    private static PrintMethodDelegate _printMethod;
    public static void InitializeGuiInterface(PrintMethodDelegate printMethod){
        _printMethod = printMethod;
    }
    public static void Print(GuiMessage data) { _printMethod(data); }
}

Initialization (in the GUI thread):

Gui.InitializeGuiInterface(_messagesToUserHandler.PrintMessage);

Then in another (non-gui) thread, I use it:

Gui.Print(new GuiMessage(testDescription) { Foreground = new SolidColorBrush(someColor) });

while GuiMessage is:

public class GuiMessage {
    public string Msg { get; set; }

    private SolidColorBrush _foregroundBrush;
    public SolidColorBrush Foreground
    {
        get { return _foregroundBrush; }
        set { _foregroundBrush = value; }
    }
}
like image 997
Tar Avatar asked May 06 '13 06:05

Tar


People also ask

How to use thread in WPF?

This method is the starting point for the new thread. We create a new window under the control of this thread. WPF automatically creates a new Dispatcher to manage the new thread. All we have to do to make the window functional is to start the Dispatcher.

What is thread affinity in WPF?

So thread affinity means that the thread, in this case the UI thread that instantiates an object is the only thread that can access its members. So for example, dependency object in WPF has thread affinity.

Is WPF single threaded?

The thread affinity is handled by the Dispatcher class, a prioritized message loop for WPF applications. Typically your WPF projects have a single Dispatcher object (and therefore a single UI thread) that all user interface work is channeled through.

What is Dispatcher object in WPF?

A dispatcher is often used to invoke calls on another thread. An example would be if you have a background thread working, and you need to update the UI thread, you would need a dispatcher to do it.


2 Answers

You can create wpf resources in another thread if you freeze them, after that the element can be passed to yet another thread or the gui thread. Remember that a once frozen object can only be modified by making a copy and using that copy. You can't freeze objects that have Bindings or animations attached to it.

like image 186
dowhilefor Avatar answered Oct 02 '22 23:10

dowhilefor


You need to use a Delegate to safe invoke the control.

Use

Control.Invoke

or

Control.BeginInvoke

for this purpose.

private delegate void SetControlPropertyThreadSafeDelegate(Control control, string propertyName, object propertyValue);

public static void SetControlPropertyThreadSafe(Control control, string propertyName, object propertyValue)
{
  if (control.InvokeRequired)
  {
    control.Invoke(new SetControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue });
  }
  else
  {
    control.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue });
  }
}

If you do not use the delegate to safe-invoke them, You will get the exception.

Check these links:

How to update the GUI from another thread in C#?enter link description here

enter link description here

like image 36
Carlos Landeras Avatar answered Oct 02 '22 23:10

Carlos Landeras