您可以从另一个线程访问 UI 元素吗? (不设置)
Posted
技术标签:
【中文标题】您可以从另一个线程访问 UI 元素吗? (不设置)【英文标题】:Can you access UI elements from another thread? (get not set) 【发布时间】:2012-05-14 02:40:33 【问题描述】:我在 google/here 上看到了很多关于从另一个线程更新 UI 元素的线程。
如果我只想获取复选框的值怎么办?
我能做到这一点而无需做任何特别的事情吗?
【问题讨论】:
你可以使用委托来做到这一点 @CodeCaster 只是尝试并查看有效的方法通常不会得到线程安全的代码。 @hvd:但它确实满足了这里提出的所有问题。 @hvd 没关系,我来不及编辑了。我只是想说我在这个问题上没有看到太多研究,比如searching。 嘿,实际上我希望我能多次投票,因为结果证明这是一个有趣的问题。从我下面的实验中可以看出,它适用于 WinForms,但不适用于 WPF。很有趣。 【参考方案1】:编辑:看来我得收回之前写的东西了。尝试了以下方法:
添加了一个名为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 的实验表明它可以在不使用 Invoke/BeginInvoke
的情况下读取 Text
属性。有趣的是,似乎设置属性也可以正常工作(无需调用),尽管我敢打赌它不是线程安全的,并且应用程序不会出于某种原因抱怨。
底线:在任何情况下,在与来自其他线程的 GUI 组件交互时使用调度程序都是一个好主意,因为它可以确保读取/写入被序列化到单个线程,因此您有没有线程安全问题。
【讨论】:
“应用程序不抱怨” -> 也许在发布模式下运行? @Henk Holterman:我已经尝试过 Release 和 Debug,但似乎没有发现任何区别。 @Geesu:您使用的是 WPF 还是 windows 窗体?Dispatcher
属性仅存在于 WPF 中。在 Windows 窗体中,您必须直接使用 textBox.BeginInvoke(...)
。
奇怪的是现在我得到“在创建窗口句柄之前不能在控件上调用 Invoke 或 BeginInvoke。”当我尝试访问它时,我知道表单已创建。即使我可以在不执行 BeginInvoke 的情况下打印出值
@Geesu:我建议你在另一个问题中使用你的代码发布这个问题,以便其他人也可以看到它。【参考方案2】:
您可以从另一个线程访问 UI 元素吗? (不设置)?
没有。
这是交易。 UI 元素有非常严格的线程亲和性要求。这意味着您只能从托管它的线程访问该元素。这包括各种访问,包括简单读取。1
对于简单的属性获取器来说它可能工作得很好,但它感知到的安全性将是特定控制实施方式的意外结果。由于Control
实例具有线程亲和性,它们可能会使用线程本地存储技术来保存它们的一些状态,这些状态当然与不同的线程不兼容。或者,如果您尝试读取的值处于半生不熟的状态怎么办?由于写入可能发生在您无法控制的代码中,因此无法同步对该读取的访问。这仍然忽略了可能出现的细微内存屏障问题。
再说一次,如果它看起来有效,那就把它归结为意外。从线程访问 UI 元素而不是从线程访问它们是灾难的根源。事情可能会出人意料地失败。
1这条规则很少有例外。使用ISynchronizeInvoke
方法就是这样一种例外。
【讨论】:
【参考方案3】:你可以但严格来说它不是线程安全的。 例如,如果属性 Get 代码包含多个操作,则 UI 线程可能会在 Get 操作的中途同时进行操作,从而导致意外结果。
【讨论】:
【参考方案4】:像往常一样简单地读取值。只有更新控件,才需要切换到GUI线程。
【讨论】:
可能适用于 CheckBox.Checked '因为它是一个布尔属性。正如其他人发布的那样,获取 textbox.Text 更加狡猾。以上是关于您可以从另一个线程访问 UI 元素吗? (不设置)的主要内容,如果未能解决你的问题,请参考以下文章