[英]How to implement async INotifyPropertyChanged
我有一個類,其屬性綁定到我的視圖。 為了使我的視圖保持最新,我實現了INotifyPropertyChanged並在每次某些屬性更改時引發事件。
現在我得到了一些重要的函數來凍結我的應用程序 我想把它們放到后台任務中。
第一:這是我目前的做法
(例如點擊按鈕)
private async void HeavyFunc()
{
foreach (var stuff)
{
count += await Task.Run(() => stuff.Fetch());
}
if (count == 0)
//...
}
東西類
public async Task<int> Fetch()
{
//network stuff
RaisePropertyChanged("MyProperty");
}
public async void RaisePropertyChanged(string pChangedProperty)
{
await Application.Current.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new ThreadStart(() =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty);
}
);
}
上面的代碼給出了一個異常(“DependencySource”必須在同一個線程中創建,如“DependencyObject”)。
AFAIK,你通常需要創建一個新線程並運行它(等待它)。 'goit Task.Run(...);'應該做這個工作。
由於PropertyChanged事件直接影響UI,因此在UI線程中調用它似乎是一個很好的決定。 這就是我調用Dispatcher.BeginInvoke的原因。
我不明白:上面的例外是由不同的線程負責數據引起的。 但我明確地在我的UI線程上調用該事件,該對象也應該由UI線程創建。 那么為什么我會得到例外?
我的主要問題是:如何實現INotifyPropertyChanged接口的事件通常是為了避免或處理上面的大多數異步編程問題? 構建函數時應該考慮什么?
現在我得到了一些重要的函數來凍結我的應用程序
如果你真的在做異步“網絡東西”,那么它不應該凍結應用程序。
我的主要問題是:如何實現INotifyPropertyChanged接口的事件通常是為了避免或處理上面的大多數異步編程問題?
我更喜歡的方法是在提升代碼時不處理這個問題。 相反,構建其余代碼以使其尊重UI層。
換句話說,將“服務”(或“業務邏輯”)代碼從“UI”代碼中划分出來,使其工作方式如下:
// In StuffService class:
public async Task<Result> FetchAsync()
{
//network stuff
return result;
}
// In StuffViewModel class:
public async void ButtonClicked()
{
foreach (var stuff)
{
var result = await Task.Run(() => _stuffService.FetchAsync());
MyProperty = result.MyProperty;
count += result.Count;
}
if (count == 0)
//...
}
public Property MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged([CallerMemberName] string pChangedProperty = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty));
}
這樣,就沒有手動跳線,所有屬性都有標准的ViewModel實現,代碼更簡單,更易於維護等。
我確實離開了對Task.Run
的調用,盡管如果您的網絡調用是真正的異步,這應該是多余的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.