5

Dưới đây là triển khai mẫu sử dụng API tàu điện ngầm và ràng buộc dữ liệu (sử dụng MVVM) để điền danh sách thư mục vào danh sách thả xuống.Gán kết quả async thành thuộc tính ràng buộc dữ liệu

Phương thức khởi tạo của mô hình Xem sử dụng phương thức SetFolders (không đồng bộ riêng tư), gọi phương thức awsable fileService.GetFoldersAsync() để nhận danh sách các thư mục. Danh sách thư mục sau đó được gán cho thuộc tính được gọi là "FoldersList". XAML sử dụng thuộc tính này để điền một danh sách thả xuống bằng cách sử dụng ràng buộc dữ liệu.

Tôi tự hỏi có cách nào tốt hơn để đặt thuộc tính FoldersList mà không phải đặt nó trong hàm tạo như sau. Tôi muốn gọi phương thức GetFilesAsync và thiết lập giá trị thuộc tính FilesList, khi liên kết dữ liệu thực tế xảy ra (không phải trong lớp init). Vì các thuộc tính không hỗ trợ các trình sửa đổi không đồng bộ/chờ đợi (theo như tôi biết), tôi đang cố gắng thực hiện một giải pháp thích hợp. Bất kỳ ý tưởng đánh giá rất nhiều.

Mã bên dưới.

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 và thực hiện

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

Trả lời

6

tôi sẽ thực hiện nó như một thuộc tính lười biếng và sử dụng ObservableCollection<T> hơn IEnumerable<T>. Chúng tôi đang làm điều đó trong một số dự án và nó hoạt động tốt. Bằng cách này bạn có thể đảm bảo rằng bạn đang tải dữ liệu chỉ khi cần thiết. Hơn nữa, nếu bạn cần tìm nạp trước nó, bạn luôn có thể gọi phương thức tải trong hàm tạo hoặc ở nơi khác.

Là một lưu ý phụ, tôi sẽ không hiển thị IStorageFolder trực tiếp từ ViewModels của tôi.

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

Lưu ý rằng bạn có thể sử dụng thuộc tính Đang tải để hiển thị vòng tiến độ chẳng hạn. sau đó bộ sưu tập quan sát được tải, bạn sẽ có thể làm mới nó mà không cần tái tạo nó. (_folders.Add, _folders.Remove, _folders.Clear ...)

+0

Tôi thấy có vấn đề với câu trả lời này. Các getter của tài sản Thư mục không chờ đợi LoadData đó là tốt như nó nên chặn. Nhưng trong LoadData một chức năng được chờ đợi để kiểm soát được trả lại cho người gọi/tài sản. Đối với tôi điều này ngụ ý rằng các _folders không nhất thiết phải khởi tạo và do đó thuộc tính Folders cũng có thể trả về null. – buckley

+0

Có, điều khiển sẽ được đưa trở lại bộ thu thập. Nhưng nó không phải là một vấn đề, vì các IsLoading bất động sản sẽ được thiết lập để đúng, báo hiệu rằng tải đang được tiến hành. Khi hoàn thành nhiệm vụ fileService.GetFolderAsync(), luồng của phương thức LoadData sẽ tiếp tục như mong đợi. Đúng là thuộc tính Folders sẽ trả về null ở cuối cuộc gọi. Nhưng ngay sau khi hoàn thành nhiệm vụ GetFolderAsync(), một sự kiện PropertyChanged sẽ được nâng lên. – Eilistraee

+0

Trên thực tế, đúng là thuộc tính Thư mục có thể trả về giá trị true. Nó hoạt động như mong đợi: Bạn không muốn chặn cuộc gọi, do đó việc khởi tạo Lazy của dữ liệu không thể xảy ra đồng bộ. Nếu bạn cần chờ LoadData, hãy đặt nó ở chế độ công khai và chờ nó trực tiếp trước khi gọi Thư mục. Nếu không, hãy để Databinding được cập nhật ngay sau khi Dữ liệu có sẵn hoặc dựa vào PropertyChanged. – Eilistraee

Các vấn đề liên quan