Wpf 什么';s依赖项属性SetValue()和;SetCurrentValue()

Wpf 什么';s依赖项属性SetValue()和;SetCurrentValue(),wpf,dependency-properties,setvalue,setcurrentvalue,Wpf,Dependency Properties,Setvalue,Setcurrentvalue,我之所以问这个问题,是因为@Greg D(from)建议我改为使用SetCurrentValue(),但是看一下文档,没有发现有什么区别。或者“不改变其价值来源”是什么意思 设置依赖项属性的本地值,该值由其 依赖属性标识符 设置依赖项属性的值而不更改其值 来源 您提供的MSDN链接很好地说明了这一点: 此方法由组件使用 以编程方式设置值 属于它自己的一种财产,没有 禁用应用程序声明的 财产的使用。这个 SetCurrentValue方法更改 财产的有效价值,但 现有触发器、数据绑定和 风格将

我之所以问这个问题,是因为@Greg D(from)建议我改为使用
SetCurrentValue()
,但是看一下文档,没有发现有什么区别。或者“不改变其价值来源”是什么意思

设置依赖项属性的本地值,该值由其 依赖属性标识符

设置依赖项属性的值而不更改其值 来源


您提供的MSDN链接很好地说明了这一点:

此方法由组件使用 以编程方式设置值 属于它自己的一种财产,没有 禁用应用程序声明的 财产的使用。这个 SetCurrentValue方法更改 财产的有效价值,但 现有触发器、数据绑定和 风格将继续发挥作用

假设您正在编写
TextBox
控件,并且您公开了人们经常使用的
Text
属性,如下所示:

<TextBox Text="{Binding SomeProperty}"/>

在控件的代码中,如果调用
SetValue
,您将用您提供的任何内容覆盖绑定。但是,如果调用
SetCurrentValue
,将确保属性接受给定的值,但不会破坏任何绑定


就我所知,格雷格的建议是不正确的。您应该始终使用CLR包装器属性中的
GetValue
/
SetValue
<代码>设置当前值在需要属性接受给定值但不想覆盖已针对属性配置的任何绑定、触发器或样式的情况下更有用。

关于接受的答案:

我发现这很好地解释了SetCurrentValue()。请注意,依赖项属性值优先系统将如何将局部值置于绑定值之上。这解释了评论者的意外行为。

演示工具(完整):

class test : DependencyObject
{
    static DependencyProperty XyzProperty =
        DependencyProperty.Register("Xyz", typeof(int), typeof(test), new PropertyMetadata(42));

    public test()
    {
        /* ... see code shown below ... */
    }

    void inf()
    {
        var info = DependencyPropertyHelper.GetValueSource(this, XyzProperty);
        var msg = $@"{"//"
                   } {(int)GetValue(XyzProperty),2
                   } {(ReadLocalValue(XyzProperty) is int x ? "(Object)" + x : "UnsetValue"),12
                   } {info.BaseValueSource,9
                   } {(info.IsCurrent ? "" : "Not") + "Current",12
                   } {(info.IsCoerced ? "" : "Not") + "Coerced",12
                   }";
        Trace.WriteLine(msg);
    }
};
                                      // v̲a̲l̲u̲e̲  s̲t̲o̲r̲e̲d̲-o̲b̲j̲      B̲V̲S̲    C̲u̲r̲r̲e̲n̲t̲?    C̲o̲e̲r̲c̲e̲d̲?
/*1*/                                    // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*2*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced

/*3*/ SetValue(XyzProperty, 42);         // 42  (Object)42    Local  NotCurrent  NotCoerced

/*4*/ ClearValue(XyzProperty);           // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*5*/ SetCurrentValue(XyzProperty, 5);   //  5   (Object)5  Default     Current     Coerced

/*6*/ SetCurrentValue(XyzProperty, 42);  // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*7*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced
      SetCurrentValue(XyzProperty, 42);  // 42  (Object)42    Local     Current     Coerced
讨论示例:

