在进程中避免挂起表单的任务方法

时间:2017-03-22 21:12:49

标签: c# multithreading forms task-parallel-library invoke

我在处理结束时有大数据处理和结果显示到文本框。

问题是表单变得不可移动几秒钟,它不是“没有响应”挂起状态或完全冻结,我能够在执行期间用按钮停止进程。但我不能在桌面上移动表格几秒钟的处理。

我不需要在处理期间显示结果,它会以Environment.NewLine作为完整列表显示在计算和计算中。但我想以某种方式避免GUI的短时间固定状态

我尝试将具有UI操作的文本框显示更新到任务中:

private void button1_Click(object sender, EventArgs e)
{
    Process(); 
    Display(); 
}

private void Display()
{
    Task.Factory.StartNew(() => {              
        Invoke((Action)(() =>
            {
                /// Textbox output
            }));
    });
}

现在我可以在此过程中移动窗体,但是如果在窗体上按下鼠标,则在释放鼠标按钮之前它不允许显示结果。另外我不确定这种方法有多安全。我试图找出哪种Task方法对于这种情况更好,更有用。

2 个答案:

答案 0 :(得分:3)

正在UI上下文中执行

Invoke方法,任务正在后台运行。以这种方式运行操作没有任何意义。

  1. 制作事件处理程序async
  2. 请勿使用StartNew方法,而是使用Task.Run
  3. await那个任务
  4. 在UI上下文之后调用Display方法
  5. 所以你的代码看起来像这样:

    private async void button1_Click(object sender, EventArgs e)
    {
        // run process in background
        await Task.Run(() => Process());
        // return to UI context
        Display(); 
    }
    
    private void Display()
    {
        // Textbox output
    }
    

答案 1 :(得分:1)

尝试使用Task这样的对象:

Task myTask = new Task(new Action(()=>
{
// your operations code here
}));
myTask.ContinueWith(c=>
{
  yourControlName.BeginInvoke(new Action(()=>
 {
  // update control here
 }));
});
myTask.Start();

请注意,您还可以通过在Task之前创建任务来完成其工作,并在任务开始后将其部署在其中并在任务启动后showdialoging

Begininvoke会发信号通知创建控件的线程并对ui进行更改,事情是

如果您没有指定控件名称,它将在此处定位表单,并且它们在程序中共享相同的创建者线程,但在复杂的多线程应用程序中则不一样

修改 感谢VMAtm指出不建议使用Task构造函数,我做了一点挖掘并发现了这个: msdn blog

随着说 在你的情况下,正确的做法是:

Task.Factory.StartNew( ()=>
{
  //computing here


      yourControlName.BeginInvoke(new Action(()=>
     {
      // update control here
     }));
}));
   // or display() here if you dont have to do it using begininvoke

<强> 无论其 根据{{​​3}} StartNew是危险的(再次感谢VMAtm) 在您的情况下,最好的方法是:

await Task.Run(() => Process());
Display();

请注意,所有这些都适用于您的情况,这只是理想情况下的哪一个问题......