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

时间:2016-06-12 02:07:40

标签: 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.Resources>
      ......   
    </Application.Resources>
</Application>

App.xaml.cs

using Front_Office.ViewModels;
using System.Windows;

namespace Front_Office
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        protected async override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            var mainWindow = new MainWindow { DataContext = await MainWindowViewModel.Create() };
            mainWindow.Show();
        }
    }
}

MainWindow.xaml.cs

using System.Windows;

namespace Front_Office
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

用于通过异步调用创建MainWindowViewModel的工厂模式。

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()
{
}

GetPatientList()

    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;
        }

我正在尝试在后台线程上运行MedicalClient.GetAllPatientsAsync()Thread.Sleep(),以免在应用程序启动时阻止UI。没有运气。

我做错了什么?

非常欢迎任何帮助。

编辑#1:

通过进行以下更改,它似乎可以正常工作。这是正确的方法吗? (这似乎打破了工厂模式,如此处所述)。

/// <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;
}

2 个答案:

答案 0 :(得分:2)

在你的情况下,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();
    }
}

await关键字将停止执行当前方法,释放当前线程(继续执行调用方法或继续执行下一个事件...)并仅在任务完成时继续。
由于mainWindow尚未初始化,因此应用程序无需显示任何内容。

我认为您可以在MainWindow中移动MainWindow.DataContext的初始化(例如Load eventhandler),然后当Create方法完成时,窗口将立即显示并填充数据

答案 1 :(得分:0)

我主要在ASP领域工作 - 我很快就开始了WPF项目。我认为问题在于你正在使用MainView&#34;初始化&#34;实际上被同步调用的方法。

或者如果我的行话是错误的,至少必须在视图呈现之前完成Initialize()。我打算像OnStartup类一样推荐使用,我看到你有以下几行:

var mainWindow = new MainWindow { DataContext = await MainWindowViewModel.Create() };

问题在于应用程序启动时您的代码调用Create()本身等待Intitialize()所以我假设这是应用程序在启动时锁定的位置,除非我错了。你可以投入一些破发点并确认吗?

我的建议如下所示 - 但它仍然需要重构,因为看起来你的对象取决于实际加载显示的数据。

    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();
    }