【发布时间】:2014-02-12 10:16:11
【问题描述】:
我的应用程序有 2 个线程 - 主 UI 线程和另一个线程。
应用程序在单独的线程上收集文件名列表。然后我希望这个列表显示在我的 GUI 中。该程序按需要运行,直到线程完成。它导致以下错误
"The calling thread must be STA, because many UI components require this."
运行以下代码,如您所见,它需要 2 个操作参数 - 一个用于 AddCurrentFile,一个用于完成。在duplication.GetDuplicateList() 期间,它调用了这两个方法。
this._duplicatesThread = new Thread(() =>
{
try
{
duplication.GetDuplicateList(new Action<string>(AddCurrentFile), new Action<List<Duplicate>>(Complete));
CreateParent();
}
catch (Exception ex)
{
string s = ex.ToString();
throw;
}
});
AddCurrentFile 为我的属性提供一个值,并使用 INotifyProperty 我的 GUI 根据需要进行更新:
private void Complete(List<Duplicate> duplicateList)
{
this._duplicateList = duplicateList;
}
问题是当我调用 CreateParent() 因为这会创建一个新的 UserControl - 然后我得到 The calling thread must be STA, because many UI components require this. 但这发生在 UserControl 的构造函数期间。以下代码是失败的地方
private void CreateParent()
{
ObservableCollection<DuplicateControl> parent = new ObservableCollection<DuplicateControl>();
foreach (var duplicate in this._duplicateList)
{
DuplicateControl ic = new DuplicateControl();//This fails as soon as I enter the constructor. The DuplicateControl uses the UserControl as a base class
parent.Add(ic);
}
this.ParentDuplicate = parent;
}
所以,为了安抚线程,我在 CreateParent() 方法中添加了this._duplicatesThread.Join;
但是,我认为(请正确/同意我的观点)此时发生的事情是因为我正在加入线程,它实际上取消了非 UI 线程,因此在它的进程的那个点停止!因此,它永远不会执行this._duplicatesThread.Join; 之后的行
现在,我希望 Programmers 最好不要问这个问题,但是,我觉得这里的问题更多是我的设计而不是代码(尽管我很高兴知道模式和我的代码很垃圾,呵呵)。
我的问题是,由于我无法通过新线程执行此操作(因为它不是 UI 线程),我需要做什么?就好像我需要像NewThread.FinishedExecuting += DoThisThing()这样的代表
【问题讨论】:
-
听起来就像您只需要从其他线程的 UI 元素上调用
.Invoke()。您不应从与创建它的线程分开的线程访问 UI 组件。也就是说,您始终可以使用大多数 UI 组件都有的.Invoke()来编组对 UI 线程的调用。 -
我很抱歉@sircodesalot,你是对的 - 我的代码有错误,我已经更新了。在构造函数中抛出异常!所以,在这个阶段,它只是创建一个对象,而不是将对象“分配”给控件。
-
也就是说,即使您在一个单独的线程上创建一个用完单个单元的组件(根据 WPF 的要求),您也永远无法将该组件与您的其余部分连接起来UI,因为一旦 WPF 尝试从原始 UI 线程更新它,它就会由于上述原因而失败。简而言之,你应该使用一个 UI 线程,然后通过
.Invoke()对 UI 线程的调用进行编组。 -
这样想,当一个控件被创建时,它会记录哪个线程创建了它,然后每次访问该控件时,它都会进行验证检查以确保它仅被该控件访问同一个线程。
标签: c# multithreading