Accessing UI (Main) Thread safely in WPF
You can use
Dispatcher.Invoke(Delegate, object[])
on the Application
's (or any UIElement
's) dispatcher.
You can use it for example like this:
Application.Current.Dispatcher.Invoke(new Action(() => { /* Your code here */ }));
or
someControl.Dispatcher.Invoke(new Action(() => { /* Your code here */ }));
WPF Access window created on different UI thread
I simulated your issue using two WPF Window objects and a timer to ensure that the Second Window was created before calling operations on it. Below is my code sample and it updates the second Windows TextBox every five seconds:
private Timer _timer;
private SecondWindow _secondWindow;
public MainWindow()
{
InitializeComponent();
CreateVisualisationWindow();
_timer = new Timer(Callback);
_timer.Change(5000, 5000);
}
private void Callback(object state)
{
UpdateSecondWindowText();
}
private void CreateVisualisationWindow()
{
Thread VisualisationWIndowThread = new Thread(ThreadStartingPoint);
VisualisationWIndowThread.SetApartmentState(ApartmentState.STA);
VisualisationWIndowThread.IsBackground = true;
VisualisationWIndowThread.Start();
}
private void ThreadStartingPoint()
{
_secondWindow = new SecondWindow();
_secondWindow.SecondWindowTextBlock.Text = "Hello";
_secondWindow.Show();
Dispatcher.Run();
}
private void UpdateSecondWindowText()
{
_secondWindow.Dispatcher.BeginInvoke(new Action(() =>
{
_secondWindow.SecondWindowTextBlock.Text = _secondWindow.SecondWindowTextBlock.Text + " World";
}));
}
So the trick is, you need to call the Dispatcher on the second Window in order to gain access to it.
How to access c# WPF control in thread safe way?
You simply want to use the Dispatcher.Invoke
method (or the asynchronous equivalent Dispatcher.BeginInvoke
), which will marshal the call to the main WPF UI thread.
The DependencyObject
class contains a Dispatcher
property, which means all controls and other objects which inherit from this class also provide this property, in a way similar to WinForms. In addition, the Application
object provides access to the dispatcher.
An example usage might be the following (in code-behind of a Window
/UserControl
):
this.Dispatcher.Invoke((Action)(() =>
{
...
}));
Accessing UI from outside thread in Winforms
You MUST access your UI from your UI Thread only. But you can use the Control.Invoke
method - a Form
IS a Control
- to ensure your code is run from the UI Thread.
Also, you have a static BindingList
, but I assume you want to display the contents of that list in an specific form. You should make the BindingList
an instance member instead... or get a reference to a valid Form. The Control.Invoke
method is not static.
There are several ways to do so. I would do it like so:
First, create a method in your Form class that adds the record to the list.
public void AddRecord(Record r) {
if(this.InvokeRequired) {
this.Invoke(new MethodInvoker(() => this.AddRecord(r)));
} else {
this.record_list.Add(r);
}
}
Second, you need to have a reference to the form (in the next step, that is the theForm
variable).
Then, in your listener method, invoke AddRecord
method instead of adding the record in your BindingList
directly.
public static void listen(IPEndPoint server_ip)
{
Console.WriteLine("In listen");
while (true)
{
try
{
byte[] received_bytes = udp_client.Receive(ref server_ip);
string received_data = Encoding.ASCII.GetString(received_bytes);
Record record = JsonConvert.DeserializeObject<Record>(received_data);
theForm.AddRecord(record); // You need a Form instance.
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
Ensuring that things run on the UI thread in WPF
Going over each of your questions, one by one:
- Not quite; you should only invoke onto the UI thread when necessary. See #2.
- Yes, it does matter. You should not just automatically
Invoke
everything. The key is to only invoke onto the UI thread if necessary. To do this, you can use the Dispatcher.CheckAccess method. - That is correct.
- Also correct, and yes, you do run the risk of less responsive programs. Most of the time, you are not going to be looking at a severe performance hit (we're talking about milliseconds for a context switch), but you should only
Invoke
if necessary. That being said, at some points it is unavoidable, so no, I would not say it is bad practice at all. It is just one solution to a problem that you will encounter every now and then. - In every case I have seen, I have made due with
Dispatcher.CurrentDispatcher
. For complex scenarios, this may not be sufficient, but I (personally) have not seen them. - Not entirely correct, but this line of thinking will not do any harm. Let me put it this way: the
Dispatcher
can be used to gain access to the UI thread for the application. But it is not in and of itself the UI thread. BackgroundWorker
is generally used when you have a time-consuming operation and want to maintain a responsive UI while running that operation in the background. Normally you do not use BackgroundWorker instead of Invoke, rather, you use BackgroundWorker in conjunction with Invoke. That is, if you need to update some UI object in your BackgroundWorker, you can Invoke onto the UI thread, perform the update, and then return to the original operation.- Yes. The UI thread of a WPF application, by definition, must be running in a single-threaded apartment.
There's a lot to be said about BackgroundWorker
, I'm sure many questions are already devoted to it, so I won't go into too much depth. If you're curious, check out the MSDN page for BackgroundWorker class.
Detecting whether on UI thread in WPF and Winforms
Don't use
if(Dispatcher.CurrentDispatcher.Thread == Thread.CurrentThread)
{
// Do something
}
Dispatcher.CurrentDispatcher
will, if the current thread do not have a dispatcher, create and return a new Dispatcher
associated with the current thread.
Instead do like this
Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread);
if (dispatcher != null)
{
// We know the thread have a dispatcher that we can use.
}
To be sure you have the correct dispatcher or are on the correct thread you have the following options
Dispatcher _myDispatcher;
public void UnknownThreadCalling()
{
if (_myDispatcher.CheckAccess())
{
// Calling thread is associated with the Dispatcher
}
try
{
_myDispatcher.VerifyAccess();
// Calling thread is associated with the Dispatcher
}
catch (InvalidOperationException)
{
// Thread can't use dispatcher
}
}
CheckAccess()
and VerifyAccess()
do not show up in intellisense.
Also, if you have to resort to these kinds of things its likely due to bad design. You should know which threads run what code in your program.
Related Topics
Best Way to Resolve File Path Too Long Exception
How to Pass Ienumerable List to Controller in MVC Including Checkbox State
Edit a Specific Line of a Text File in C#
How to Find All Partitions of a Set
How to Call the 'Base Implementation' of an Overridden Virtual Method
Decompressing Gzip Stream from Httpclient Response
Why Can't C# Infer Type from This Seemingly Simple, Obvious Case
Unloading the Assembly Loaded with Assembly.Loadfrom()
How to Set Extended File Properties
How to Do Pagination in Datagridview in Winform
General Purpose Fromevent Method
Is a Memory Leak Created If a Memorystream in .Net Is Not Closed
Pass Table Valued Parameter Using Ado.Net
Why Can't I Unbox an Int as a Decimal
How to Get All Constants of a Type by Reflection