16

値の変更時にかなり深刻な計算を強制するスライダーを取得したため、ユーザーがスライドを終了したときに、たとえば 50ms が経過した後に実際のイベントを発生させるように調整したいと考えています。

Rx についてさまざまなことを学びましたが、MVVM パターンを使用してこれにどのようにアプローチすればよいかは不明です。

現在の MVVM アプローチでは、viewModel にバインドされたスライダー値を取得しました。既存のコードへの影響を最小限に抑えて Rx スロットルを追加することをお勧めします (少なくとも最初は)。

MVVM と Rx に関する他のスレッドを見たことがありますが、それらが私の問題を正確な方向に導くとは思いません。さまざまなアプローチが考えられますが、自転車を発明したくありません。

4

2 に答える 2

25

この場合、次のような ViewModel の PropertyChanged イベントにバインドする必要があります。

Observable.FromEvent<PropertyChangedEventArgs>(x => this.PropertyChanged +=x, x => this.PropertyChanged -= x)
    .Where(x => x.PropertyName == "SliderName")
    .Select(_ => this.SliderName)
    .Throttle(TimeSpan.FromMilliseconds(50));

または、 ReactiveUIを使用している場合は、次のようになります。

this.WhenAnyValue(x => x.SliderName)
    .Throttle(TimeSpan.FromMilliseconds(50), RxApp.DeferredScheduler);
于 2011-09-20T17:47:57.317 に答える
-8

問題の概要を説明しましょう。double型付きのプロパティを持つビュー モデルがあります。このプロパティに値が割り当てられると、かなりコストのかかる計算が行われます。通常は問題になりませんが、UI が a の値Sliderをこのプロパティにバインドすると、生成される急速な変化によって問題が発生します。

最初に行うべき決定は、ビューと、この問題の処理を担当するビューモデルの間です。View-Model がプロパティの割り当てを経費操作にするために「選択」したのに対し、View はSlider.

これを実装するのに適した場所であるため、私の選択はビュー側になります。ただし、ビューを直接いじるのではなくControl、機能を追加するために新しいものを作成します。と呼びましょうDelaySlider。から派生しSilder、2 つの追加の依存関係プロパティDelayと を持ちDelayedValueます。DelayedValueはプロパティの既存の値と一致しますが、最後の変更からミリ秒が経過しValueた後でのみです。DelayValue

コントロールの完全なコードは次のとおりです。

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し、そのプロパティでミリ秒の遅延値を指定します。DelaySliderDelayedValueDelay

これで、便利な再利用可能なコントロールが得られました。ビューで厄介なトリックをいじっていません。ビューの分離コードに追加のコードはありません。ビューモデルは変更されておらず、邪魔されていません。 Rxのものをまったく含める必要がありました。

于 2011-09-20T21:43:06.080 に答える