2016-10-10 50 views
0

我向Github Api做请求,所以我有异步方法,这些都是做这个工作。在它之前,我总是在方法中调用它们,即从命令调用(实际上是DelegateCommand)。但现在我想在ViewModel中做请求,因为我需要在页面上显示列表。我正在使用Prism来连接视图和视图模型。 因为我无法使viewmodel异步,所以我不能使用await字样,所以我试图做一些类似于从任务或task.wait获取结果的东西。但与此我有相同的结果。我的应用程序在请求时会停止使用白色显示。我读了一些关于这方面的信息,我明白,在异步方法调用异步方法是不好的,它会导致死锁,但我不知道如何处理这个。我认为僵局会导致该应用停止工作。 这里是方法,其中应用模具:在ViewModel中调用的异步方法导致死锁

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

这里是视图模型:

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

不要在构造函数中使用TPL –

+2

不要在主(GUI)线程中使用'Task.Result'。 –

+2

http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html – Krumelur

回答

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用于显示/隐藏繁忙的旋转器。

+0

非常感谢。还有你的文章。 –

0

如果你要去从构造函数启动你的方法,你可以试试下面:

ISecuredDataProvider _securedDataProvider; 

// New constructor 
public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider) 
{ 
    _navigationService = navigationService; 
    _securedDataProvider = securedDataProvider; 
    System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(Init)); 
} 

private void Init() 
{ 
    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(); 
    Repositories = task.Result as ObservableCollection<RepositoryModel>; 
} 
相关问题