存档

帖子标记'依赖项属性'

的DependencyProperty:审定,胁迫及变化处理(第二部分:Silverlight中)

11月11日,2008年 5个评论

介绍

这是就如何落实与验证,胁迫和变化通知WPF和Silverlight依赖项属性的三部分系列的第二部分。 这篇文章的重点在Silverlight。 因为Silverlight属性系统支持只PropertyChangedCallback ,开发人员必须实现类似WPF CoerceValueCallbackValidateValueCallback使用PropertyChangedCallback和局部变量。 这可能会变得非常棘手,因为它会被Silverlight中的错误显示RangeBase后系列的第三部分控制。 它是建议你读DependencyProeprty:审定,胁迫及变化处理(第一部分:WPF)中得到一些背景:WPF属性系统的工作原理,实施WPF依赖属性的模式,简单的例子,我们将重新概述使用Silverlight实现,在这个岗位。

Silverlight的依赖项属性概述

MSDN有一个很好的用于 Silverlight的依赖项属性概述 ,它是一个必须阅读,任何人要落实在Silverlight的依赖属性。 在这里,我只是召唤出三个核心类的Silverlight属性系统编程接口和两个重要的方法,正如我在第一部分为WPF:

  • DependencyProperty的 :Silverlight的DependencyProperty的是比WPF的小。 暴露其公共接口没有属性,只有注册RegisterAttached静态方法,没有超载。
      公共类的DependencyProperty 
    {
    / /字段
    公共静态只读对象 UnsetValue的;

    / /方法
    公共 PropertyMetadata可用getMetaData(类型forType);
    name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata); 公共静态的DependencyProperty注册( 字符串名称,类型propertyType,键入ownerType,PropertyMetadata typeMetadata);
    name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata); 公共静态的DependencyProperty RegisterAttached( 字符串名称,的类型propertyType,类型ownerType,defaultMetadata PropertyMetadata);
    }

  • PropertyMetadata :它的公共接口暴露任何属性,默认值,PropertyChangedCallback,但不CoerceValueCallback只有建设者
     公共类 PropertyMetadata 
    {
    / /方法
    defaultValue); 公共 PropertyMetadata( 对象的DefaultValue);
    公共 PropertyMetadata(propertyChangedCallback PropertyChangedCallback);
    defaultValue, PropertyChangedCallback propertyChangedCallback); 公共 PropertyMetadata( 对象的DefaultValue,PropertyChangedCallback propertyChangedCallback);

    / /属性
    公共对象的DefaultValue {获取;}
    }

  • DependencyObject的 :它的公共接口的GetValueSetValue的ReadLocalValueClearValue方法,但不CoerceValue的方法。
     DependencyObject的公共抽象类 :IManagedPeer,INativeCoreTypeWrapper 
    {
    / /方法
    保护 DependencyObject的();
    [(EditorBrowsableState.Never)EditorBrowsable]
    公共布尔 CheckAccess中();
    公共无效 ClearValue(DependencyProperty的DP);
    公共,对象 GetAnimationBaseValue(DependencyProperty的DP);
    公共对象的GetValue(DependencyProperty的DP);
    公共,对象 ReadLocalValue(DependencyProperty的DP);
    ); 公共无效的SetValue(DependencyProperty的DP, 对象的值 );

    / /属性
    [(EditorBrowsableState.Advanced)EditorBrowsable]
    公共分派分派{获取;}
    }

  • DependencyProperty.Register的方法:请注意,它并没有采取ValidateValueCallback参数。

    DependencyProperty.Register

  • PropertyMetadata构造方法:请注意,它并没有采取CoerceValueCallback参数。

    PropertyMetadata.PropertyMetadata

例子

概观

这是第一部分相同的例子,但在Si​​lverlight上重新实现。 它有一个简单的类MyButton的继承按钮,并增加了一个依赖项属性MyValue。 MyValue属性的值必须是0和10之间,其有效价值是由它的IsEnabled从基类继承的财产的影响:如果IsEnabled的是真实的,的MyValue必须小于或等于5,O / W,它必须大于或等于6。

MyValue既然是一个依赖项属性,它应该有一个依赖项属性的所有的好处:

  • 它具有简单的CLR属性界面;
  • 它有一个默认值;
  • 其值可以通过XAML代码,数据绑定,样式,动画等设置;
  • 它的价值是动态决定它的依赖,并可以自动重新计算时,它的依赖性改变;
  • 它通常有一个客户端的值改变事件和价值改变保护的虚方法,子类重写插件;
  • MyValue设置一个非法的值应该抛出一个ArgumentException,不改变MyValue财产的价值或射击它的值改变事件;

