Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 加入线程会毫无例外地停止执行_C#_Multithreading - Fatal编程技术网

C# 加入线程会毫无例外地停止执行

C# 加入线程会毫无例外地停止执行,c#,multithreading,C#,Multithreading,我的应用程序有两个线程——主UI线程和另一个线程 应用程序在单独的线程上收集文件名列表。然后我希望这个列表显示在我的GUI中。在线程完成之前,程序将按需要工作。它会导致以下错误 "The calling thread must be STA, because many UI components require this." 下面的代码正在运行,正如您所看到的,它包含两个操作参数——一个用于AddCurrentFile,另一个称为Complete。在复制过程中,GetDuplicateList

我的应用程序有两个线程——主UI线程和另一个线程

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

"The calling thread must be STA, because many UI components require this."
下面的代码正在运行,正如您所看到的,它包含两个操作参数——一个用于AddCurrentFile,另一个称为Complete。在
复制过程中,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;
            }
        });
因此,为了安抚线程,我在CreateParent()方法中添加了
this.\u duplicatesThread.Join

然而,我认为(请纠正/同意我的观点)此时发生的事情是因为我加入了线程,它实际上取消了非UI线程,因此在进程的这一点上停止!因此,它从不执行
this之后的行

现在,我希望程序员们不要问得更好,但是,我感觉这里的问题更多的是我的设计而不是代码(尽管我很高兴知道模式和代码都是垃圾)


我的问题是,既然我不能通过新线程(因为它不是UI线程)来实现这一点,我需要做什么?这就好像我需要一个委托,比如
NewThread.FinishedExecuting+=DoThisThing()

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

但是,我更愿意以与UI元素相同的方式对待ViewModel,即手动将所有ViewModel更新从后台线程封送到主UI线程。这可以通过
Dispatcher.Invoke
(同步)或
Dispatcher.InvokeAsync
(建议异步)完成

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


听起来就像您只需要从另一个线程调用UI元素上的
.Invoke()
。您不应该从创建UI组件的线程之外的线程访问UI组件。也就是说,您可以通过使用大多数UI组件都具有的
.Invoke()
,来封送对UI线程的调用。这里有一个简单的示例:对不起@sircodesalot,您是对的-我的代码中有一个错误,我已经更新了。异常将在构造函数中引发!因此,在这个阶段,它只是创建一个对象,而不是将对象“分配”给一个控件。也就是说,即使您在一个单独的线程上创建一个组件,该线程运行于单个单元之外(根据WPF的要求),您将永远无法将该组件与UI的其余部分连接起来,因为只要WPF尝试从原始UI线程更新它,它就会由于上述原因而失败。简而言之,您应该使用一个UI线程,然后通过
.Invoke()
封送对UI线程的调用。这样想,当创建控件时,它会记录创建它的线程,然后每次访问该控件时,它都会进行验证检查,以确保只有同一线程访问它。这很酷,但现在你有两个问题。如果在此线程上创建控件,如何将其附加到主UI线程上的其他UI?您仍然可以从主UI线程指向此对象,但基本上整个UI需要在sta上运行。在主ui类的上方添加[StatThread]啊,后台工作线程做了所有的事情,就像那样-它甚至还有我希望的完整委托!!
private void Complete(List<Duplicate> duplicateList)
{
   this._duplicateList = duplicateList;
}
    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;
    }
Thread thread = new Thread(MethodWhichCallesTheConstructor);
        thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start(); 
thread.Join(); //Wait for the thread to end