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

时间:2012-05-04 14:24:44

标签: c# wpf multithreading

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

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

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

4 个答案:

答案 0 :(得分:19)

编辑:我似乎要收回以前写的内容。尝试以下方法:

添加了一个名为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组件交互时使用调度程序是个好主意,因为它确保将读/写序列化为单个线程,因此您拥有没有线程安全问题。

答案 1 :(得分:8)

  

您可以从其他线程访问UI元素吗? (没设定)?

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

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

同样,如果它似乎工作,那么将其作为一个意外将其粉碎。从一个线程访问UI元素而不是托管它们的UI元素是灾难的一个方法。事情可能无法预测和惊人地失败。


1 此规则的例外情况非常少。使用ISynchronizeInvoke方法就是一个例外。

答案 2 :(得分:2)

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

答案 3 :(得分:0)

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