2016-10-10 79 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>; 
} 
相關問題