为什么我的数据绑定看到真正的价值,而不是强制的价值? [英] Why does my data binding see the real value instead of the coerced value?

查看:161
本文介绍了为什么我的数据绑定看到真正的价值,而不是强制的价值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写一个真正的的NumericUpDown /微调控制作为一个练习来学习自定义控件创作。我已经得到了大多数我在寻找,包括适当的强制行为。 。我的一个测试揭示了一个缺陷,但是

I'm writing a real NumericUpDown/Spinner control as an exercise to learn custom control authoring. I've got most of the behavior that I'm looking for, including appropriate coercion. One of my tests has revealed a flaw, however.

我的控制有3个依赖属性: MaximumValue MinimumValue 。我用强制手段确保保持最小值和最大值(含)之间。例如:

My control has 3 dependency properties: Value, MaximumValue, and MinimumValue. I use coercion to ensure that Value remains between the min and max, inclusive. E.g.:

// In NumericUpDown.cs

public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown), 
    new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, HandleValueChanged, HandleCoerceValue));

[Localizability(LocalizationCategory.Text)]
public int Value
{
    get { return (int)this.GetValue(ValueProperty); }
    set { this.SetCurrentValue(ValueProperty, value); }
}

private static object HandleCoerceValue(DependencyObject d, object baseValue)
{
    NumericUpDown o = (NumericUpDown)d;
    var v = (int)baseValue;

    if (v < o.MinimumValue) v = o.MinimumValue;
    if (v > o.MaximumValue) v = o.MaximumValue;

    return v;
}



我的测试只是为了确保数据绑定的工作方式我怎么期待。我创建了一个默认的WPF Windows应用程序,并在下面的XAML扔:

My test is just to ensure that data binding works how I expect. I created a default wpf windows application and threw in the following xaml:

<Window x:Class="WpfApplication.MainWindow" x:Name="This"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:nud="clr-namespace:WpfCustomControlLibrary;assembly=WpfCustomControlLibrary"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <nud:NumericUpDown Value="{Binding ElementName=This, Path=NumberValue}"/>
        <TextBox Grid.Row="1" Text="{Binding ElementName=This, Path=NumberValue, Mode=OneWay}" />
    </Grid>
</Window>

通过非常简单的代码隐藏:

with very simple codebehind:

public partial class MainWindow : Window
{
    public int NumberValue
    {
        get { return (int)GetValue(NumberValueProperty); }
        set { SetCurrentValue(NumberValueProperty, value); }
    }

    // Using a DependencyProperty as the backing store for NumberValue.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty NumberValueProperty =
        DependencyProperty.Register("NumberValue", typeof(int), typeof(MainWindow), new UIPropertyMetadata(0));     

    public MainWindow()
    {
        InitializeComponent();
    }
}



(我省略了控件的介绍XAML )

(I'm omitting the xaml for the control's presentation)

现在,如果我跑这我看到从的NumericUpDown 适当地在文本框中反映了价值,但如果我输入一个值是出了超出范围值的获取显示在测试文本,而的NumericUpDown 显示正确的数值范围。

Now if I run this I see the value from the NumericUpDown reflected appropriately in the textbox, but if I type in a value that's out of range the out of range value gets displayed in the test textbox while the NumericUpDown shows the correct value.

这是怎么裹挟值都应该采取行动?这是很好的,它在用户界面中的胁迫,但我预计裹挟值通过数据绑定到运行良好。

Is this how coerced values are supposed to act? It's good that it's coerced in the ui, but I expected the coerced value to run through the databinding as well.

推荐答案

哇,这是令人惊讶的。当您在一个依赖属性设置一个值,绑定表达式的值强制执行之前更新!

Wow, that is surprising. When you set a value on a dependency property, binding expressions are updated before value coercion runs!

如果您在反射器看DependencyObject.SetValueCommon,你可以看到通话,通过该方法半路Expression.SetValue。到UpdateEffectiveValue的调用将调用您的CoerceValueCallback是在最后,结合已经更新了。

If you look at DependencyObject.SetValueCommon in Reflector, you can see the call to Expression.SetValue halfway through the method. The call to UpdateEffectiveValue that will invoke your CoerceValueCallback is at the very end, after the binding has already been updated.

您可以看到这个框架类为好。从一个新的WPF应用程序,添加以下XAML:

You can see this on framework classes as well. From a new WPF application, add the following XAML:

<StackPanel>
    <Slider Name="Slider" Minimum="10" Maximum="20" Value="{Binding Value, 
        RelativeSource={RelativeSource AncestorType=Window}}"/>
    <Button Click="SetInvalid_Click">Set Invalid</Button>
</StackPanel>

和下面的代码:

private void SetInvalid_Click(object sender, RoutedEventArgs e)
{
    var before = this.Value;
    var sliderBefore = Slider.Value;
    Slider.Value = -1;
    var after = this.Value;
    var sliderAfter = Slider.Value;
    MessageBox.Show(string.Format("Value changed from {0} to {1}; " + 
        "Slider changed from {2} to {3}", 
        before, after, sliderBefore, sliderAfter));
}

public int Value { get; set; }

如果您拖动滑块,然后按一下按钮,你会得到像值的消息从11到-1变化;滑块改变了从11到10。

If you drag the Slider and then click the button, you'll get a message like "Value changed from 11 to -1; Slider changed from 11 to 10".

这篇关于为什么我的数据绑定看到真正的价值,而不是强制的价值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