5

Di seguito è riportata un'implementazione di esempio che utilizza Metro API e associazione dati (utilizzando MVVM) per popolare l'elenco di cartelle in un elenco a discesa.Assegnazione di un risultato asincrono a una proprietà di associazione dati

Il costruttore del modello View utilizza il metodo SetFolders (private async), che chiama un metodo attendibile fileService.GetFoldersAsync() per ottenere l'elenco delle cartelle. L'elenco delle cartelle viene quindi assegnato alla proprietà denominata "Lista cartelle". XAML utilizza questa proprietà per compilare un elenco a discesa utilizzando l'associazione dati.

Mi chiedo se esiste un modo migliore per impostare la proprietà FoldersList senza doverlo impostare nel costruttore come di seguito. Preferisco chiamare il metodo GetFilesAsync e impostare il valore della proprietà FilesList, quando si verifica l'associazione dati effettiva (non durante la classe init). Dal momento che le proprietà non supportano i modificatori asincroni/attendi (per quanto ne so) sto faticando a implementare una soluzione adeguata. Qualche idea molto apprezzata.

Il codice è di seguito.

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 e l'attuazione

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

risposta

6

avrei attuarla come una proprietà pigro e utilizzare ObservableCollection<T> piuttosto che IEnumerable<T>. Lo stiamo facendo in diversi progetti e funziona bene. In questo modo puoi garantire di caricare i dati solo quando necessario. Inoltre, se hai bisogno di precaricarlo, puoi sempre chiamare il metodo di caricamento nel costruttore o altrove.

Come nota a margine, personalmente non esporrei IStorageFolder direttamente dai miei 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); 
    } 
} 

Si noti che è possibile utilizzare la proprietà IsLoading per visualizzare un anello di avanzamento per esempio. dopo che la raccolta osservabile è stata caricata, sarà possibile aggiornarla senza ricrearla. (_folders.Add, _folders.Remove, _folders.Clear ...)

+0

Vedo un problema con questa risposta. Il getter della proprietà Folders non attende LoadData che è buono come dovrebbe bloccare. Ma in LoadData è attesa una funzione in modo che il controllo sia restituito al chiamante/alla proprietà. Per me ciò implica che le _folders non sono necessariamente inizializzate e quindi la proprietà Folders può restituire anche null. – buckley

+0

Sì, il controllo verrà restituito al getter. Ma non è un problema, poiché la proprietà IsLoading verrà impostata su true, segnalando che il caricamento è in corso. Quando l'attività fileService.GetFolderAsync() completa, il flusso del metodo LoadData continuerà come previsto. È vero che la proprietà Folders restituirà null alla fine della chiamata. Ma non appena l'attività GetFolderAsync() completa, verrà generato un evento PropertyChanged. – Eilistraee

+0

In effetti, è vero che la proprietà Folders può restituire true. Funziona come previsto: non si desidera bloccare la chiamata, pertanto l'inizializzazione Lazy dei dati non può avvenire in modo sincrono. Se è necessario attendere LoadData, renderlo pubblico e attendere direttamente prima di chiamare le cartelle. Altrimenti, lascia che il Databinding sia aggiornato non appena i Dati sono disponibili, o faccia affidamento su PropertyChanged. – Eilistraee

Problemi correlati