2010-10-27 33 views
2

我在解決如何執行此操作時遇到問題。我有兩個實例(源&目標),實現INotifyPropertyChanged,我正在跟蹤兩者的PropertyChanged事件。我想要做的就是在source.PropertyChanged的任何時候執行動作,直到target.PropertyChanged被提出。我能做到這一點就好像這樣:Rx:忽略訂閱者造成的更新

INotifyPropertyChanged source; 
INotifyPropertyChanged target; 

var sourcePropertyChanged = Observable 
    .FromEvent<PropertyChangedEventArgs>(source, "PropertyChanged") 
    .Where(x => x.EventArgs.PropertyName == sourcePropertyName); 

var targetPropertyChanged = Observable 
    .FromEvent<PropertyChangedEventArgs>(target, "PropertyChanged") 
    .Where(x => x.EventArgs.PropertyName == targetPropertyName); 

sourcePropertyChanged 
    .TakeUntil(targetPropertyChanged) 
    .ObserveOnDispatcher() 
    .Subscribe(_ => /*Raises target.PropertyChanged for targetPropertyName*/); 

我遇到的問題是我想忽略造成行動PropertyChanged通知,而只能停在PropertyChanged事件是由外部源引發取值。有沒有一種好方法來實現這一點?

+0

你是什麼意思'PropertyChanged通知的行動'?什麼行爲? – 2010-10-27 15:19:52

+0

@羅納爾我更新了我的解釋,希望能夠更清楚一些,但通過操作我的意思是不返回值的函數。由'/ *表示的部分爲targetPropertyName * /'引發target.PropertyChanged。 – 2010-10-27 15:31:52

回答

4

有沒有建立你在說什麼的方式。下面是一個簡單SkipWhen實現,每一個在「其他」序列中接收的值時跳過下一源值:

public static IObservable<TSource> SkipWhen(this IObservable<TSource> source, 
    IObservable<TOther> other) 
{ 
    return Observable.Defer<TSource>(() => 
    { 
     object lockObject = new object(); 
     Stack<TOther> skipStack = new Stack<TOther>(); 

     other.Subscribe(x => { lock(lockObject) { skipStack.Push(x); }); 

     return source.Where(_ => 
     { 
      lock(lockObject); 
      { 
       if (skipStack.Count > 0) 
       { 
        skipStack.Pop(); 
        return false; 
       } 
       else 
       { 
        return true; 
       } 
      } 
     }); 
    }); 
} 

你的代碼會那麼像這樣(見下文我注)進行更新:

INotifyPropertyChanged source; 
INotifyPropertyChanged target; 

// See the link at the bottom of my answer 
var sourcePropertyChanged = source.GetPropertyChangeValues(x => x.SourceProperty); 

// Unit is Rx's "void" 
var targetChangedLocally = new Subject<Unit>(); 

var targetPropertyChanged = target.GetPropertyChangeValues(x => x.TargetProperty) 
    .SkipWhen(targetChangedLocally); 

sourcePropertyChanged 
    .TakeUntil(targetPropertyChanged) 
    .ObserveOnDispatcher() 
    .Subscribe(_ => 
    { 
     targetChangedLocally.OnNext(); 
     /*Raises target.PropertyChanged for targetPropertyName*/ 
    }); 

注:我最近在博客上寫了a strongly typed IObservable wrapper around INotifyPropertyChanged events;隨意竊取該代碼。

+0

這是一個不錯的解決方案。不幸的是我使用的是Silverlight,所以我沒有可用的ConcurrentStack,我寧願不必爲此實現一個。我更新了標籤以顯示SL。 – 2010-10-27 18:45:49

+0

@Bryan - 這不是問題。將Stack替換爲ConcurrentStack,並在'GetPropertyChangeValues'和'SkipWhen'之間添加'ObserveOnDispatcher' - 或者 - 執行自己的鎖定。我已經通過回覆更新了後者(因爲它不太可能在以後咬你) – 2010-10-27 18:58:08

+0

Doh!謝謝。有些日子,它只是不支付起牀。 – 2010-10-27 20:02:55

0

沒有內置方式,但可以使用Where擴展方法過濾掉可觀察事件。過濾的條件將是事件的發送者。我想target.PropertyChanged事件的發件人不同於其他來源提出的PropertyChanged事件的發件人。

我不完全確定這是否可以使用。

+0

不幸的是,無論發生什麼事情都會導致事件發生,發送者將是任何引發'PropertyChanged'事件的類,在本例中爲'target'。 – 2010-10-27 20:11:31

0

以這種方式在Rx中使用鎖定很好。鎖定時間很短,不會向用戶代碼發出呼叫。

+0

僅供參考 - 這應該是我的答案的評論,而不是自己的答案:) – 2010-11-08 09:50:30