Давайте просто наметим проблему. У вас есть модель просмотра, у которой есть double
типизированное свойство. Когда этому свойству присваивается значение, выполняется довольно дорогой расчет. Обычно это не проблема, но когда пользовательский интерфейс связывает значение Slider
с этим свойством, быстрые изменения создают проблему.
Первое решение, которое следует принять, - это представление и модель представления, которая отвечает за решение этой проблемы. Можно утверждать, что оба варианта View-Model «выбрала», чтобы присвоение свойства было операцией с расходами, с другой стороны, View «выбрало» назначение свойства с помощью Slider
.
.
Мой выбор был бы на стороне взгляда, потому что это лучшее место для реализации этого. Однако вместо того, чтобы возиться с View напрямую, я бы построил новый Control
, чтобы добавить функцию. Давайте назовем это DelaySlider
. Он будет производным от Silder
и будет иметь два дополнительных свойства зависимостей Delay
и DelayedValue
. DelayedValue
будет соответствовать существующему значению свойства Value
, но только после истечения Delay
миллисекунд с момента последнего изменения Value
.
Вот полный код для управления: -
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.