SetCurrentValue在某些非常特定的条件下清除依赖属性

时间:2014-05-14 11:00:07

标签: c# wpf .net-4.5 dependency-properties

TL; DR: SetCurrentValue取消设置依赖项属性,如果:

  1. 传递与当前值相同的值
  2. 通过覆盖属性的元数据来提供CoerceValueCallback。
  3. 此强制回调不会更改值
  4. 依赖项属性没有绑定。

  5. 我今天遇到这个问题需要一段时间来修复,但我仍然不明白为什么会发生这种情况,所以我认为这里可能值得一提。我目前认为这是WPF框架中的一个错误。

    我有一个控件MyTextBox,它继承自WPF TextBox。它具有以下文本属性的元数据覆盖:

    static MyTextBox()
    {
        TextProperty.OverrideMetadata(typeof(MyTextBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, null, CoerceText, true, UpdateSourceTrigger.Explicit));
    }
    

    CoerceText方法存在,但不会更改基值:

    private static object CoerceText(DependencyObject d, object basevalue)
    {
        return basevalue;
    }
    

    Text属性没有约束(如果有的话,事情会有效!)

    现在假设我执行以下操作:

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        base.OnPreviewKeyDown(e);
    
        if (e.Key == Key.Enter)
        {
            var newText = Text;
            SetCurrentValue(TextProperty, newText);
        }
    }
    

    如果我调试此代码,this.Text在调用""后变为SetCurrentValue(空字符串)。但是,它应该保持不变。

    我最后通过调试SetCurrentValue方法(实际上并不是真正的可调试方法......)。

    该特定测试失败,来自UpdateEffectiveValue的{​​{1}},导致无法取消DP的值。为了自己的理智,我没有再进一步了。

    DependencyObject.cs

    最后,正如我所说,我修复了问题,解决方法是在重写的元数据中删除我自己的Coerce回调:

    if (newEntry.FullValueSource != (FullValueSource) BaseValueSourceInternal.Default)
    {
        ...
    }
    else
    {
        UnsetEffectiveValue(entryIndex, dp, metadata);
    }
    

    我没有理由解释为什么删除static MyTextBox() { TextProperty.OverrideMetadata(typeof(MyTextBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, null, null, true, UpdateSourceTrigger.Explicit)); } CoerceValueCallback按预期工作并保持依赖属性不变而不是清除它。

    所以我的问题是,是否有一个明智的解释为什么在这些特定条件下会发生这种行为?

0 个答案:

没有答案