让我们概述一下问题。你有一个视图模型,它有一些 double 类型的属性。当为该属性分配一个值时,会进行相当昂贵的计算。通常不会有问题,但是当 UI 将 Slider 的值绑定到此属性时,生成的快速更改确实会产生问题。
首先要在视图和负责处理此问题的视图模型之间做出决定。可以说,视图模型“选择”将属性分配作为费用操作的两种方式,另一方面,视图“选择”使用Slider 分配属性。
我的选择是从事物的角度来看,因为那是实现这一点的更好地方。但是,与其直接摆弄 View,不如构建一个新的 Control 来添加该功能。我们称之为DelaySlider。它将派生自Silder,并具有两个额外的依赖属性Delay 和DelayedValue。 DelayedValue 将匹配 Value 属性的现有值,但仅在自上次更改 Value 后经过 Delay 毫秒之后。
这里是控件的完整代码:-
public class DelaySlider : Slider
{
private DispatcherTimer myTimer;
private bool myChanging = false;
#region public double DelayedValue
public double DelayedValue
{
get { return (double)GetValue(DelayedValueProperty); }
set { SetValue(DelayedValueProperty, value); }
}
public static readonly DependencyProperty DelayedValueProperty =
DependencyProperty.Register(
"DelayedValue",
typeof(double),
typeof(DelaySlider),
new PropertyMetadata(0.0, OnDelayedValuePropertyChanged));
private static void OnDelayedValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DelaySlider source = d as DelaySlider;
if (source != null && !source.myChanging)
{
source.Value = (double)e.NewValue;
}
}
#endregion public double DelayedValue
#region public int Delay
public int Delay
{
get { return (int)GetValue(DelayProperty); }
set { SetValue(DelayProperty, value); }
}
public static readonly DependencyProperty DelayProperty =
DependencyProperty.Register(
"Delay",
typeof(int),
typeof(DelaySlider),
new PropertyMetadata(0, OnDelayPropertyChanged));
private static void OnDelayPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DelaySlider source = d as DelaySlider;
if (source != null)
{
source.OnDelayPropertyChanged((int)e.OldValue, (int)e.NewValue);
}
}
private void OnDelayPropertyChanged(int oldValue, int newValue)
{
if (myTimer != null)
{
myTimer.Stop();
myTimer = null;
}
if (newValue > 0)
{
myTimer = new DispatcherTimer();
myTimer.Tick += myTimer_Tick;
myTimer.Interval = TimeSpan.FromMilliseconds(newValue);
}
}
void myTimer_Tick(object sender, EventArgs e)
{
myTimer.Stop();
myChanging = true;
SetValue(DelayedValueProperty, Value);
myChanging = false;
}
#endregion public int Delay
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
if (myTimer != null)
{
myTimer.Start();
}
}
}
现在将您的 Silder 替换为 DelaySlider 并将您的 View-Model 属性绑定到 DelayedValue 并在其 Delay 属性中指定您的毫秒延迟值。
您现在拥有了一个有用的可重用控件,您没有在视图中使用讨厌的技巧,您在视图的代码隐藏中没有额外的代码,视图模型未更改且不受干扰,并且您根本不需要包含 Rx 的东西。