在ViewModel中调用的异步方法会导致死锁

时间:2016-10-10 12:00:54

标签: c# asynchronous xamarin xamarin.forms prism

我向Github Api请求所以我有异步方法,这些都可以完成这项工作。在它之前,我总是在方法中调用它们,从命令调用(实际上是DelegateCommand)。但现在我想在ViewModel中做请求,因为我需要在页面上显示列表。我正在使用Prism来连接视图和视图模型。 因为我无法使viewmodel异步,所以我无法使用await字,所以我尝试做一些像从task或task.wait获取结果的东西。但有了这个,我有同样的结果。我的应用程序停止在请求时使用白色显示。我读了一些关于它的信息,我理解在非异步方法中调用异步方法很糟糕,它会导致死锁,但我不知道如何处理这个问题。而且我认为死锁导致应用程序停止工作。 这是app死的方法:

public async Task<IEnumerable<RepositoryModel>> GetRepositoriesAsync()
{
    try
    {
        var reposRequest = new RepositoryRequest { Sort = RepositorySort.FullName };
        var gitHubRepos = await _gitHubClient.Repository.GetAllForCurrent(reposRequest);  //async request, don't say about name convention, it is not my method.
        var gitRemoteRepos = new List<RepositoryModel>();
        foreach ( var repository in gitHubRepos )
        {
            var repos = new RepositoryModel();
            repos.RepositoryTypeIcon = GetRepositoryTypeIcon(repository);
            gitRemoteRepos.Add(repos);
        }
        return gitRemoteRepos;
    }
    catch ( WebException ex )
    {
        throw new Exception("Something wrong with internet connection, try to On Internet " + ex.Message);
    }
    catch ( Exception ex )
    {
        throw new Exception("Getting repos from github failed! " + ex.Message);
    }
}

这是viewmodel:

public class RepositoriesPageViewModel : BindableBase
{
    private INavigationService _navigationService;
    private readonly Session _session;
    public ObservableCollection<RepositoryModel> Repositories { get; }
    private readonly RepositoriesManager _repositoriesManager;
    public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider)
    {
        _navigationService = navigationService;
        var token = securedDataProvider.Retreive(ConstantsService.ProviderName, UserManager.GetLastUser());
        _session = new Session(UserManager.GetLastUser(), token.Properties.First().Value);
        var navigationParameters = new NavigationParameters { { "Session", _session } };

        _repositoriesManager = new RepositoriesManager(_session);
        var task = _repositoriesManager.GetRepositoriesAsync();
        //task.Wait();
        Repositories = task.Result as ObservableCollection<RepositoryModel>;
    }
}

1 个答案:

答案 0 :(得分:3)

我建议使用我的NotifyTask<T> type,它提供Task<T>周围的数据绑定包装。我在article on async MVVM data binding中更完整地解释了这种模式。

public class RepositoriesPageViewModel : BindableBase
{
  private INavigationService _navigationService;
  private readonly Session _session;
  public NotifyTask<ObservableCollection<RepositoryModel>> Repositories { get; }
  private readonly RepositoriesManager _repositoriesManager;
  public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider)
  {
    _navigationService = navigationService;
    var token = securedDataProvider.Retreive(ConstantsService.ProviderName, UserManager.GetLastUser());
    _session = new Session(UserManager.GetLastUser(), token.Properties.First().Value);
    var navigationParameters = new NavigationParameters { { "Session", _session } };

    _repositoriesManager = new RepositoriesManager(_session);
    Repositories = NotifyTask.Create(GetRepositoriesAsync());
  }
}

private async Task<ObservableCollection<RepositoryModel>> GetRepositoriesAsync()
{
  return new ObservableCollection<RepositoryModel>(await _repositoriesManager.GetRepositoriesAsync());
}

请注意,使用此方法,您的数据绑定将使用Repositories.Result来访问实际的集合。其他属性也可用,最值得注意的是Repositories.IsCompletedRespositories.IsNotCompleted,用于显示/隐藏繁忙的微调器。