我过去曾使用 BackgroundWorker 进行过此类工作,但我想使用 .NET 4.5 的新异步/等待方法。我可能会叫错树。请指教。
目标:创建一个组件,该组件将执行一些长时间运行的工作,并在工作时显示一个带有进度条的模态表单。该组件将获取窗口句柄以在执行长时间运行的工作时阻止交互。
状态:见下面的代码。我以为我做得很好,直到我尝试与窗户互动。如果我不理会事情(即不要碰!),一切都会“完美地”运行,但如果我只点击任一窗口,程序就会在长时间运行的工作结束后挂起。实际交互(拖动)被忽略,就像 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;
}
}
}
}