5

メトロAPIとデータバインディング(MVVMを使用)を使用してドロップダウンリストにフォルダのリストを設定する実装例を以下に示します。データバインディングプロパティへの非同期結果の割り当て

Viewモデルのコンストラクタは、フォルダのリストを取得するために、待っているメソッドfileService.GetFoldersAsync()を呼び出すSetFoldersメソッド(private async)を使用します。フォルダリストは、 "FoldersList"というプロパティに割り当てられます。 XAMLはこのプロパティを使用して、データバインディングを使用してドロップダウンリストを設定します。

FoldersListプロパティを以下のようにコンストラクタで設定しなくても設定することができます。私はGetFilesAsyncメソッドを呼び出して、実際のデータバインディングが発生したとき(クラスinitではなく)、FilesListプロパティ値を設定する方が好きです。プロパティは(私が知る限り)非同期/待機の修飾子をサポートしていないので、私は適切な解決策を実装するのに苦労しています。任意のアイデアを大いに感謝します

コードは次のとおりです。

のViewModel

public class FileViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    private readonly IFileService fileService; 

    public FileDataViewModel(IFileService fileService) 
    { 
     this.fileService = fileService; 
     SetFolders(); 
    } 

    private async void SetFolders() 
    { 
     FoldersList = await fileService.GetFoldersAsync(); 
    } 

    private IEnumerable<IStorageFolder> foldersList; 
    public IEnumerable<StorageFolder> FoldersList 
    { 
     get { return foldersList; } 
     private set 
     { 
      foldersList = value; 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs("FoldersList")); 
      } 
     } 
    } 
} 

IFileServiceと実装

public interface IFileService { 
    Task<IEnumerable<IStorageFolder>> GetFilesAsync(); 
    } 

public class FileService : IFileService 
{ 
    public async Task<IEnumerable<IStorageFolder>> GetFoldersAsync() 
    { 
     var folder = KnownFolders.DocumentsLibrary; 
     return await folder.GetFoldersAsync(); 
    } 
} 

答えて

6

私は怠け者プロパティとしてそれを実装し、IEnumerable<T>ではなくObservableCollection<T>を使用します。私たちはいくつかのプロジェクトでそれをやっており、うまくいきます。これにより、必要なときにのみデータをロードすることが保証されます。さらに、プリフェッチが必要な場合は、コンストラクタや他の場所でloadメソッドを呼び出すことができます。

私のpersonnalyは、自分のViewModelsからIStorageFolderを直接公開しません。

private async Task LoadData() 
{ 
    if(!IsLoading) 
    { 
    IsLoading = true; 
    Folders = new ObservableCollection<Folder>(await fileService.GetFolderAsync()); 

    } 
    IsLoading = false; 
} 

private ObservableCollection<Folder> _folders; 

public ObservableCollection<Folder> Folders 
{ 
    get 
    { 
    if(_folders == null) 
    { 
     LoadData();//Don't await... 
    } 
    return _folders; 

    } 
    private set 
    { 
    SetProperty(ref _folders,value); 
    } 

} 
private bool _isLoading; 
public bool IsLoading 
{ 
    get 
    { 
    return _isLoading; 
    } 
    private set 
    { 
    SetProperty(ref _isLoading,value); 
    } 
} 

たとえば、IsLoadingプロパティを使用して進行状況を表示できます。その後、観測可能なコレクションがロードされると、再作成せずにリフレッシュすることができます。 (_folders.Add、_folders.Remove、_folders.Clear ...)

+0

この回答に問題があります。プロパティFoldersのゲッターは、ブロックされるべきであるLoadDataを良好に待っていません。しかし、LoadDataでは、コントロールが呼び出し元/プロパティに返されるように関数が待たれています。私にとってこれは、_foldersが必ずしも初期化されていないことを意味し、したがってFoldersプロパティはnullも返すことができます。 – buckley

+0

はい、コントロールはゲッターに戻されます。 IsLoadingプロパティがtrueに設定されているため、ロードが進行中であることを知らせるため、問題ではありません。 fileService.GetFolderAsync()タスクが完了すると、LoadDataメソッドのフローは期待どおりに続行されます。 Foldersプロパティは、呼び出しの最後にnullを返すことは事実です。 GetFolderAsync()タスクが完了するとすぐに、PropertyChangedイベントが発生します。 – Eilistraee

+0

実際、Foldersプロパティがtrueを返すことは事実です。期待どおりに動作します。コールをブロックしたくないため、データの遅延初期化は同期して実行できません。 LoadDataを待つ必要がある場合は、それをパブリックにして、Foldersを呼び出す前に直接待機します。それ以外の場合は、データが使用可能になるとすぐにデータバインディングを更新するか、PropertyChangedを使用します。 – Eilistraee

関連する問題