2014-12-03 51 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