20

我在 google/here 上看到了很多关于从另一个线程更新 UI 元素的线程。

如果我只想获取复选框的值怎么办?

我能做到这一点而不必做任何特别的事情吗?

4

4 回答 4

20

编辑:看来我必须收回我之前写的东西。尝试了以下方法:

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

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

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

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

因此,在从 GUI 组件读取值时,您仍然需要通过调度程序线程,至少在 WPF 中是这样。

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

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

于 2012-05-04T14:26:35.407 回答
8

您可以从另一个线程访问 UI 元素吗?(不设置)?

不。

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

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

同样,如果它看起来有效,那么将其归为意外。从线程访问 UI 元素而不是从线程访问它们是灾难的根源。事情可能会出人意料地失败。


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

于 2012-05-04T16:28:19.737 回答
2

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

于 2012-05-04T14:27:17.170 回答
0

只需像往常一样读取值。仅要更新控件,您需要切换到 GUI 线程。

于 2012-05-04T14:27:15.517 回答