5

Poniżej znajduje się przykładowa implementacja, która korzysta z interfejsu API Metro i powiązania danych (przy użyciu MVVM) w celu zapełnienia listy folderów z rozwijanej listy.Przypisywanie wyniku asynchronicznego do właściwości powiązania danych

Konstruktor modelu View korzysta z metody SetFolders (asynchroniczny prywatny), która wywołuje godną zaufania metodę fileService.GetFoldersAsync() w celu pobrania listy folderów. Lista folderów zostanie następnie przypisana do właściwości o nazwie "FoldersList". XAML używa tej właściwości do wypełnienia listy rozwijanej przy użyciu powiązania danych.

Zastanawiam się, czy istnieje lepszy sposób ustawiania właściwości FoldersList bez konieczności ustawiania go w konstruktorze, jak poniżej. Wolałbym wywołać metodę GetFilesAsync i ustawić wartość właściwości FilesList, gdy nastąpi faktyczne powiązanie danych (nie podczas init klasy). Ponieważ właściwości nie obsługują modyfikatorów async/await (o ile mi wiadomo) staram się zaimplementować właściwe rozwiązanie. Wszelkie pomysły bardzo doceniane.

Kod znajduje się poniżej.

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 i realizacja

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

Odpowiedz

6

chciałbym wdrożyć go jako właściwość leniwy i używać ObservableCollection<T> zamiast IEnumerable<T>. Robimy to w kilku projektach i działa dobrze. W ten sposób możesz zagwarantować, że ładujesz dane tylko w razie potrzeby. Ponadto, jeśli chcesz go wstępnie pobrać, zawsze możesz wywołać metodę load w konstruktorze lub w innym miejscu.

Na marginesie, ja osobiście nie ujawniłbym IStorageFolder bezpośrednio z moich ViewModels.

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

Pamiętaj, że możesz użyć właściwości IsLoading, aby wyświetlić na przykład pierścień postępu. po tym, jak załadowana zostanie obserwowalna kolekcja, będziesz mógł ją odświeżyć, nie odtwarzając jej. (_folders.Add, _folders.Remove, _folders.Clear ...)

+0

Widzę problem z tą odpowiedzią. Zbiór właściwości Folders nie czeka na LoadData, która jest dobra, ponieważ powinna blokować. Ale w LoadData oczekuje się funkcji, więc kontrola jest zwracana do wywołującego/właściwości. Dla mnie oznacza to, że _foldery niekoniecznie są inicjowane, a zatem właściwość Folders może również zwrócić wartość null. – buckley

+0

Tak, kontrola zostanie zwrócona do gettera. Ale to nie problem, ponieważ właściwość IsLoading zostanie ustawiona na wartość true, sygnalizując, że ładowanie jest w toku. Po zakończeniu zadania fileService.GetFolderAsync() przepływ metody LoadData będzie kontynuowany zgodnie z oczekiwaniami. To prawda, że ​​właściwość Folders zwróci wartość null na końcu połączenia. Ale zaraz po zakończeniu zadania GetFolderAsync() zostanie wygenerowane zdarzenie PropertyChanged. – Eilistraee

+0

W rzeczywistości prawdą jest, że właściwość Folders może zwracać wartość true. Działa zgodnie z oczekiwaniami: Nie chcesz blokować połączenia, dlatego inicjalizacja Lazy danych nie może odbywać się synchronicznie. Jeśli musisz poczekać na LoadData, upublicznij go i poczekaj na niego bezpośrednio przed wywołaniem Folderów. W przeciwnym razie należy zaktualizować Databinding, gdy tylko dane będą dostępne, lub polegać na PropertyChanged. – Eilistraee

Powiązane problemy