[英]Binding slider Value with Minimum set in XAML
我对WPF绑定行为有些困惑。 我在代码背后有一个绑定到依赖属性的滑块值(仅作为示例)。 滑块的最小值在XAML中设置。 加载窗口后,将滑块的值设置为最小值,但dependency属性仍具有默认值0。但是,正在调用滑块的ValueChanged回调,因此我实际上希望绑定是更新。
因此,我有以下窗口,一个标签显示滑块值,另一个标签显示值绑定到的属性。
<Window x:Class="SliderBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" x:Name="window">
<StackPanel DataContext="{Binding ElementName=window}">
<Slider Minimum="10" Maximum="100" x:Name="slider" Value="{Binding SliderValue, Mode=TwoWay}" ValueChanged="Slider_OnValueChanged"/>
<Label Content="{Binding Value, ElementName=slider}"></Label>
<Label Content="{Binding SliderValue}"></Label>
</StackPanel>
</Window>
后面的代码包含依赖项属性和事件回调,该事件回调在更改滑块值时仅打印跟踪消息。
using System;
using System.Diagnostics;
using System.Windows;
namespace SliderBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
/* Sorry, wrong code
public double SliderValue
{
get; set;
}*/
public double SliderValue
{
get { return (double)GetValue(SliderValueProperty); }
set { SetValue(SliderValueProperty, value); }
}
public static readonly DependencyProperty SliderValueProperty =
DependencyProperty.Register("SliderValue", typeof(double), typeof(MainWindow), new PropertyMetadata(default(double)));
private void Slider_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Trace.TraceInformation("Slider value changed to {0}", e.NewValue);
}
}
}
一旦移动滑块,两个值就相等。
我的问题是,当滑块值设置为最小值时,为什么在启动时不更新依赖项属性?
以斜体编辑。
此处发生的是,滑块控件的Value
属性被强制设置为处于Minimum
属性和Maximum
属性定义的范围内。
加载XAML并绑定绑定后,将读取SliderValue
零,并且WPF尝试设置Value
属性。 但是,由于零不在其他属性定义的范围内,因此将提供的值强制转换为该范围,因此Value
属性保持为10(设置Minimum
属性时给出的值)。 因此,从标签绑定中可以看到, SliderValue
的值保持为0,而滑块的Value
保持为10。
拖动滑块时,滑块的Value
属性会更改。 这将导致双向绑定被更新,但方向相反(从控件到依赖属性)。 由于DP上没有强制性,因此其值将设置为滑块的值。 从那时起,两者是同步的。
您可以通过在窗口中添加按钮,然后在OnClick
处理程序中将SliderValue
设置为滑块范围之外的值来验证此行为。 您将看到SliderValue
发生了变化,但是由于强制,滑块的值被设置为其最小值或最大值。
值强制是可以为依赖项属性配置的功能之一。 在MSDN上了解有关它的更多信息。
如果查看Slider的ValueProperty的源代码, CoerceValueCallback
在其DP注册中提供CoerceValueCallback
,以确保该值始终在滑块的最大值和最小值之内。 因此,每当绑定源属性传递某个不在范围内的值时,它都会根据从源传递的值传递最小/最大值。 (但是它不会将值设置回源属性)。
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value",
typeof(double),
typeof(RangeBase),
new FrameworkPropertyMetadata(
0.0d,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault |
FrameworkPropertyMetadataOptions.Journal,
new PropertyChangedCallback(OnValueChanged),
new CoerceValueCallback(ConstrainToRange)),
new ValidateValueCallback(IsValidDoubleValue));
internal static object ConstrainToRange(DependencyObject d, object value)
{
RangeBase ctrl = (RangeBase) d;
double min = ctrl.Minimum;
double v = (double) value;
if (v < min)
{
return min;
}
double max = ctrl.Maximum;
if (v > max)
{
return max;
}
return value;
}
因此,您可以做的是CoerceValueCallback中的SliderValue属性具有相同的逻辑,以便它始终与滑块值同步,但为此您必须从值更改事件中手动强制滑块值。
public static readonly DependencyProperty SliderValueProperty =
DependencyProperty.Register("SliderValue", typeof(double), typeof(MainWindow),
new PropertyMetadata(default(double), null, CoerceSliderValue));
private static object CoerceSliderValue(DependencyObject d, object value)
{
// Of course good idea would be to be have min/max as CLR properies
// in your class and bind slider with those values.
// So, that you can have refer to those values directly here.
double min = ((MainWindow)d).slider.Minimum;
double max = ((MainWindow)d).slider.Maximum;
double passedValue = (double)value;
if (passedValue < min)
{
return min;
}
else if (passedValue > max)
{
return max;
}
return passedValue;
}
private void Slider_OnValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
CoerceValue(SliderValueProperty);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.