Tod*_*ang 17 c# multithreading asynchronous winforms async-await
我在过去使用BackgroundWorker得到了这种类型的东西,但是我想使用.NET 4.5的新async/await方法.我可能正在咆哮错误的树.请指教.
目标:创建一个组件,该组件将执行一些长时间运行的工作,并在执行工作时显示带有进度条的模态表单.该组件将获取窗口的句柄,以便在执行长时间运行的工作时阻止交互.
状态:请参阅下面的代码.在我尝试与windows进行交互之前,我以为自己做得很好.如果我把事情单独处理(即不要触摸!),一切都"完美"运行,但是如果我点击任一窗口,程序会在长时间运行结束后挂起.忽略实际交互(拖动),就好像UI线程被阻止一样.
问题:我的代码可以很容易修复吗?如果是这样,怎么样?或者,我应该使用不同的方法(例如BackgroundWorker)吗?
代码(Form1是带有ProgressBar和公共方法的标准表单,UpdateProgress,用于设置ProgressBar的值):
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting..");
var mgr = new Manager();
mgr.GoAsync();
Console.WriteLine("..Ended");
Console.ReadKey();
}
}
class Manager
{
private static Form1 _progressForm;
public async void GoAsync()
{
var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm = new Form1();
_progressForm.Show(owner);
await Go();
_progressForm.Hide();
}
private async Task<bool> Go()
{
var job = new LongJob();
job.OnProgress += job_OnProgress;
job.Spin();
return true;
}
void job_OnProgress(int percent)
{
_progressForm.UpdateProgress(percent);
}
}
class LongJob
{
public event Progressed OnProgress;
public delegate void Progressed(int percent);
public void Spin()
{
for (var i = 1; i <= 100; i++)
{
Thread.Sleep(25);
if (OnProgress != null)
{
OnProgress(i);
}
}
}
}
class Win32Window : IWin32Window
{
private readonly IntPtr _hwnd;
public Win32Window(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get
{
return _hwnd;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*ary 18
在async
与await
关键字并不意味着"在后台线程上运行." 我有一个async
/ await
在我的博客的介绍,描述他们做的意思.您必须在后台线程上明确地放置CPU绑定操作,例如Task.Run
.
此外,基于任务的异步模式文档描述了async
代码的常见方法,例如进度报告.
class Manager
{
private static Form1 _progressForm;
public async Task GoAsync()
{
var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm = new Form1();
_progressForm.Show(owner);
var progress = new Progress<int>(value => _progressForm.UpdateProgress(value));
await Go(progress);
_progressForm.Hide();
}
private Task<bool> Go(IProgress<int> progress)
{
return Task.Run(() =>
{
var job = new LongJob();
job.Spin(progress);
return true;
});
}
}
class LongJob
{
public void Spin(IProgress<int> progress)
{
for (var i = 1; i <= 100; i++)
{
Thread.Sleep(25);
if (progress != null)
{
progress.Report(i);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,该Progress<T>
类型正确处理线程编组,因此不需要在其中进行编组Form1.UpdateProgress
.
@ StephenCleary的回答是正确的.虽然,我不得不对他的答案做一点修改,以获得我认为OP想要的行为.
public void GoAsync() //no longer async as it blocks on Appication.Run
{
var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm = new Form1();
var progress = new Progress<int>(value => _progressForm.UpdateProgress(value));
_progressForm.Activated += async (sender, args) =>
{
await Go(progress);
_progressForm.Close();
};
Application.Run(_progressForm);
}
Run Code Online (Sandbox Code Playgroud)
小智 5
private async void button1_Click(object sender, EventArgs e)
{
IProgress<int> progress = new Progress<int>(value => { progressBar1.Value = value; });
await Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
progress.Report(i);
});
}
Run Code Online (Sandbox Code Playgroud)
如果我错了,请纠正我,但这似乎是更新进度条的最简单方法。
归档时间: |
|
查看次数: |
23869 次 |
最近记录: |