你可以从另一个线程访问UI元素吗? (没有设定)

时间:2022-08-25 23:27:33

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

我在google / here上看到很多线程在UPDATING来自另一个线程的UI元素。

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

如果我想获得复选框的值,该怎么办?

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

我能不做任何特别的事情吗?

4 个解决方案

#1


18  

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:

添加了一个名为myTextBox的文本框,并尝试检索Text属性的值:

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:

似乎应用程序(WPF)在2秒后崩溃。使用调度程序工作:

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.

因此,在从GUI组件读取值时,您仍需要通过调度程序线程,至少在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.

第二次编辑:这会变得更好。显然重复经典WinForms的实验表明,它可以在不使用Invoke / BeginInvoke的情况下读取Text属性。有趣的是,似乎也设置属性工作正常(没有调用),虽然我打赌它不是线程安全的,应用程序不会因为某些原因抱怨。

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.

结论:在任何情况下,在与来自其他线程的GUI组件交互时使用调度程序是个好主意,因为它确保将读/写序列化为单个线程,因此您没有线程安全问题。

#2


7  

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

你可以从另一个线程访问UI元素吗? (没设定)?

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

这是交易。 UI元素具有非常严格的线程亲和力要求。这意味着您只能从托管它的线程访问该元素。这包括各种访问,包括简单的读取

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.

它对于简单的属性获取者可能工作正常,但其感知的安全性将是特定控制实现方式的偶然结果。由于Control实例具有线程关联性,因此它们可能使用线程本地存储技术来保存它们的某些状态,当然这些状态与不同的线程不兼容。或者,如果您尝试阅读的值处于半生不熟状态,该怎么办?由于写入可能发生在您无法控制的代码中,因此无法同步对该读取的访问。而且这仍然忽略了可能出现的微妙的记忆障碍问题。

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.

再说一次,如果看起来有效,那就把它当成一个意外。从托管它们的线程访问UI元素是灾难的一个方法。事情可能无法预测和惊人地失败。


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

1这条规则很少有例外。使用ISynchronizeInvoke方法就是一个这样的例外。

#3


2  

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.

你可以但严格来说它不是线程安全的。例如,如果属性Get代码包含多个操作,则UI线程可以在Get操作期间的中途行动,从而导致意外结果。

#4


0  

simply read the value as you normally do. Only to update the control, you need to switch to GUI thread.

只需像平常一样读取值即可。只有更新控件,才需要切换到GUI线程。

#1


18  

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:

添加了一个名为myTextBox的文本框,并尝试检索Text属性的值:

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:

似乎应用程序(WPF)在2秒后崩溃。使用调度程序工作:

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.

因此,在从GUI组件读取值时,您仍需要通过调度程序线程,至少在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.

第二次编辑:这会变得更好。显然重复经典WinForms的实验表明,它可以在不使用Invoke / BeginInvoke的情况下读取Text属性。有趣的是,似乎也设置属性工作正常(没有调用),虽然我打赌它不是线程安全的,应用程序不会因为某些原因抱怨。

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.

结论:在任何情况下,在与来自其他线程的GUI组件交互时使用调度程序是个好主意,因为它确保将读/写序列化为单个线程,因此您没有线程安全问题。

#2


7  

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

你可以从另一个线程访问UI元素吗? (没设定)?

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

这是交易。 UI元素具有非常严格的线程亲和力要求。这意味着您只能从托管它的线程访问该元素。这包括各种访问,包括简单的读取

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.

它对于简单的属性获取者可能工作正常,但其感知的安全性将是特定控制实现方式的偶然结果。由于Control实例具有线程关联性,因此它们可能使用线程本地存储技术来保存它们的某些状态,当然这些状态与不同的线程不兼容。或者,如果您尝试阅读的值处于半生不熟状态,该怎么办?由于写入可能发生在您无法控制的代码中,因此无法同步对该读取的访问。而且这仍然忽略了可能出现的微妙的记忆障碍问题。

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.

再说一次,如果看起来有效,那就把它当成一个意外。从托管它们的线程访问UI元素是灾难的一个方法。事情可能无法预测和惊人地失败。


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

1这条规则很少有例外。使用ISynchronizeInvoke方法就是一个这样的例外。

#3


2  

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.

你可以但严格来说它不是线程安全的。例如,如果属性Get代码包含多个操作,则UI线程可以在Get操作期间的中途行动,从而导致意外结果。

#4


0  

simply read the value as you normally do. Only to update the control, you need to switch to GUI thread.

只需像平常一样读取值即可。只有更新控件,才需要切换到GUI线程。