C# 如何在应用程序启动期间在后台线程上执行异步过程而不阻塞?
简单地说,我看不出是什么阻塞了UI,也看不到如何修复它。我已经盯着这个看了好几个小时了 从一开始, App.xamlC# 如何在应用程序启动期间在后台线程上执行异步过程而不阻塞?,c#,wpf,multithreading,xaml,asynchronous,C#,Wpf,Multithreading,Xaml,Asynchronous,简单地说,我看不出是什么阻塞了UI,也看不到如何修复它。我已经盯着这个看了好几个小时了 从一开始, App.xaml <Application x:Class="Front_Office.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Application x:Class="Front_Office.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Application.Resources>
......
</Application.Resources>
</Application>
我主要在ASP领域工作——我正在快速地开发一个WPF项目。我认为问题在于您使用的是MainView的“Initialize”方法,该方法实际上是同步调用的
或者,如果我的专业术语是错误的,那么在视图呈现之前,至少必须完成Initialize()。我正要推荐使用OnStartup类,我看到您有以下行:
var mainfown=newmainfown{DataContext=wait mainfowneviewmodel.Create()}代码>
问题是,在应用程序启动时,您的代码调用Create()
,这本身就在等待initialize()
,所以我假设这就是应用程序启动时锁定的地方,除非我弄错了。你能不能加几个断点并确认一下
我的建议如下——但仍然需要重构,因为您的对象似乎取决于实际加载以显示的数据
protected async override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainData = await GetPatientList();
// Your MainWindowViewModel's Create() call would have to
//undo it's dependency on GetPatientList(), however. I don't really
//have a coherent example
var mainWindow = new MainWindow { DataContext = await MainWindowViewModel.Create() };
mainWindow.Show();
}
在您的情况下,UI线程没有被阻止,只是没有什么可显示。
这是你的问题:
public partial class App : Application
{
protected async override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainWindow = new MainWindow
{ DataContext = await MainWindowViewModel.Create() };
//next line will be executed after "Create" method will complete
mainWindow.Show();
}
}
wait
关键字将停止执行当前方法,释放当前线程(继续执行调用方方法或继续执行下一个事件…),并仅在任务完成时继续。
由于main窗口
尚未初始化,应用程序没有任何显示
我认为您可以将MainWindow.DataContext
的初始化移动到MainWindow内部(例如Load
eventhandler),然后当Create
方法完成时,窗口将立即显示并填充数据发生了什么?这段代码在启动时运行,但阻塞了UI吗?或者您的任务在启动时根本没有运行?我想我有个主意。@FernandoRodriguez任务正在运行,但在执行任务时UI被阻止。运行(…)。很抱歉……我不知道如何将GetPatientList()移出MainWindowViewModel以完成此任务。另外,在完整的代码中,GetPatientList()只是几个不同的异步过程之一。(例如,代码被减少到最小值)。谢谢。请看我上面的编辑。我没有承诺100%的最佳实践!我只是注意到逻辑有点混乱。尽管我们“拥有”了async和await关键字,但当我需要从代码中的现有位置分离并单独运行时,我仍然使用Task.Run()方法。我希望有人能修改我的答案,使之更符合“最佳实践”。很高兴你现在能工作tho:)+1你的想法基本上就是我在编辑中所做的,并且与斯蒂芬·克利里的评论一致。谢谢,我很困惑。根据我对构造函数中异步调用类创建的工厂模式的理解,MainWindowViewModel的构造函数是私有的,无法从MainWindow.xaml.cs访问。是否正确?请参阅我上面的编辑。@AlanWayne:视图模型不能使用异步工厂模式。您必须在某种“加载”状态下创建它,然后在初始化完成后更新VM属性。@StephenCleary您能举个例子吗??加载更新后如何触发更新?谢谢。@AlanWayne:在MVVM中,更新是通过INotifyPropertyChanged
完成的。我有一个完整的例子。
public static async Task<MainWindowViewModel> Create()
{
var myClass = new MainWindowViewModel();
await myClass.Initialize();
return myClass;
}
private async Task Initialize()
{
PatientList = await GetPatientList();
FilteredPatientList = PatientList;
}
private MainWindowViewModel() : base()
{
}
private Task<ObservableCollection<ViewPatient>> GetPatientList()
{
IsLoading = true;
var x = Task.Run(async () =>
{
Thread.Sleep(30000); // SIMULATING A VERY LONG CALL.
return new ObservableCollection<ViewPatient>(await MedicalClient.GetAllPatientsAsync());
});
IsLoading = false;
return x;
}
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
// Droped the async and the await
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainWindow = new MainWindow { DataContext = MainWindowViewModel.Create() };
mainWindow.Show();
}
}
// Dropped async and await. Added Task.Run()
public static MainWindowViewModel Create()
{
var myClass = new MainWindowViewModel(); // Create/Load ViewModel
Task.Run(()=> myClass.Initialize()); // Update ViewModel from Asynchronous methods.
return myClass;
}
protected async override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainData = await GetPatientList();
// Your MainWindowViewModel's Create() call would have to
//undo it's dependency on GetPatientList(), however. I don't really
//have a coherent example
var mainWindow = new MainWindow { DataContext = await MainWindowViewModel.Create() };
mainWindow.Show();
}
public partial class App : Application
{
protected async override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainWindow = new MainWindow
{ DataContext = await MainWindowViewModel.Create() };
//next line will be executed after "Create" method will complete
mainWindow.Show();
}
}