5

다음은 메트로 API 및 데이터 바인딩 (MVVM 사용)을 사용하여 드롭 다운 목록에 폴더 목록을 채우는 샘플 구현입니다.데이터 바인딩 속성에 비동기 결과 할당

View 모델의 생성자는 FileService.GetFoldersAsync() 메소드를 호출하여 폴더 목록을 가져 오는 SetFolders 메서드 (비공개 비동기)를 사용합니다. 그러면 폴더 목록이 "FoldersList"라는 속성에 할당됩니다. XAML은이 속성을 사용하여 데이터 바인딩을 사용하여 드롭 다운 목록을 채 웁니다.

FoldersList 속성을 아래와 같이 생성자에서 설정하지 않고 설정하는 더 좋은 방법이 있는지 궁금합니다. GetFilesAsync 메서드를 호출하고 실제 데이터 바인딩이 발생할 때 (클래스 초기화 도중) FilesList 속성 값을 설정하는 것을 선호합니다. 속성은 async/await modifiers (내가 아는 한)를 지원하지 않기 때문에 적절한 해결책을 구현하는 데 어려움을 겪고 있습니다. 모든 아이디어 크게 감사드립니다.

코드는 다음과 같습니다.

뷰 모델

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 메소드를 호출 할 수 있습니다.

필자는 personality가 IStorageFolder를 내 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); 
    } 
} 

예를 들어 진행률 링을 표시하려면 IsLoading 속성을 사용할 수 있습니다. 그런 다음 관찰 가능한 컬렉션이로드되면 다시 만들지 않고 새로 고칠 수 있습니다. (_folders.Add, _folders.Remove, _folders.Clear ...)

+0

이 답변에 문제가 있습니다. 속성 폴더의 getter는 차단해야하는 LoadData를 기다리지 않습니다. 그러나 LoadData에서 함수는 호출자/속성에 제어가 돌아가도록 기다립니다. 나에게 이것은 _folders가 반드시 초기화되지 않았 음을 의미하므로 Folders 속성은 null도 반환 할 수 있습니다. – buckley

+0

예, 컨트롤이 게터로 다시 제공됩니다. IsLoading 속성이 true로 설정되어 로딩이 진행 중임을 알리기 때문에 문제는 아닙니다. fileService.GetFolderAsync() 작업이 완료되면 LoadData 메서드의 흐름이 예상대로 계속됩니다. Folders 속성은 호출이 끝날 때 null을 반환합니다. 그러나 GetFolderAsync() 작업이 완료 되 자마자 PropertyChanged 이벤트가 발생합니다. – Eilistraee

+0

실제로 Folders 속성이 true를 반환 할 수 있다는 것은 사실입니다. 예상대로 작동합니다. 호출을 차단하고 싶지 않으므로 지연된 데이터 초기화가 동시에 발생할 수 없습니다. LoadData를 기다려야하는 경우이를 공개하고 폴더를 호출하기 전에 직접 기다려야합니다. 그렇지 않으면 데이터 바인딩을 사용할 수있게되는 즉시 Databinding을 업데이트하거나 PropertyChanged를 사용합니다. – Eilistraee

관련 문제