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

C# 您可以从另一个线程访问UI元素吗?(未设置),c#,wpf,multithreading,C#,Wpf,Multithreading,我在google/here上看到很多关于从另一个线程更新UI元素的线程 如果我只想得到一个复选框的值呢 我能做到这一点而不需要做任何特殊的事情吗?编辑:似乎我必须收回我以前写的东西。尝试了以下操作: 添加了名为myTextBox的文本框,并尝试检索Text属性的值: Thread t = new Thread( o => { Thread.Sleep(2000); string value = myTe

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

如果我只想得到一个复选框的值呢


我能做到这一点而不需要做任何特殊的事情吗?

编辑:似乎我必须收回我以前写的东西。尝试了以下操作:

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

Thread t = new Thread(
    o =>
    {
        Thread.Sleep(2000);                    
        string value = myTextBox.Text;
        Thread.Sleep(2000);
    });
t.Start();
似乎应用程序(WPF)在2秒后崩溃。使用dispatcher可以:

Thread t = new Thread(
    o =>
    {
        Thread.Sleep(2000);
        myTextBox.Dispatcher.BeginInvoke(
            (Action)(() => { string value = myTextBox.Text; }));
        Thread.Sleep(2000);
    });
t.Start();
因此,从GUI组件读取值时,至少在WPF中,您仍然需要通过dispatcher线程。

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


底线:在任何情况下,在与其他线程的GUI组件交互时使用dispatcher都是一个好主意,因为它可以确保读/写被序列化到单个线程,因此不会出现线程安全问题。

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

您可以,但严格来说,它不是线程安全的。 例如,如果属性Get代码由多个操作组成,那么UI线程可能会在Get操作的中途执行操作,从而导致意外的结果

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

否。

这是交易。UI元素具有非常严格的线程关联性要求。这意味着您只能从承载该元素的线程访问该元素。这包括各种访问,包括简单读取。1

对于简单的属性获取程序来说,它可能工作得很好,但它的安全性可能是特定控件实现方式的意外结果。由于
Control
实例具有线程亲缘关系,它们可能会使用线程本地存储技术来保存它们的一些状态,当然,这些状态与不同的线程不兼容。或者,如果您试图读取的值处于未完成状态,该怎么办?无法同步对该读取的访问,因为写入可能发生在您无法控制的代码内部。这仍然忽略了可能出现的细微的记忆障碍问题

同样,如果它看起来起作用,那就记为事故。从线程访问UI元素而不是从托管它们的线程访问UI元素会导致灾难。事情可能会以不可预测和惊人的方式失败



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

您可以使用委托来执行此操作that@CodeCaster仅仅试着看看什么是有效的并不能让你得到线程安全的代码。@hvd:但它确实满足了这里提出的所有问题。@hvd没关系,我来不及编辑了。我只是想说我在这个问题上看不到太多的研究,比如。嘿,实际上我希望我能把这个问题提高几次,因为这是一个有趣的问题。从我下面的实验中可以看出,它适用于WinForms,但不适用于WPF。有趣。可能与复选框一起使用。选中是因为它是布尔属性。正如其他人所发布的,获取textbox.Text要狡猾得多。“应用程序不会抱怨”->可能在发布模式下运行?@Henk Holterman:我已经尝试了发布和调试,似乎没有发现任何区别。@Geesu:您使用的是WPF还是windows窗体?
Dispatcher
属性仅存在于WPF中。在windows窗体中,您必须直接使用
textBox.BeginInvoke(…)
。奇怪的是,现在我得到了“在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。”当我尝试访问它时,我知道该窗体已创建。即使我可以只打印出值,而不必执行BeginInvoke@Geesu:我建议你用你的代码在另一个问题中发布这个问题,这样其他人也可以看到它。