How to pass a WPF object created in thread X to thread Y?

I am creating a SolidColorBrush for some thread without a GUI and I want to pass it to the 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 Freeze(); its) How do I pass an object that was created in thread X to thread Y?

I know that I can create this SolidColorBrush object in a GUI thread using Dispatcher , but this will complicate everything ... I want to create it in a workflow.


Additional Information:

I initialize some static delegate in some static class to allow sending messages from the business layer to the 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) }); 

and GuiMessage :

 public class GuiMessage { public string Msg { get; set; } private SolidColorBrush _foregroundBrush; public SolidColorBrush Foreground { get { return _foregroundBrush; } set { _foregroundBrush = value; } } } 
+8
multithreading c # wpf
source share
3 answers

You can create wpf resources in another thread by freezing them, after which the element can be transferred to another thread or gui thread. Remember that once a frozen object can only be modified by copying and using this copy. You cannot freeze objects to which bindings or animations are attached.

+6
source share

You need to use a delegate to call the control safely.

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 a delegate for a secure call, you will get an exception.

Check out these links:

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

enter the link here

+1
source share

You must use Dispatcher .

You can create a class that will contain the dispatcher created in the main thread, and enter it through your container into any class running in the background thread that should interact with your main thread.

 public interface IUiDispatcher { Dispatcher Dispatcher { get; } } public class UiDispatcher : IUiDispatcher { public UiDispatcher() { if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA && !Thread.CurrentThread.IsBackground && !Thread.CurrentThread.IsThreadPoolThread) { this.Dispatcher = Dispatcher.CurrentDispatcher; } else { throw new InvalidOperationException("Ui Dispatcher must be created in UI thread"); } } public Dispatcher Dispatcher { get; set; } } public class ExecutedOnABackgroundThread { IUiDispatcher uidispatcher; public ExecutedOnABackgroundThread(IUiDispatcher uidispatcher) { this.uidispatcher = uidispatcher; } public void Method() { // Do something on the background thread... // ... // Now we need to do something on the UI this.uidispatcher.Dispatcher.BeginInvoke(new Action(delegate { // Do something }), null); } } 

Create an instance of UiDispatcher at a point where you are sure that you are in the user interface stream, for example, during the initialization of your application. Using the dependency injection container, make sure that only one instance of this class will be created and added to any other class that requires it, and use it to create / manage user interface components.

I chose the code to check if the UiDispatcher constructor is UiDispatcher in the main thread from this answer .

The fact is that you cannot use something created in another thread in the user interface thread. Thus, you need your background thread to be delegated to the main user interface thread, in which the user interface materials are involved.

0
source share

All Articles