私たちのプログラムの 1 つのウィンドウ マネージャーを作成しようとしています。クライアントに一連のウィンドウを表示し、各ウィンドウがさまざまな情報を要求し、その情報を処理してから次のウィンドウに移動する必要があります。新しいウィンドウは動的に追加または削除できるため、ウィンドウ マネージャーです。これを行うために、親ウィンドウを提供するメイン シェルがあります。各子ウィンドウは、コンテンツとして親ウィンドウに挿入されます。次のボタンをクリックすると、子供は画面上の情報を処理し、次のウィンドウに移動できることを親に知らせる必要があります。一部のウィンドウでは処理に最大 30 秒かかる場合があるため、この処理の進行中にビジー インジケーターを表示したいと考えています。親ビューで Telerik RadBusyIndicator を使用してそれを達成しています。ビジー インジケーターを適切に表示するために、await/async を使用して OnNext メソッドを非同期で呼び出そうとしています。OnNext メソッドが呼び出されて処理が行われていますが、処理中に UI スレッドがロックされており、ビジー インジケーターが表示されていません。私のコードの関連部分は次のとおりです。
ShellViewModel.cs (親ウィンドウのビュー モデル):
protected async void NextAction()
{
//This is the property that is bound to the RadBusyIndicator to indicate if it should show or not
IsBusy = true;
//windowManager is the class that tells the child window to start processing and provides the parent window with the next view
bool? retVal = await windowManager.OnNext();
if (retVal == true)
{
GetCurrentView();
}
else if (retVal == null)
{
SetupApp.IsRestarting = true;
GetCurrentView();
SetupApp.Config.RestartPoint = windowManager.CurrentViewCounter;
File.WriteAllText("Config.xml", SetupConfig.Serialize(SetupApp.Config));
System.Diagnostics.Process.Start(Application.ResourceAssembly.Location);
Application.Current.Shutdown();
}
IsBusy = false;
}
private async void GetCurrentView()
{
IsBusy = true;
SetupViewInit retVal = await windowManager.InitializeView();
if (retVal == SetupViewInit.CloseApp)
{
RaiseCloseRequest();
IsBusy = false;
return;
}
IsBusy = false;
Content = windowManager.CurrentView as FrameworkElement;
OnPropertyChanged("CanNext");
OnPropertyChanged("CanBack");
OnPropertyChanged("NextToolTip");
if (windowManager.IsFinalView)
{
CancelText = "Close";
SetupApp.IsComplete = true;
}
}
SetupWindowManager.cs:
public async Task<bool?> OnNext()
{
//calls into the current view model to begin processing
bool? retVal = CurrentViewModel.OnNext();
if (retVal == true)
CurrentViewCounter++;
return retVal;
}
//Called from GetCurrentView to set the current view model and perform any initialization that view model might need
public async Task<SetupViewInit> InitializeView()
{
CurrentView = currentViewList[CurrentViewCounter];
CurrentViewModel.FireNextAction += FireNextAction;
CurrentViewModel.PropertyChanged += PropertyChanged;
SetupViewInit retVal = CurrentViewModel.Init();
if (retVal == SetupViewInit.NextScreen)
{
CurrentViewCounter++;
retVal = await InitializeView();
}
else if (retVal == SetupViewInit.TypeChange)
{
SetupType = SetupApp.Config.SetupType;
MachineType = SetupApp.Config.MachineType;
GetViewList();
retVal = await InitializeView();
}
return retVal;
}
ここでも、すべてのコードが適切に実行されています。コードは UI スレッドをロックしているだけです。違いがある場合は、.net 4.0 で Bcl コンパイラ コンポーネントを使用しています。これは大きなプロジェクトであり、まだ .net 4.5 に移行する準備ができていません。
編集: Sethcran の回答に対する私の回答は、コメントするには長すぎます。
.Net 4.5 ライブラリをまだ使用していないため、Task.Run を使用できません。しかし、Task.Factory.StartNew を見てみました。以下に示すようにコードを変更したところ、コメントに示されている問題が発生しました。
Task.Factory.StartNew<SetupViewInit>(new Func<SetupViewInit>(async () =>
{
CurrentView = currentViewList[CurrentViewCounter];
CurrentViewModel.FireNextAction += FireNextAction;
CurrentViewModel.PropertyChanged += PropertyChanged;
SetupViewInit retVal = CurrentViewModel.Init();
if (retVal == SetupViewInit.NextScreen)
{
CurrentViewCounter++;
retVal = await InitializeView();
}
else if (retVal == SetupViewInit.TypeChange)
{
SetupType = SetupApp.Config.SetupType;
MachineType = SetupApp.Config.MachineType;
GetViewList();
retVal = await InitializeView();
}
//On the following line, VS shows an "Unexpected return value" error
return retVal;
}));
では、タスクからの戻り値を取得するにはどうすればよいでしょうか?
これらの方法のいずれも機能させることができず、まったく別のルートに行き着きました。あなたの提案に感謝しますが、私はこのプロジェクトをこれ以上いじる時間がありません.