加入一个线程会停止执行,没有异常

时间:2014-02-11 17:56:43

标签: c# multithreading

我的应用程序有2个线程 - 主UI线程和另一个线程。

应用程序在单独的线程上收集文件名列表。然后我希望这个列表显示在我的GUI中。程序按照需要工作,直到线程完成。它会导致以下错误

"The calling thread must be STA, because many UI components require this."

运行以下代码,正如您所看到的,它需要2个Action Parameters - 一个用于AddCurrentFile,另一个用于Complete。在duplication.GetDuplicateList()期间,它调用了2种方法。

        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;

之后执行该行

现在,我希望程序员不要问这个问题,但是,我觉得这里的问题更多的是我的设计而不是代码(虽然我很高兴知道模式和我的代码是他的垃圾。

我的问题是,由于我不能通过新线程(因为它不是UI线程)这样做,我需要做什么?这几乎就像我需要一个像NewThread.FinishedExecuting += DoThisThing()

这样的代表

2 个答案:

答案 0 :(得分:3)

您应该将ViewModel与View(UI)分开,并使用WPF数据绑定将它们绑定在一起。实际上可以从后台工作线程更新ViewModel对象,WPF框架将自动封送数据绑定UI控件的INotifyPropertyChanged.PropertyChanged通知(至少在.NET 4.5,AFAIK中)。这样,控件将根据需要在主UI线程上自动更新。

但是,我宁愿以与UI元素相同的方式处理ViewModel,即手动将所有ViewModel更新从后台线程封送到主UI线程。这可以使用Dispatcher.Invoke(同步)或Dispatcher.InvokeAsync(异步,推荐)来完成。

也可以使用Progress<T>模式将更新传播到UI线程。这是一个相关的问题/答案:

How to execute task in the wpf background while able to provide report and allow cancellation?

答案 1 :(得分:0)

Thread thread = new Thread(MethodWhichCallesTheConstructor);
        thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start(); 
thread.Join(); //Wait for the thread to end