Поэтому я создал RangeSlider и запустил тест.
NormalSlider хорошо работает без Bindingmode.Twoway, поэтому я не добавлял двусторонний к любым привязкам.
Результат теста
Когда я перетаскиваю обычный слайдер, это значение изменяется.
- normalSlider.Value
- TTTTT.Value
- rangeSlider.LowValue
- rangeSlider.LowValue
- normalSlider.Value
- TTTTT .Value
Когда я перетаскиваю обычный ползунок, это значение должно измениться.
- normalSlider.Value
- TTTTT.Value
- rangeSlider.LowValue
- normalSlider.Value
TTTTT.Value - rangeSlider.LowValue
И код здесь
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public bool Set(ref T field, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer.Default.Equals(field, value))
return false;
field = value;
RaiseOnPropertyChanged(propertyName);
return true;
}
private void RaiseOnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
private MyTestValues tTTTTT;
public MyTestValues TTTTTT { get => tTTTTT; set => Set(ref tTTTTT, value); }
public MainWindow()
{
TTTTTT = new MyTestValues { HighValue = 100, LowValue = 0 };
InitializeComponent();
}
private void rangeSlider_ValueChanged(SliderValueType arg1, double arg2)
{
Console.WriteLine("Range Slider Value is Changed");
}
}
public class MyTestValues : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public bool Set(ref T field, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer.Default.Equals(field, value))
return false;
field = value;
RaiseOnPropertyChanged(propertyName);
return true;
}
private void RaiseOnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
private double lowValue;
private double highValue;
public double LowValue { get => lowValue; set => Set(ref lowValue, value); }
public double HighValue { get => highValue; set => Set(ref highValue, value); }
}
Это мой код RangeSlider
namespace Common.Control
{
public enum SliderValueType
{
Low,
High
}
public partial class RangeSlider : UserControl, INotifyPropertyChanged
{
#region DP
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(RangeSlider), new PropertyMetadata(false));
public static readonly DependencyProperty IsRangeVisiableProperty = DependencyProperty.Register("IsRangeVisiable", typeof(bool), typeof(RangeSlider), new PropertyMetadata(true));
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(RangeSlider), new PropertyMetadata(100.0, MaximumPropertyChanged));
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(RangeSlider), new PropertyMetadata(0.0, MinimumPropertyChanged));
public static readonly DependencyProperty LowValueProperty = DependencyProperty.Register("LowValue", typeof(double), typeof(RangeSlider), new PropertyMetadata(0.0, LowValuePropertyChanged));
public static readonly DependencyProperty HighValueProperty = DependencyProperty.Register("HighValue", typeof(double), typeof(RangeSlider), new PropertyMetadata(0.0, HighValuePropertyChanged));
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(RangeSlider), new PropertyMetadata(Orientation.Horizontal, OrientationPropertyChanged));
public bool IsReadOnly { get => (bool)GetValue(IsReadOnlyProperty); set => SetValue(IsReadOnlyProperty, value); }
public bool IsRangeVisiable { get => (bool)GetValue(IsRangeVisiableProperty); set => SetValue(IsRangeVisiableProperty, value); }
public double Maximum { get => (double)GetValue(MaximumProperty); set => SetValue(MaximumProperty, value); }
public double Minimum { get => (double)GetValue(MinimumProperty); set => SetValue(MinimumProperty, value); }
public double LowValue { get => (double)GetValue(LowValueProperty); set => SetValue(LowValueProperty, value); }
public double HighValue { get => (double)GetValue(HighValueProperty); set => SetValue(HighValueProperty, value); }
public Orientation Orientation { get => (Orientation)GetValue(OrientationProperty); set => SetValue(OrientationProperty, value); }
private static void MaximumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = d as RangeSlider;
sender.UpdateView(SliderValueType.Low);
sender.UpdateView(SliderValueType.High);
}
private static void MinimumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = d as RangeSlider;
sender.UpdateView(SliderValueType.Low);
sender.UpdateView(SliderValueType.High);
}
private static void LowValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = d as RangeSlider;
sender.CheckInRange(SliderValueType.Low);
sender.UpdateView(SliderValueType.Low);
sender.ValueChanged?.Invoke(SliderValueType.Low, sender.LowValue);
}
private static void HighValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = d as RangeSlider;
sender.CheckInRange(SliderValueType.High);
sender.UpdateView(SliderValueType.High);
sender.ValueChanged?.Invoke(SliderValueType.High, sender.HighValue);
}
private static void OrientationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = d as RangeSlider;
}
#endregion
#region Variables
private double lowPosX;
private double highPosX;
#endregion
#region Events
public event Action ValueChanged;
public event PropertyChangedEventHandler PropertyChanged;
public bool Set(ref T field, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer.Default.Equals(field, value))
return false;
field = value;
RaiseOnPropertyChanged(propertyName);
return true;
}
private void RaiseOnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
#endregion
#region Properties
private double Range_value => Maximum - Minimum;
private double SliderWidth_Pixel => rangeSliderArea.ActualWidth - lowThumb.Width;
private double ValuePerPixel => SliderWidth_Pixel / Range_value;
public double LowPosX { get => lowPosX; set => Set(ref lowPosX, value); }
public double HighPosX { get => highPosX; set => Set(ref highPosX, value); }
#endregion
#region Constructor
public RangeSlider()
{
InitializeComponent();
Loaded += RangeSlider_Loaded;
SizeChanged += RangeSlider_SizeChanged;
}
#endregion
#region Finalizer
~RangeSlider()
{
}
#endregion
#region Functions
private void UpdateView(SliderValueType valueType)
{
switch (valueType)
{
case SliderValueType.Low:
if (Orientation == Orientation.Horizontal)
{
var distanceFromLeft_pixel = (LowValue - Minimum) * ValuePerPixel;
var distanceHighLow = (HighValue - LowValue) * ValuePerPixel;
rangeArea.Margin = new Thickness(distanceFromLeft_pixel, 0, SliderWidth_Pixel - distanceFromLeft_pixel - distanceHighLow, 0);
LowPosX = distanceFromLeft_pixel;
}
else
{
}
break;
case SliderValueType.High:
if (Orientation == Orientation.Horizontal)
{
var distanceFromLeft_pixel = (HighValue - Minimum) * ValuePerPixel;
var distanceHighLow = (HighValue - LowValue) * ValuePerPixel;
rangeArea.Margin = new Thickness(distanceFromLeft_pixel - distanceHighLow, 0, SliderWidth_Pixel - distanceFromLeft_pixel, 0);
HighPosX = distanceFromLeft_pixel;
}
else
{
}
break;
}
}
private void CheckInRange(SliderValueType sliderValue)
{
switch (sliderValue)
{
case SliderValueType.Low:
if (LowValue > HighValue) LowValue = HighValue;
if (LowValue < Minimum) LowValue = Minimum;
break;
case SliderValueType.High:
if (HighValue < LowValue) HighValue = LowValue;
if (HighValue > Maximum) HighValue = Maximum;
break;
}
}
private void MoveBlockTo(Point point, SliderValueType block)
{
double position;
if (Orientation == Orientation.Horizontal)
{
position = point.X;
}
else
{
position = point.Y;
}
var value = Math.Min(Maximum, Minimum + (position / SliderWidth_Pixel) * (Maximum - Minimum));
if (block == SliderValueType.Low)
{
LowValue = value;
}
else if (block == SliderValueType.High)
{
HighValue = value;
}
}
#region Event_Functions
private void RangeSlider_Loaded(object sender, RoutedEventArgs e)
{
UpdateView(SliderValueType.Low);
UpdateView(SliderValueType.High);
}
private void RangeSlider_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateView(SliderValueType.Low);
UpdateView(SliderValueType.High);
}
private void rangeSliderArea_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (!IsReadOnly)
{
if ((lowThumb != null && lowThumb.IsMouseOver) || (highThumb != null && highThumb.IsMouseOver))
return;
var point = e.GetPosition(rangeSliderArea);
if (e.ChangedButton == MouseButton.Left)
{
MoveBlockTo(point, SliderValueType.Low);
}
else if (e.ChangedButton == MouseButton.Right)
{
MoveBlockTo(point, SliderValueType.High);
}
e.Handled = true;
}
}
private void DragStarted(object sender, DragStartedEventArgs e)
{
}
private void DragCompleted(object sender, DragCompletedEventArgs e)
{
}
private void DragDelta(object sender, DragDeltaEventArgs e)
{
if (!IsReadOnly && e.OriginalSource is Thumb thumb && rangeSliderArea != null)
{
double changedValue = 0.0;
if (Orientation == Orientation.Horizontal)
{
var currentChange_PixelWidth = e.HorizontalChange;
changedValue = currentChange_PixelWidth / ValuePerPixel;
}
if (thumb == lowThumb)
{
LowValue += changedValue;
}
else if (thumb == highThumb)
{
HighValue += changedValue;
}
}
}
#endregion
#endregion
}
}
Подробнее здесь: https://stackoverflow.com/questions/788 ... g-properly