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

时间:2014-01-29 16:56:49

标签: c# wpf mvvm async-await mvvm-light

我有一个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();
    }
}

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

2 个答案:

答案 0 :(得分:8)

您看到我在博客上描述的classic deadlock situation

要解决此问题,请使用async all the way,正如我在MSDN上有关async最佳做法的文章中所述。

在某些情况下,这可能很难。我有一篇博客文章描述了async constructors的几种方法。但是,由于您正在讨论用户界面的ViewModel和数据,您可能会发现async properties上的博文更有帮助 - 特别是关于数据绑定的部分。

答案 1 :(得分:7)

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

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

    //...
}

至于为什么你的代码不工作,你得到了标准await死锁,你在异步操作中阻塞,阻塞阻止在UI线程上调用continuation,以及有两个不同的操作,每个等待另一个继续,你会陷入僵局。这就是为什么“异步一直”非常重要,而不是同步阻塞异步操作。