繁体   English   中英

在XAML中设置最小值的绑定滑块值

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM