我正在尝试为我们的一个程序编写一个窗口管理器。它应该向客户端显示一系列窗口,每个窗口询问不同的信息,然后在移动到下一个窗口之前处理该信息。可以动态添加或删除新窗口,因此可以使用窗口管理器。为了做到这一点,我有一个提供父窗口的主 shell。每个子窗口都作为内容插入到父窗口中。当点击下一个按钮时,孩子应该处理屏幕上的信息,然后让父母知道它可以移动到下一个窗口。因为某些窗口的处理可能需要长达 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;
}
}
设置窗口管理器.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 线程。如果有什么不同,我将 Bcl 编译器组件与 .net 4.0 一起使用。这是一个大项目,我们还没有准备好迁移到 .net 4.5。
编辑:我对塞思克兰的回答的回复太长了,无法发表评论。
我不能使用 Task.Run,因为我们还没有使用 .Net 4.5 库。但是,它让我看到了 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;
}));
那么如何从任务中获取返回值呢?
我无法让这些方法中的任何一种发挥作用,最终走上了一条完全不同的路线。感谢您的建议,但我根本没有时间在这个项目上再搞乱他们了。