visual net microsoft lenguaje enciclopedia edición aplicaciones silverlight mvvm system.reactive throttling

silverlight - net - ¿Cómo puedo controlar el evento de cambio de valor de un control deslizante?



microsoft c# lenguaje y aplicaciones pdf (2)

Tengo un control deslizante que en el cambio de valor obliga a un cálculo bastante serio, por lo que quiero estrangularlo para disparar un evento real después de, por ejemplo, que pasen 50 ms cuando el usuario ha terminado de deslizarlo.

Si bien aprendí algunas cosas sobre Rx, no está claro cómo debo enfocar esto utilizando el patrón MVVM.

En mi enfoque actual de MVVM obtuve un valor de control deslizante vinculado a mi viewModel. Preferiría agregar el acelerador Rx con el mínimo impacto posible en el código existente (al menos al principio).

He visto algunos otros hilos sobre MVVM y Rx y no creo que me lleven a una dirección exacta con mi problema. Veo varios enfoques posibles y me gustaría no inventar una bicicleta.


En este caso, debe vincularse al evento PropertyChanged de su ViewModel, algo como:

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

O, si estuvieras usando ReactiveUI , se vería así:

this.WhenAnyValue(x => x.SliderName) .Throttle(TimeSpan.FromMilliseconds(50), RxApp.DeferredScheduler);


Sólo esbozar el problema. Tienes un modelo de vista que tiene alguna propiedad de tipo double . Cuando se asigna un valor a esta propiedad, se realiza un cálculo bastante costoso. Normalmente no sería un problema, pero cuando la IU vincula el valor de un Slider a esta propiedad, los rápidos cambios generados crean un problema.

La primera decisión que se debe tomar es entre la vista y el modelo de vista que es responsable de tratar este problema. Se podría argumentar de dos maneras en que View-Model ha "elegido" para hacer que una asignación de propiedad sea una operación costosa; por otro lado, la Vista ha "elegido" para asignar la propiedad mediante un Slider .

Mi elección estaría en el lado de las cosas porque ese es un mejor lugar para implementar esto. Sin embargo, en lugar de jugar con la Vista directamente, construiría un nuevo Control para agregar la función. Llamémoslo el DelaySlider . Silder de Silder y tendrá dos propiedades de dependencia adicionales Delay y DelayedValue . El valor DelayedValue coincidirá con el valor existente de la propiedad Value , pero solo después de que hayan transcurrido milisegundos de Delay desde que cambió el último Value .

Aquí está el código completo para el control: -

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(); } } }

Ahora reemplace su Silder con DelaySlider y vincule su propiedad View-Model con DelayedValue y especifique el valor de retraso de milisegundos en su propiedad Delay .

Ahora tiene un útil control reutilizable, no se ha metido con trucos desagradables en la Vista, no tiene ningún código adicional en el código subyacente de la vista, el View-Model no se modifica ni se ve afectado y no tiene Tenía que hacer incluir las cosas de Rx en absoluto.