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; }
}
}
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.
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With