2014-12-03 49 views
3

我有一個wpf應用程序,所有viewModel都繼承自實現INotifyPropertyChanged的NotifyPropertyChangeClass類(見下文)。Buffer PropertyChanged Events

我想限制發送到視圖的通知,以避免由於發送太多通知而導致滯後。 到目前爲止,我所實現的目標是使用反應擴展方法Sample來延遲每個屬性。

問題在於,Gui在throttlingPeriod後期被刷新了。它會覺得更適應有在這樣的週期始提出了第一個事件:

More graphic explanation

NotifyPropertyChangeClass的代碼:

using System; 
using System.ComponentModel; 
using System.Reactive.Linq; 

namespace MyNameSpace 
{ 
    public class NotifyPropertyChangeClass : INotifyPropertyChanged 
    { 
     public NotifyPropertyChangeClass(int throttlingPeriod) 
     { 
      var obs = Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
       h => this.privatePropertyChanged += h, h => this.privatePropertyChanged -= h); 
      var groupedByName = obs.Select(o => o.EventArgs.PropertyName).GroupBy(x => x).SelectMany(o => o.Sample(TimeSpan.FromMilliseconds(throttlingPeriod))); 
      groupedByName.Subscribe(o => 
      { 
       PropertyChangedEventHandler handler = PropertyChanged; 
       if (handler != null) 
        handler(this, new PropertyChangedEventArgs(o)); 
      }); 
     } 
     public event PropertyChangedEventHandler PropertyChanged; 
     private event PropertyChangedEventHandler privatePropertyChanged; 

     protected virtual void OnPropertyChanged(string propertyName) 
     { 
      PropertyChangedEventHandler handler = privatePropertyChanged; 
      if (handler != null) 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

我如何能實現我想要什麼?

+0

我傾向於認爲,沒有解決方案,恰好滿足你的要求。很顯然,在View中收到的事件通知之間存在延遲。你確切知道這種滯後發生的地點和原因嗎?但即使你確實知道這種滯後的原因,也不能確定你能解決這個問題。你可能不得不通過減少你的油門時間或其他東西來補償它。 – 2014-12-03 14:07:46

回答

1

我沒有試過,但你可以試試這個:

using System; 
using System.ComponentModel; 
using System.Reactive.Linq; 

namespace MyNameSpace 
{ 
    public class NotifyPropertyChangeClass : INotifyPropertyChanged 
    { 
     private bool _isThrottling = false; 

     public NotifyPropertyChangeClass(int throttlingPeriod) 
     { 
      var obs = Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
       h => this.privatePropertyChanged += h, h => this.privatePropertyChanged -= h); 
      var groupedByName = obs.Select(o => o.EventArgs.PropertyName).GroupBy(x => x).SelectMany(o => o.Sample(TimeSpan.FromMilliseconds(throttlingPeriod))); 
      groupedByName.Subscribe(o => 
      { 
       PropertyChangedEventHandler handler = PropertyChanged; 
       if (handler != null) 
        handler(this, new PropertyChangedEventArgs(o)); 
       _isThrottling = false; 
      }); 
     } 
     public event PropertyChangedEventHandler PropertyChanged; 
     private event PropertyChangedEventHandler privatePropertyChanged; 

     protected virtual void OnPropertyChanged(string propertyName) 
     { 
      // Will fire the first time, the event is raised 
      if (!_isThrottling) 
      { 
       PropertyChangedEventHandler handler = PropertyChanged; 
       if (handler != null) 
        handler(this, new PropertyChangedEventArgs(o)); 
      } 

      // Setting to true here will suppress raising the public event 
      // for every subsequent call, until the event is raised 
      // by the observable pattern and the flag is set to false again. 
      _isThrottling = true; 

      // Will always be raised 
      PropertyChangedEventHandler handler = privatePropertyChanged; 
      if (handler != null) 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 
+0

是的,它的工作!請注意,一個布爾'_isThrottling'是不夠的,它應該是一個字典,用於關鍵的PropertyName。 謝謝! – Thomas 2014-12-03 15:35:27

+0

@Thomas - 我已經完成的Rx版本應該避免你必須管理該狀態。 – 2014-12-03 15:36:45

+0

@JamesWorld你的Rx版本在哪裏? – stromms 2017-08-13 22:56:07