C# 如何在应用程序启动期间在后台线程上执行异步过程而不阻塞?

C# 如何在应用程序启动期间在后台线程上执行异步过程而不阻塞?,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"

简单地说,我看不出是什么阻塞了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.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();
    }
}