class test : DependencyObject
{
    static DependencyProperty XyzProperty =
        DependencyProperty.Register("Xyz", typeof(int), typeof(test), new PropertyMetadata(42));

    public test()
    {
        /* ... see code shown below ... */
    }

    void inf()
    {
        var info = DependencyPropertyHelper.GetValueSource(this, XyzProperty);
        var msg = $@"{"//"
                   } {(int)GetValue(XyzProperty),2
                   } {(ReadLocalValue(XyzProperty) is int x ? "(Object)" + x : "UnsetValue"),12
                   } {info.BaseValueSource,9
                   } {(info.IsCurrent ? "" : "Not") + "Current",12
                   } {(info.IsCoerced ? "" : "Not") + "Coerced",12
                   }";
        Trace.WriteLine(msg);
    }
};
                                      // v̲a̲l̲u̲e̲  s̲t̲o̲r̲e̲d̲-o̲b̲j̲      B̲V̲S̲    C̲u̲r̲r̲e̲n̲t̲?    C̲o̲e̲r̲c̲e̲d̲?
/*1*/                                    // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*2*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced

/*3*/ SetValue(XyzProperty, 42);         // 42  (Object)42    Local  NotCurrent  NotCoerced

/*4*/ ClearValue(XyzProperty);           // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*5*/ SetCurrentValue(XyzProperty, 5);   //  5   (Object)5  Default     Current     Coerced

/*6*/ SetCurrentValue(XyzProperty, 42);  // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*7*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced
      SetCurrentValue(XyzProperty, 42);  // 42  (Object)42    Local     Current     Coerced
讨论:

class test : DependencyObject
{
    static DependencyProperty XyzProperty =
        DependencyProperty.Register("Xyz", typeof(int), typeof(test), new PropertyMetadata(42));

    public test()
    {
        /* ... see code shown below ... */
    }

    void inf()
    {
        var info = DependencyPropertyHelper.GetValueSource(this, XyzProperty);
        var msg = $@"{"//"
                   } {(int)GetValue(XyzProperty),2
                   } {(ReadLocalValue(XyzProperty) is int x ? "(Object)" + x : "UnsetValue"),12
                   } {info.BaseValueSource,9
                   } {(info.IsCurrent ? "" : "Not") + "Current",12
                   } {(info.IsCoerced ? "" : "Not") + "Coerced",12
                   }";
        Trace.WriteLine(msg);
    }
};
                                      // v̲a̲l̲u̲e̲  s̲t̲o̲r̲e̲d̲-o̲b̲j̲      B̲V̲S̲    C̲u̲r̲r̲e̲n̲t̲?    C̲o̲e̲r̲c̲e̲d̲?
/*1*/                                    // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*2*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced

/*3*/ SetValue(XyzProperty, 42);         // 42  (Object)42    Local  NotCurrent  NotCoerced

/*4*/ ClearValue(XyzProperty);           // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*5*/ SetCurrentValue(XyzProperty, 5);   //  5   (Object)5  Default     Current     Coerced

