2013-11-21 35 views
0

我用this blog(最後一段)與INotifyTaskCompletion方法有一個視圖模型的異步性。它很好地工作,但我不得不適應它有一個謊言我的問題 - 我是否正確地做了它。額外的PropertyChanged需要INotifyTaskCompletion後完成其任務

視圖模型:

async Task<ObservableCollection<string>> GetInstancesAsync() 
{ 
    var instances = await TaskEx.Run(new Func<List<string>>(() => Agent.GetInstances())); 
    return new ObservableCollection<string>(instances); 
} 
public INotifyTaskCompletion<ObservableCollection<string>> InstancesAsync { get; private set; } 
string instance; 
public string Instance 
{ 
    get { return instance; } 
    set 
    { 
     instance = value; 
     ProjectsAsync = NotifyTaskCompletion.Create(GetProjetsAsync(value)); 
     raisePropertyChanged("ProjectsAsync"); 
    } 
} 

在構造函數中我開始:

InstancesAsync = NotifyTaskCompletion.Create(GetInstancesAsync(value)); 
raisePropertyChanged("InstancesAsync"); 

數據綁定僅僅是ItemsSource="{Binding InstancesAsync.Result}"。 的INotifyTaskCompletion<TResult>的實現並不複雜,簡稱:task.ContinueWith(t => { PropertyChanged(this, new PropertyChangedEventArgs("Result")); };

我的理解如下:啓動任務之後,raisePropertyChanged("InstancesAsync")有WPF試圖找到InstancesAsync.Result效果。它發現InstancesAsync,因爲此對象實例化之前任務啓動,但結果是null。完成任務後,wpf收到PropertyChanged("Result"),並通過現有訪問者InstancesAsyncResult現在被發現。
wpf中的ItemsSource已填充,現在wpf必須觸發SelectedItem的綁定,並以此方式轉至屬性Instance。因爲在我的情況下,啓動了另一個異步屬性任務。 要完成這個任務,我需要在任務完成後啓動raisePropertyChanged("Instance")

我解決了這個問題,將我的raisePropertyChanged作爲委託,將屬性名稱作爲字符串傳遞給實現類INotifyTaskCompletion

我很滿意這個解決方案,但也許我忽略了一些東西?
編輯:
原來,克萊裏先生的直接方式是正確的,但只有當IsSynchronizedWithCurrentItem=True。否則,不會自動選擇列表中的第一項。

另一個相關的問題彈出。
我加入INotifyTaskCompletion支票if (propertyChanged == null) throw new Exception("PropertyChanged: no subscribers");,因爲我之前遇到過這個問題。

然後在Instance二傳手我說:

private string _instance; 
public string Instance 
{ 
    get { return _instance; } 
    set 
    { 
    if (ProjectsAsync == null && !Properties.Settings.Default.Instance.IsNullOrEmpty()) 
    { 
     value = InstantiesAsync.Result.FirstOrDefault(i => i == Properties.Settings.Default.Instance); 
    } 
    _instance = value; 
    raisePropertyChanged("Instance"); 
    ProjectsAsync = NotifyTaskCompletion.Create(GetProjetsAsync(value)); 
    } 
} 

這裏的想法是重寫底層ICollectionView項目0的默認選擇。
然後我提到的例外發生。我有操縱ICollectionViewCurrentItem,而不是隨意更改值。有任何想法嗎?

我目前的解決方案是避免IsSynchronizedWithCurrentItem=True乾脆當列表被設爲一個新的值設置列表的的SelectedItem。
因此,我不得不訂閱異步PropertyChanged事件:

instancesAsync.PropertyChanged += instancesAsync_Ready; 

還有:

if (e.PropertyName == "Result") 
    { 
     if (instance == null && !Properties.Settings.Default.Instance.IsNullOrEmpty()) 
     { 
      Instance = InstancesAsync.Result.FirstOrDefault(i => i == Properties.Settings.Default.Instance); 
     } 
    } 

回答

1

我不太獲取數據綁定的外觀或者「額外」來電raisePropertyChanged("Instance")是。它不在上面的代碼中。

但是應該工作只在自己的屬性提高PropertyChanged,當他們改變,因爲這樣的:

async Task<ObservableCollection<string>> GetInstancesAsync() 
{ 
    var instances = await TaskEx.Run(() => Agent.GetInstances()); 
    return new ObservableCollection<string>(instances); 
} 

private readonly INotifyTaskCompletion<ObservableCollection<string>> _instancesAsync; 
public INotifyTaskCompletion<ObservableCollection<string>> InstancesAsync 
{ get { return _instancesAsync; } } 

private string _instance; 
public string Instance 
{ 
    get { return _instance; } 
    set 
    { 
    _instance = value; 
    raisePropertyChanged("Instance"); 
    ProjectsAsync = NotifyTaskCompletion.Create(GetProjetsAsync(value)); 
    } 
} 

private INotifyTaskCompletion<ObservableCollection<string>> _projectsAsync; 
public INotifyTaskCompletion<ObservableCollection<string>> ProjectsAsync 
{ 
    get { return _projectsAsync; } 
    set 
    { 
    _projectsAsync = value; 
    raisePropertyChanged("ProjectsAsync"); 
    } 
} 

而且,沒有必要從構造提高PropertyChanged

+0

你是對的,它的工作原理。另一個相關問題現在出現了,也許你可以看看我編輯的問題。 – Gerard

+0

刪除你的'PropertyChanged:no subscribers'異常。如果一個屬性發生了變化,那麼如果沒有人在傾聽,它應該*不會*引發異常。 –

+0

我同意,對於我確定某些問題,例如改變/創建一個對象,例如'_instancesAsync'錯誤。 Evertything現在完美地工作,感謝支持。 – Gerard