2017-04-12 63 views
2

我想知道是否有更好的方法來將異步數據加載到屬性中。現在我創建一個異步功能,在這樣的屬性的Get部分提出一個任務:MVVM c#如何將異步數據加載到屬性中?

private ObservableCollection<CProyecto> prope; 

public ObservableCollection<CProyecto> Prope 
{ 
    get 
    { 
     if (prope == null) 
     { 
      Task.Run(()=> LoadData()).Wait(); 
     } 

     return proyectos; 
    } 
    set 
    { 
     prope = value; 
     RaisePropertyChanged(); 
    } 
} 

async private Task LoadData() 
{ 
    Prope = await clsStaticClassDataLoader.GetDataFromWebService(); 
} 

這種方法的工作原理,但我不喜歡使用.Wait的,因爲可以隨時鎖定屏幕,如果該服務無法快速響應。

你能指導我這件事嗎?

在此先感謝

+0

什麼,如果你調用wait()方法無論如何阻塞調用線程,開始一個新的任務點.. ..? – mm8

+0

關於異步屬性,您應該閱讀以下內容:https://blog.stephencleary.com/2013/01/async-oop-3-properties.html – mm8

+0

使用「加載事件」從外部源獲取數據。使事件異步並綁定到您的集合。最糟糕的是 – Eldho

回答

1

我處理這個問題的方法是開始加載屬性的過程當對象被構建時,但我沒有等待結果。由於該屬性通知填充時,綁定工作得很好。本質上,它是這樣工作的:

public class MyClass : INotifyPropertyChanged 
{ 
    private ObservableCollection<CProyecto> prope; 

    public ObservableCollection<CProyecto> Prope 
    { 
     get { return prope; } 
     set { prope = value; RaisePropertyChanged(nameof(Prope)); } 
    } 

    public MyClass() 
    { 
     // Don't wait or await. When it's ready 
     // the UI will get notified. 
     LoadData(); 
    } 

    async private Task LoadData() 
    { 
     Prope = await clsStaticClassDataLoader.GetDataFromWebService(); 
    } 
} 

這個作品非常好,並且不會造成任何UI延遲或口吃。如果您希望集合永遠不會成爲null(海事組織的良好慣例),您可以用空集合預先初始化prope字段。

+2

這是一個很好的第一步,但會默默地吞下'LoadData'引發的錯誤。更全面的方法是在LoadData中有一個頂級的'try' /'catch',並用錯誤通知更新你的UI。 –

+0

同意。我正在描述我採取的方法。但是,您有正確的位置來執行錯誤處理。 –

+0

但您無法從構造函數調用異步方法,這與屬性的問題相同。你有這個警告https://msdn.microsoft.com/en-us/library/hh873131.aspx – KillemAll

0

您目前執行的Prope財產沒有太大的意義。在後臺線程上執行LoadData方法毫無意義,因爲當您撥打Wait()時,無論如何都會阻止主線程。你還不如直接調用Wait()LoadData()方法返回的任務:

//BAD IMPLEMENTATION! 
private ObservableCollection<CProyecto> prope; 
public ObservableCollection<CProyecto> Prope 
{ 
    get 
    { 
     if (prope == null) 
      LoadData().Wait(); 
     return proyectos; 
    } 
    set { prope = value; RaisePropertyChanged(); } 
} 

上述實施仍是一個壞的。屬性的getter不應該執行異步操作。你應該閱讀關於這個問題@Stephen克利的博客文章:https://blog.stephencleary.com/2013/01/async-oop-3-properties.html

...並看看他NotifyTaskCompletion類型在他AsyncEx庫:https://github.com/StephenCleary/AsyncEx

+0

好吧它看起來沒有意義,但實際上它有意義,如果我不這樣做,系統掛起時,我打電話給我的web服務。我想這是因爲我調用服務var Response = client.GetAsync(url).Result的方式; – KillemAll

4

我建議你閱讀我的關於async MVVM data-binding的MSDN文章。我有a library,提供了一個NotifyTask<T> type,它可以作爲這樣的:

public class MyClass : INotifyPropertyChanged 
{ 
    public NotifyTask<ObservableCollection<CProyecto>> Prope { get; private set; } 

    public MyClass() 
    { 
    // Synchronously *start* the operation. 
    Prope = NotifyTask.Create(LoadDataAsync()); 
    } 

    async private Task<ObservableCollection<CProyecto>> LoadDataAsync() 
    { 
    return await clsStaticClassDataLoader.GetDataFromWebService(); 
    } 
} 

那麼你的綁定將在Prope.Result操作。

這種方法的好處是,你還可以使用數據綁定隱藏/顯示忙指示器(Prope.IsNotCompleted),顯示控制當數據可用(Prope.IsSuccessfullyCompleted),和錯誤通知(Prope.IsFaulted/Prope.ErrorMessage)。

此外,您還可以指定一個非null默認值,如果你想:

Prope = NotifyTask.Create(LoadDataAsync(), new ObservableCollection<CProyecto>()); 
+0

我會讀它,謝謝你的時間 – KillemAll