Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you access UI elements from another thread? (get not set)

I see a lot of threads on google/here on UPDATING a UI element from another thread.

What if I want to just get the value of a checkbox?

Am I able to do this without having to do anything special?

like image 943
Geesu Avatar asked May 04 '12 14:05

Geesu


People also ask

How do you handle the UI update from multiple threads?

1) Have each thread set a "DataUpdated" flag when new data is available, and have the UI periodically check for new data. 2) Create each thread with a callback to a UI Update(...) method to be called when new data becomes available.

Is WPF multi threaded?

Multiple Windows, Multiple ThreadsSome WPF applications require multiple top-level windows. It is perfectly acceptable for one Thread/Dispatcher combination to manage multiple windows, but sometimes several threads do a better job.

Is WPF single threaded?

Typically your WPF projects have a single Dispatcher object (and therefore a single UI thread) that all user interface work is channeled through.


3 Answers

Edit: It seems I have to take back what I wrote before. Tried the following:

Added a textbox called myTextBox and tried to retrieve the value of the Text property:

Thread t = new Thread(
    o =>
    {
        Thread.Sleep(2000);                    
        string value = myTextBox.Text;
        Thread.Sleep(2000);
    });
t.Start();

And it seems that the app (WPF) crashes after 2 seconds. Using the dispatcher works:

Thread t = new Thread(
    o =>
    {
        Thread.Sleep(2000);
        myTextBox.Dispatcher.BeginInvoke(
            (Action)(() => { string value = myTextBox.Text; }));
        Thread.Sleep(2000);
    });
t.Start();

Thus, you still need to go through the dispatcher thread when reading values from GUI components, at least in WPF.

Second edit: This gets better. Apparently repeating the experiment for classic WinForms reveals that it works to read the Text property without using Invoke/BeginInvoke. Interestingly enough, it seems that also setting the property works fine (without invoke), although I'll wager it's not thread safe and the app doesn't complain for some reason.

Bottom line: It's a good idea in any case to use the dispatcher when interacting with GUI components from other threads, as it ensures the reads/writes are serialized to a single thread and so you have no thread-safety issues.

like image 71
Tudor Avatar answered Nov 14 '22 21:11

Tudor


Can you access UI elements from another thread? (get not set)?

No.

Here is the deal. UI elements have very strict thread affinity requirements. This means you can only access the element from the thread hosting it. This includes all kinds of accesses including simple reads.1

It may work fine for simple property getters, but its perceived safeness would be an accidental result of the way that particular control was implemented. Since Control instances have thread affinity they could potentially use thread local storage techniques to save some of their state which, of course, would not be compatible with different thread. Or what if the value you are trying to read is in a half-baked state? There would be no way to synchronize access to that read since the write may be occurring inside code you have no control over. And still this is ignoring subtle memory barrier problems that may arise.

Again, if it appears to work then chalk it up as an accident. Accessing UI elements from a thread than the one hosting them is a recipe for disaster. Things may fail unpredictably and spectacularly.


1There are very few exceptions to this rule. Using the ISynchronizeInvoke methods is one such exception.

like image 41
Brian Gideon Avatar answered Nov 14 '22 19:11

Brian Gideon


You could but strictly it wouldn't be thread safe. For instance if the property Get code would consist of multiple operations, the UI thread could act in the mean time, halfway during the Get operation, causing unexpected results.

like image 2
Peladao Avatar answered Nov 14 '22 21:11

Peladao