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

Gee*_*esu 19 c# wpf multithreading

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

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

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

Tud*_*dor 20

编辑:似乎我必须收回我之前写的内容.尝试以下方法:

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

Thread t = new Thread(
    o =>
    {
        Thread.Sleep(2000);                    
        string value = myTextBox.Text;
        Thread.Sleep(2000);
    });
t.Start();
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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


Bri*_*eon 8

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

没有.

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

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

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


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