避免过程中表格挂起的任务方法
Task method to avoid hanging of form during process
我有处理大数据的过程,并在过程结束时将结果显示到文本框。
问题是表单在几秒钟内变得不可移动,它不是 "not responding" 挂起状态或完全冻结,我可以在执行过程中使用按钮停止进程。但是我无法在桌面上移动表格几秒钟的处理时间。
我不需要在过程中显示结果,它显示在计算和 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 方法对这种情况更好、更有用。
Invoke
方法正在 UI 上下文中执行,任务正在后台 运行 执行。这样运行操作没有任何意义。
- 创建事件处理程序
async
- 不要使用
StartNew
方法,改用Task.Run
await
那个任务
- 之后在 UI 上下文中调用
Display
方法
因此您的代码可能如下所示:
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
}
尝试像这样使用 Task
对象:
Task myTask = new Task(new Action(()=>
{
// your operations code here
}));
myTask.ContinueWith(c=>
{
yourControlName.BeginInvoke(new Action(()=>
{
// update control here
}));
});
myTask.Start();
请注意,您还可以通过在 Task
之前创建它来在任务执行其工作时显示某种加载表单的对话框,将其放置在继续块中,并在任务之后显示对话框开始
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
然而
因为 StartNew
根据 Stephen Cleary 是危险的(再次感谢 VMAtm )
在你的情况下最好的方法是:
await Task.Run(() => Process());
Display();
请注意,所有这些都适用于您的情况,这只是理想情况下哪个适用于哪种情况的问题...
我有处理大数据的过程,并在过程结束时将结果显示到文本框。
问题是表单在几秒钟内变得不可移动,它不是 "not responding" 挂起状态或完全冻结,我可以在执行过程中使用按钮停止进程。但是我无法在桌面上移动表格几秒钟的处理时间。
我不需要在过程中显示结果,它显示在计算和 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 方法对这种情况更好、更有用。
Invoke
方法正在 UI 上下文中执行,任务正在后台 运行 执行。这样运行操作没有任何意义。
- 创建事件处理程序
async
- 不要使用
StartNew
方法,改用Task.Run
await
那个任务- 之后在 UI 上下文中调用
Display
方法
因此您的代码可能如下所示:
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
}
尝试像这样使用 Task
对象:
Task myTask = new Task(new Action(()=>
{
// your operations code here
}));
myTask.ContinueWith(c=>
{
yourControlName.BeginInvoke(new Action(()=>
{
// update control here
}));
});
myTask.Start();
请注意,您还可以通过在 Task
之前创建它来在任务执行其工作时显示某种加载表单的对话框,将其放置在继续块中,并在任务之后显示对话框开始
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
然而
因为 StartNew
根据 Stephen Cleary 是危险的(再次感谢 VMAtm )
在你的情况下最好的方法是:
await Task.Run(() => Process());
Display();
请注意,所有这些都适用于您的情况,这只是理想情况下哪个适用于哪种情况的问题...