問題の概要を説明しましょう。double
型付きのプロパティを持つビュー モデルがあります。このプロパティに値が割り当てられると、かなりコストのかかる計算が行われます。通常は問題になりませんが、UI が a の値Slider
をこのプロパティにバインドすると、生成される急速な変化によって問題が発生します。
最初に行うべき決定は、ビューと、この問題の処理を担当するビューモデルの間です。View-Model がプロパティの割り当てを経費操作にするために「選択」したのに対し、View はSlider
.
これを実装するのに適した場所であるため、私の選択はビュー側になります。ただし、ビューを直接いじるのではなくControl
、機能を追加するために新しいものを作成します。と呼びましょうDelaySlider
。から派生しSilder
、2 つの追加の依存関係プロパティ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();
}
}
}
次に、 View-Model プロパティを に置き換えてバインドSilder
し、そのプロパティでミリ秒の遅延値を指定します。DelaySlider
DelayedValue
Delay
これで、便利な再利用可能なコントロールが得られました。ビューで厄介なトリックをいじっていません。ビューの分離コードに追加のコードはありません。ビューモデルは変更されておらず、邪魔されていません。 Rxのものをまったく含める必要がありました。