WPF应用程序的异步和填充数据

Kil*_*ine 5 c# wpf mvvm mvvm-light async-await

我有一个WPF应用程序,通过构造函数中的方法初始化UI的状态.但是,它永远不会从Wait();构造函数中返回.

这是我目前通过一个相当人为的样本做的事情:

public class SomeViewModel
{
    public ICommand AddDataCommand { get { return RelayCommand(AddDataExecute); } }
    public ObservableCollection<int> UIData { /* Property with INotifyPropertyChanged */}   

    public SomeViewModel() 
    {
        //Load synch. here
        LoadData().Wait();      
    }

    public async Task LoadData()
    {
        UIData = await Task.Run(() => SomeService.SelectAllUIData());
    }

    public async void AddDataExecute()
    {
        //Add new data item to database on separate thread to keep UI responsive
        await Task.Run(() => SomeService.AddNewData(0));

        //Reload data from database and update UI, has to happen after AddNewData completes
        await LoadData();
    }
}
Run Code Online (Sandbox Code Playgroud)

我相信这是悬而未决的,因为我实际上从来没有回来过Task.但是,我不知道以不同的方式异步分配UIData,它在构造函数和调用它的命令中都有效.

Ser*_*rvy 9

如果需要构造为异步,请不要通过构造函数构造对象.使用静态工厂方法:

public class SomeViewModel
{
    private SomeViewModel() 
    { }

    public static async Task<SomeViewModel> Create()
    {
        SomeViewModel model = new SomeViewModel();
        await model.LoadData();
        return model;
    }

    public async Task LoadData()
    {
        UIData = await Task.Run(() => SomeService.SelectAllUIData());
    }

    //...
}
Run Code Online (Sandbox Code Playgroud)

至于为什么你的代码不起作用,你得到了await你在异步操作上阻塞的标准死锁,阻塞阻止了在UI线程上调用continuation,并且每个等待的都有两个不同的操作另外,你会陷入僵局.这就是为什么"异步一直"非常重要,而不是在异步操作上同步阻塞.


Ste*_*ary 9

您将看到我在博客中描述的经典死锁情况.

要解决它,请使用async所有方法,正如我在MSDN中关于async最佳实践的文章中所描述的那样.

在某些情况下,这可能很困难.我有一篇博客文章描述了async构造函数的一些方法.但是,因为你是在谈论一个视图模型和数据的UI,你可能会发现在我的博客文章async性能更有帮助-特别是关于数据的部分结合.