我有一个wpf应用程序,所有viewModel都继承自实现INotifyPropertyChanged的NotifyPropertyChangeClass类(见下文)。
我希望限制发送到视图的通知,以避免由于发送过多通知而导致滞后。 到目前为止,我所做的是使用反应扩展的Sample Sample延迟每个属性。
问题是Gui在节流期间后期更新了。如果在这个时期的开始时提出第一个事件会更加敏感:
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 :(得分: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));
}
}
}
答案 1 :(得分:0)
我还想在同时通知许多更改(它使列表视图陷入泥潭)时限制PropertyChanged通知程序
我最终使用了时间检查,因此,如果自上一个事件起经过500毫秒之前引发了一个新事件,它将在触发所有属性更新之前在500毫秒内阻止此事件以及任何其他事件。 下面的代码
private DateTime _lastPropertyChange = DateTime.Now - TimeSpan.FromMinutes(1);
private readonly TimeSpan _propertyChangeBuffer = TimeSpan.FromMilliseconds(500);
private bool _propertyChangeBlock = false;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (_propertyChangeBlock)
return;
if (_lastPropertyChange < DateTime.Now - _propertyChangeBuffer)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
_lastPropertyChange = DateTime.Now;
}
else
{
_propertyChangeBlock = true;
ThreadPool.QueueUserWorkItem(p =>
{
Thread.Sleep(_propertyChangeBuffer);
_propertyChangeBlock = false;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
});
}
}