实施模式

MyValue在执行下面的源代码如下Silverlight相依性属​​性的常见模式和实现/提供上面提到的依赖项属性的全部好处。 因为Silverlight属性系统只支持WPF属性系统功能的一个子集,特别是它不仅改变了回调,但不支持直接验证和胁迫,对Silverlight的依赖属性的实现模式,实际上是非常棘手的,这是很容易有细微的错误,如果不小心,调试/节稍后尝试在这个岗位所示。

  • ; set ; } CLR包装:{ 公众诠释 MyValue 获得 ; 设置 ;}
  • 依赖属性标识符: 公共静态只读的DependencyProperty MyValueProperty
  • 产权制度登记:DependencyProperty.Register的()
  • PropertyChangedCallback是所有的DP功能(验证,胁迫事件)的关键功能:
    • 私人静态无效 OnMyValuePropertyChanged的(DependencyObject的D,DependencyPropertyChangedEventArgs E):PropertyChangedCallback功能
    • 私人诠释 _initialMyValu

      E:地方国有记得MyValue财产的PropertyChangedCallback根水平在以前的值,以避免不必要的/假的变化notfication

    • 私人INT _requestedMyValue的:地方国有记得原来的用户要求设置值胁迫基地
    • 递归调用PropertyChangedCallback,从可见光到客户端验证和强制执行,并防止内部转换,不发射假的更改通知, 私人INT _nestLevel的水平
  • 验证逻辑:
    • 私人静态,BOOL IsValidMyValue(DependencyPropertyChangedEventArgsé):比赛WPF的ValicateValueCallback
    • 私有静态无效 ValidationHelper恢复无效的变化和扔在验证失败情况下的例外:一个共同的事业
  • 强制的逻辑:
    • ): match WPF's CoerceValueCallback 私有静态对象 CoerceMyValue(DependencyObject的D, 对象的值 ):比赛WPF的CoerceValueCallback
    • sender, DependencyPropertyChangedEventArgs e): to trigger automatic re-calculation of the effective value of MyValue property when its dependency IsEnabled changes. 私有静态无效 OnIsEnabledChanged( 对象发件人,DependencyPropertyChangedEventArgs五):触发自动MyValue财产的有效价值重新计算时,其依赖IsEnabled的变化。
  • 事件
    • > MyValueChanged; 公共事件 RoutedPropertyChangedEventHandler <> MyValueChanged;
    • oldValue, int newValue) (oldValue,int newValue)在保护虚拟无效 OnMyValueChanged
    • 私有静态无效 OnMyValuePropertyChanged(DependencyObject的D,DependencyPropertyChangedEventArgs E),CoerceMyValue静态方法

    您可能需要通读源代码的调试和实验下文,了解如何在Silverlight相依性属​​性的正确实施的复杂和微妙,因为它是很容易在这里犯了一个错误,因为在Silverlight中的错误证明。