/*6*/ SetCurrentValue(XyzProperty, 42);  // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*7*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced
      SetCurrentValue(XyzProperty, 42);  // 42  (Object)42    Local     Current     Coerced
  • 缺少的
    dependencProperty
    的初始状态,其
    DefaultValue
    为'42',已断言
    BaseValueSource.Default
    标志
    ReadLocalValue()
    返回全局单例实例
    dependencProperty.UnsetValue

  • SetValue()
    按预期在内部存储
    BaseValueSource.Local

  • 使用
    SetValue
    存储恰好等于
    DefaultValue
    的值不会还原
    BaseValueSource.Default
    状态(与下面的#6比较)

  • 相反,如果要删除任何/所有存储值或绑定并将DP恢复为原始状态,请调用
    ClearValue()
    。(见下文注释)

  • 使用
    SetCurrentValue()
    ,通过强制生成属性值,而不断言
    BaseValueSource.Local
    模式。请注意,以前的
    BaseValueSource
    默认值仍然有效,尽管该属性现在报告的值不是,实际上等于其
    默认值

  • 重要提示:
    这意味着检查
    GetValueSource()
    返回的
    BaseValueSource
    状态是否为
    BaseValueSource。Default
    not当前属性值是否等于DP metatdata的默认值的可靠指示器

  • 另一方面,与上面的第3条不同,
    SetCurrentValue
    检查DP元数据的
    DefaultValue
    是否相等,以便删减被认为是“不必要”的冗余值。这种急切的清理可能是为了缓解DP存储膨胀,但它也会使DP状态的透明度变得复杂,因为它有一种特殊的“取消屏蔽”行为,如果不完全理解,可能会导致模糊的错误。例如,#6将DP清除回与
    ClearValue()
    无法区分的原始状态

  • …但仅当先前存储的
    BaseValueSource
    当前的
    ,而不是
    本地的
    ;将#5/#6与对#7进行比较,尽管报告的属性值相同,但内部状态标志差异很大

  • 关于
    ClearValue()

    class test : DependencyObject
    {
        static DependencyProperty XyzProperty =
            DependencyProperty.Register("Xyz", typeof(int), typeof(test), new PropertyMetadata(42));
    
        public test()
        {
            /* ... see code shown below ... */
        }
    
        void inf()
        {
            var info = DependencyPropertyHelper.GetValueSource(this, XyzProperty);
            var msg = $@"{"//"
                       } {(int)GetValue(XyzProperty),2
                       } {(ReadLocalValue(XyzProperty) is int x ? "(Object)" + x : "UnsetValue"),12
                       } {info.BaseValueSource,9
                       } {(info.IsCurrent ? "" : "Not") + "Current",12
                       } {(info.IsCoerced ? "" : "Not") + "Coerced",12
                       }";
            Trace.WriteLine(msg);
        }
    };
    
                                          // v̲a̲l̲u̲e̲  s̲t̲o̲r̲e̲d̲-o̲b̲j̲      B̲V̲S̲    C̲u̲r̲r̲e̲n̲t̲?    C̲o̲e̲r̲c̲e̲d̲?
    /*1*/                                    // 42  UnsetValue  Default  NotCurrent  NotCoerced
    
    /*2*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced
    
    /*3*/ SetValue(XyzProperty, 42);         // 42  (Object)42    Local  NotCurrent  NotCoerced
    
    /*4*/ ClearValue(XyzProperty);           // 42  UnsetValue  Default  NotCurrent  NotCoerced
    
    /*5*/ SetCurrentValue(XyzProperty, 5);   //  5   (Object)5  Default     Current     Coerced
    
    /*6*/ SetCurrentValue(XyzProperty, 42);  // 42  UnsetValue  Default  NotCurrent  NotCoerced
    
    /*7*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced
          SetCurrentValue(XyzProperty, 42);  // 42  (Object)42    Local     Current     Coerced
    
    很明显,任何
    SetValue()
    操作都不会调用
    PropertyChangedCallback
    ,因为该操作最终不会导致对属性的上一个值的更改。这是最基本的,因为
    SetValue
    隐含了一个假设,即正在进行的更改与工作中的活动属性的值有关。不那么直观的是,同样的逻辑也适用于
    ClearValue()


    例如,在#4中,
    ClearValue
    导致本地值
    42
    从内部DP存储中删除,以及其他内部状态更改,所有这些都是预期的。问题在于,在当前的
    ClearValue
    调用过程中,是否调用
    OnPropertyChanged
    取决于之前的值是否等于元数据默认值操作似乎意味着对先前状态的摘要丢弃(因此通常被认为是上下文任意的)
    ClearValue()
    的行为依赖于某些/任何先前状态时,人们可能不会想到这种不一致性。特别是对于一个涉及(并混合)新州的重大行为,例如是否发出“变更”通知。

    @Meleak:老实说,我认为这篇文章有点不清楚。我想他是想说
    SetCurrentValue
    应该用在你控制的任何地方