過去に BackgroundWorker でこの種の作業を行ったことがありますが、.NET 4.5 の新しい async/await アプローチを使用したいと考えています。私は間違った木を吠えているかもしれません。お知らせ下さい。
目標: 長時間実行される作業を実行し、作業中にプログレス バーを含むモーダル フォームを表示するコンポーネントを作成します。コンポーネントは、ウィンドウへのハンドルを取得して、長時間実行される作業の実行中に対話をブロックします。
ステータス: 以下のコードを参照してください。ウィンドウを操作してみるまでは、うまくやっていると思っていました。放っておくと (つまり、触れないでください!)、すべてが「完全に」実行されますが、いずれかのウィンドウをクリックするだけで、長時間の作業が終了した後にプログラムがハングします。UI スレッドがブロックされているかのように、実際の操作 (ドラッグ) は無視されます。
質問: 私のコードはかなり簡単に修正できますか? もしそうなら、どのように?または、別のアプローチ (BackgroundWorker など) を使用する必要がありますか?
コード(Form1 は、ProgressBar と、ProgressBar の値を設定するパブリック メソッド UpdateProgress を持つ標準フォームです):
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;
}
}
}
}