我在google / here上看到很多线程在UPDATING来自另一个线程的UI元素。
如果我想获取复选框的值,该怎么办?
我能不做任何特别的事情吗?
答案 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线程。