源代码

  • Page.xaml中:

  • page.xaml.cs:
     System.Windows; using System.Windows.Controls; namespace SLApp1 { // exampl to demonstrate how to implement dependency property on Silverlight public class MyButton : Button { // DP: CLR wrapper public int MyValue { get { return ( int )GetValue(MyValueProperty); } set { SetValue(MyValueProperty, value ); } } // DP: dependency property identifier & registration public static readonly DependencyProperty MyValueProperty = 使用系统; 使用 System.Windows; 使用 System.Windows.Controls的命名空间 SLApp1 {/ /为例来说明如何实现对Silverlight的 公共类 MyButton的依赖项属性 :按钮{/ / DP:CLR包装 MyValue {{ 返回INT)的GetValue(MyValueProperty);} {的SetValue(MyValueProperty,  );}} / / DP:依赖属性标识符登记 公共静态只读的DependencyProperty MyValueProperty =  IsValidMyValue(DependencyPropertyChangedEventArgs e) { int newValue = ( int )e.NewValue; return newValue >= 0 && newValue <= 10; } // DP: coercion callback private static object CoerceMyValue(DependencyObject d, object value ) { MyButton ctrl = (MyButton)d; int newValue = ( int ) value ; return ctrl.IsEnabled ? DP:验证回调 私有静态布尔 IsValidMyValue(DependencyPropertyChangedEventArgs E){newValue =(INT)e.NewValue;回报 newValue> = 0 && newValue <= 10;} / / DP的强制回调 私有静态对象 CoerceMyValue(D,DependencyObject的对象 ctrl.IsEnabled  ){MyButton的CTRL =(MyButton的)D; newValue =(int) ; 回报 ValidationHelper( DependencyObject d, DependencyPropertyChangedEventArgs e, Predicate<DependencyPropertyChangedEventArgs> p) { if (!p(e)) { // Isolate SetValue call with _netLevel to prevent state change ((MyButton)d)._nestLevel++; d.SetValue(e.Property, e.OldValue); ((MyButton)d)._nestLevel--; throw new ArgumentException( "Invalid DP value" , "e" ); } } // DP: changed callback private static void OnMyValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // validation first: in case of failure, revert change, // throw ArgumentException, no state change or changed notification ValidationHelper(d, e, IsValidMyValue); MyButton ctrl = (MyButton)d; int oldValue = ( int )e.OldValue; int newValue = ( int )e.NewValue; if (ctrl._nestLevel == 0) { // remember initial state ctrl._initialMyValue = oldValue; ctrl._requestedMyValue = newValue; } ctrl._nestLevel++; // coercion, DP stores effective value on SL int coercedValue = ( int )CoerceMyValue(d, e.NewValue); if (newValue != coercedValue) ctrl.MyValue = coercedValue; ctrl._nestLevel--; if (ctrl._nestLevel == 0 && ctrl.MyValue != ctrl._initialMyValue) { // changed notification happens only at root level (_nestLevel == 1) // and when there is a really a change (MyValue != _initialMyValue) ctrl.OnMyValueChanged(oldValue, ctrl.MyValue); } } // RE: use direct event to simulate routed event public event RoutedPropertyChangedEventHandler< int > MyValueChanged; // RE: provide a protected virtual for subclass to override protected virtual void OnMyValueChanged( int oldValue, int newValue) { RoutedPropertyChangedEventArgs< int > e = new RoutedPropertyChangedEventArgs< int >(oldValue, newValue); if (MyValueChanged != null ) MyValueChanged( this , e); } private int _initialMyValue; private int _requestedMyValue; private int _nestLevel; // DP: event handler to trigger re-calculation of DP because of dependency change private static void OnIsEnabledChanged( object sender, DependencyPropertyChangedEventArgs e) { MyButton ctrl = (MyButton)sender; // coerce local value to re-calculate effective value // set DP only when effective value changes to avoid blow away binding unnecessarily ctrl._nestLevel++; int oldValue = ctrl.MyValue; int newValue = ( int )CoerceMyValue(ctrl, ctrl._requestedMyValue); if (newValue != ctrl.MyValue) { ctrl.MyValue = newValue; ctrl.OnMyValueChanged(oldValue, ctrl.MyValue); } ctrl._nestLevel--; } public MyButton() { _initialMyValue = _requestedMyValue = MyValue; // init state IsEnabledChanged += OnIsEnabledChanged; // hook up dependency } } public partial class Page : UserControl { public Page() { InitializeComponent(); } private void mybtn_Click( object sender, RoutedEventArgs e) { } private void mybtn_MyValueChanged( object sender, RoutedPropertyChangedEventArgs< int > e) { int oldValue = e.OldValue; int newValue = e.NewValue; } } }的Math.Min(5,newValue)以Math.Max(newValue)以6;} / / DP:普通验证助手/ /恢复值,并在验证失败的 私有静态的无效 ValidationHelper(DependencyObject的D,DependencyPropertyChangedEventArgsé,谓词的情况下抛出异常 <DependencyPropertyChangedEventArgs> P){){/ /隔离与_netLevel的SetValue的调用,以防止状态的变化 ((MyButton的)ð)_nestLevel的+(P(E); d.SetValue(e.Property,e.OldValue)(( MyButton的)D)_nestLevel - ; 抛出新 ArgumentException(“无效的DP值”,“E”);}} / / DP的:改变回调 私有静态无效 OnMyValuePropertyChanged(DependencyObject的D,DependencyPropertyChangedEventArgs E){/ /验证:失败的情况下,恢复变化,/ /抛出ArgumentException,没有国家的变化,或改变 ValidationHelper 通知 (D,E,IsValidMyValue); MyButton的CTRL =(MyButton的)D; oldValue =(INT)e.OldValue; newValue =(INT ()e.NewValue; ctrl._nestLevel == 0){/ /记住初始状态 ctrl._initialMyValue oldValue; ctrl._requestedMyValue = newValue;} ctrl._nestLevel + +; / /胁迫,DP的商店有效的SL INT coercedValue  = (INT)CoerceMyValue(D,e.NewValue);如果 (newValue = coercedValue!)ctrl.MyValue = coercedValue; ctrl._nestLevel - 如果 (== 0 &&!ctrl._nestLevel ctrl.MyValue = ctrl._initialMyValue){ / /改变通知只发生在根级别(_nestLevel == 1)/ /时,有一个真正的变化(MyValue = _initialMyValue!)(oldValue,ctrl.MyValue),ctrl.OnMyValueChanged;}} / / Re:使用直接事件模拟路由事件 公共事件 RoutedPropertyChangedEventHandler的< 诠释 > MyValueChanged的; / /重新提供受保护的虚拟子类覆盖 保护虚拟无效OnMyValueChanged(oldValue,newValue)以{RoutedPropertyChangedEventArgs < 整数 >电子=  RoutedPropertyChangedEventArgs < 整数 >(oldValue newValue)以(MyValueChanged = NULL)MyValueChanged(E);} INT _initialMyValue; 私人诠释 _requestedMyValue; 私人诠释 _nestLevel; / / DP的:事件处理程序触发DP重新计算,因为依赖变化 私有静态丧失 OnIsEnabledChanged( 对象发件人,DependencyPropertyChangedEventArgsé){MyButton的CTRL =(MyButton的)发件人/ /强制本地值重新计算有效的值/ /设置DP只有当有效的价值变动,以避免吹走结合不必要 ctrl._nestLevel +; oldValue 如果 (newValue = ctrl.MyValue!){ctrl.MyValue = newValue; ctrl.OnMyValueChanged的(oldValue ctrl.MyValue)的;} CTRL = ctrl.MyValue; newValue =(INT)CoerceMyValue“(CTRL ctrl._requestedMyValue)的。 _nestLevel - ;} 公共 MyButton的(){_initialMyValue = _requestedMyValue = MyValue; / /初始化状态 IsEnabledChanged + = OnIsEnabledChanged的; 高达依赖钩/ /}} 公共部分的类页:UserControl的公共页面(){();} 私人,无效 mybtn_Click( 对象发件人,RoutedEventArgs E){} 私人无效 mybtn_MyValueChanged的( 对象发件人,RoutedPropertyChangedEventArgs < 整数 > E){INT的 oldValue e.OldValue; 诠释 newValue = e.NewValue;}} 

调试和试验:如何在Silverlight的依赖属性工作

正如在第一部分,我将演示如何依赖项属性的Silverlight调试和试验工作。 我在最上面的源代码中的功能设置断点,从Visual Studio内启动的应用程序,点击按钮打入mybtn_Click功能,然后检查状态和Visual Studio的即时窗口内做实验。

默认值作为有效值

首先,让我们检查后到mybtn_Click功能SLApp1休息状态mybtn:

default value as effective value

  • mybtn.MyValue和mybtn.GetValue都返回0,MyValue DP(DP =的DependencyProperty)的默认值。
  • mybtn.ReadLocalValue(MyButton.MyValueProperty)返回DependencyObject.UnsetValue,为此DP在mybtn没有本地值。 因此,它是Silverlight返回DP的默认值,作为其有效价值的产权制度。
  • mybtn.ClearVa​​lue(MyButton.MyValueProperty)没有任何效果,因为没有本地值清除。
  • MyButton的构造,状态变量(_initialMyValue,_requestedMyValue)都被初始化为的MyValue有效价值。

验证

现在,让我们与验证实验。 类型mybtn.MyValue = -1在即​​时窗口:

validation

  • VS分成OnMyValuePropertyChanged PropertyChangedCallback静态方法,因为改变的回调是所有的Silverlight属性系统支持。
  • 输出mybtn,mybtn.MyValue,mybtn.GetValue(MyButton.MyValueProperty)表明MyValue已经采取了非法的值-1作为其本地和有效的价值,所以它是一个无效的状态。
  • 本地窗口显示e.Property有型CustomDependencyProperty的。 有许多微妙之间CoreDependencyProperty和CustomDependencyProperty的Silverlight的差异,所以可能不是真正的Silverlight有关WPF DependencyProperty的许多假设。 准备尝试和错误。
  • 来模拟的WPF行为,OnMyValuePropertyChanged的调用ValidationHelper验证e.NewValue,并恢复在验证失败情况下的变化,而不会引发不必要的变更通知为非法的新值-1。

validation

  • 在调用堆栈窗口和源代码窗口上面看:ValidationHelper的呼吁IsValidMyValue,这将返回-1 e.NewValue的虚假。

validate & revert

  • ,因为IsValidMyValue(通过参数p)返回false,如上图所示,ValidationHelper恢复DP值设置到e.OldValue变化。 不幸的是,这SetValue的调用将引发一轮又一轮,甚至两轮改变处理(验证/强制/更改通知),递归,即使它仍然是改变当前DP值的中间处理,只是恢复的变化,不应该有发生的开始。 这个递归是所有的复杂性,在Silverlight相依性属性的正确实施
  • 的SetValue的呼叫包围/保护一双_nestLevell + + / _nestLevell的语句,所以当OnMyValuePropertyChanged被称为再​​次递归,_nestLevel将超过1,所以它知道它是在递归,和会不会引发更改通知:在这种情况下,从0到-1和-1到0,因为这些变化将发生在WPF中,应该仅在内部到客户端听的MyValueChanged事件和不可见的。
  • 下面的屏幕截图显示OnMyValidationPropertyChanged递归调用,同时通过加强在上面的屏幕截图上线49条的SetValue调用:

validate, revert & recursion

  • 以上在屏幕上打出,OnMyValuePropertyChanged显示了两次调用堆栈窗口中,我们仍然是内部MyValue.set(-1)调用(和“评价:mybtn.MyValue = -1”从即时窗口)。
  • 在即时窗口中的输出显示MyValue财产的价值,现在恢复从-1回0。
  • ((MyButton的)D)。GetValue的输出(MyButton.MyValueProperty)的DependencyProperty.UnsetValue 0,而是表明mybtn现在有此DP为本地值,而不是采取从DP登记的默认值。
  • _nestLevel是1而不是0,因为OnMyValidationPropertyChanged被称为递归。
  • 在当地人的窗口,我们可以看到,E的NewValue和OldValue交换。 e.NewValue现在是0和有效,所以ValidationHelper不会触发另一轮的变化处理。
  • 因为_nestLevel了价值1,所以将不会被执行,如果从68至72条,即,递归将不会改变地方国有(_initialMyValue和_requestedMyValue)。

validate, revert & recursion

  • 如上图所示,将继续执行强制上线76。 由于mybtn.IsEnabled是真实的,newValue是0,所以没有胁迫的情况,被跳过78行,而不是因胁迫而造成另一种递归一轮。
  • 1 _netstLevel将是81行,和ctrl.MyValue等于ctrl._initialMyValue,所以如果从82行更改的通知,以86条将被跳过太多。 OnMyValuePropertyChanged将返回,调用堆栈回溯到ValidationHelper呼叫,如下所示。

exception for validation failure

  • 回到ValidationHelper,恢复旧值后,ValidationHelper抛出ArgumentExeption为无效的新的价值,这一切都没有改变状态(_initialMyValue和_requestedMyValue)或触发更改通知(在这种情况下,从0到-1,然后-1回0)。

强迫

现在让我们用强制的实验:mybtn.MyValue设置8应该触发胁迫,mybtn.MyValue应该结束,而不是8 5,因为IsEnabled的是真实的,并应与新的价值5发射MyValueChanged事件。 自8是一个有效的值,它应该记住;时依赖IsEnabled的变化,MyValue的有效价值的重新的计算应该发生,并应改变MyValue的有效价值的最初requeste和现在有效的值8,和MyValueChanged事件应与发射新的价值8。

如下图所示,立即窗口mybtn.MyValue = 8触发OnMyValuePropertyChanged静态方法,如= -1以前在的mybtn.MyValue的情况,但有一些不同:

coercion

  • 在上面的屏幕截图,8 e.NewValue由IsValidMyValue验证,因此没有SetValue的调用和递归改变处理内部ValidationHelper。
  • 因为这是改变处理的根通话(_nestLevel走进OnMyValuePropertyChanged值0),如果从68至72条执行,要记住的状态,因为在即时窗口CTRL输出显示。
  • 继续执行排队胁迫76。

coercion causes recursive changed handling

  • 在上面的屏幕截图,CoerceMyValue回报5,有效的价值,因为IsEnabled的是真实的和要求的新的价值是8。
  • MyValue实际值5,将触发OnMyValuePropertyChanged,IsValidMyValue的OnMyValuePropertyChanged套,CoerceMyValue等被称为递归再次值为5。 自5是有效的,已经裹挟,将继续坚持。

change notification

  • 如上图所示,从强制执行回来,mybtn(CTRL),作为其有效和地方MyValue的DP值5,但还记得请求的值8 _requestedMyValue领域。
  • 只发生在通话的根级别(_nestLevel == 0)更改的通知时,确实是有一个有效的DP值的变化(MyValue!= _initialValue)。
  • MyValueChanged事件总是触发新的有效的值(ctrl.MyValue,coercedValue,ctrl.ReadLocalValue()都应该是有效的新值)。
  • 下面的屏幕截图显示了事件处理调用堆栈:

changed event firing & handling

动态重新计算的依赖性变动的有效价值

现在让我们用一个依赖项属性值的依赖性变动时有效的动态/自动重新计算实验。

在即时窗口的类型mybtn.IsEnabled =假:

dynamic/automatic effective value

  • IsEnabled的变化是异步处理 ,即改变IsEnabled的,不会导致其处理程序OnIsEnabledChanged立即调用。 你必须立即按F5,到让SLApp1运行,因此它可以拿起IsEnabledChanged事件,并打入OnIsEnabledChanged。 如果等待几秒钟,然后按F5,IsEnabled的更改事件将永远失去了,OnIsEnabledChanged将不会被调用 尽管事件处理是异步的,可能会丢失,变化的影响是同步的,棒:现在被禁用按钮。 所以,如果你没有足够快击中F5键后,输入在mybtn.IsEnabled =假的,你将能够继续进行实验,因为现在被禁用按钮不会回应点击,所以你将不得不重新启动程序继续进行实验。 短调用堆栈的asynchronousness还显示,自“mybtn.IsEnabled =假”立即返回,并打印出“即时”窗口中的虚假,不包含调用堆栈像行“的评价:mybtn.IsEnabled =假”,在“评价:mybtn.MyValue = 8”在以前的实验和瞬态事件处理异步的情况下,可能是一个很好的性能和可靠性改进,但它也使事情变得非常棘手的,所以不要牢记异步性质!
  • 产权制度不知道的依赖关系取决于一个DP上,因此开发人员提供的逻辑,就像处理IsEnabledChanged事件触发的例子在这里MyValue重新计算。
  • 请注意,我们强迫缓存_requestedMyValue,不ctrl.MyValue,现行有效的价值。 有效的价值不应该是强迫的基础,依赖变化可能不再有效。
  • 被包围内OnIsEnabledChanged的代码/一双_nestLevel + / _nestLevel的陈述与保护,以防止代码和其递归,从不断变化的状态(_initialMyValue _requestedMyValue)。 副作用是没有MyValueChanged的事件,将被解雇,所以OnIsEnabledChanged已明确触发事件时,确实是有实际价值的变化。

做最后的实验是在即时窗口中调用mybtn.ClearVa​​lue(MyButton.MyValidProperty),这将引发新值0 OnMyValuePropertyChanged称为,现在作为新的有效的值的默认值,自8本地值被清除:

ClearValue causes re-calculation of effective value and change notification

新的有效值为0将被迫通过递归调用的OnMyValuePropertyChanged(OnMyValuePropertyChanged显示在调用堆栈窗口下方两次)6,因为IsEnabled的仍是虚假的。 最终mybtn.MyValue将落户6有效和地方的价值,并发射新的价值6 MyValueChanged事件。

Coersion and final change notification

结论

,因为Silverlight只支持PropertyValueChangedCallback,验证和强制执行的Silverlight可以非常棘手,因为验证和强制逻辑只能通过PropertyValueChangedCallback的实施,如果验证或强制改变有效的DP值,PropertyValueChangedCallback可以递归调用,这大大复杂的逻辑。 加Silverlight的不记得原先要求的DP值后强制,不允许DP是处于无效状态,所以有很多地方在执行上的Silverlight依赖项属性的错误。

这是另一个长的职位。 如果有足够的兴趣,我可以考虑提供一个代码片段和一些辅助类来贯彻执行的Silverlight相依性属​​性,以尽量减少WPF和Silverlight产权制度之间的差异,使SL简单,只要实施的DP基本水暖在WPF。

Technorati的标签: