翼度科技»论坛 编程开发 .net 查看内容

WPF学习笔记07-简析依赖属性

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
接下来我们对依赖属性进行一个简单的剖析,从以下几个方面入手吧。
1 - 为什么是public static

首先说下为什么是public
答:WPF有一种特殊属性,叫附加属性,需要直接访问xxxxProperty的方法才能实现,所以xxxxProperty是public 的。
其次为什么是静态static
答:和依赖属性的实现有关,也就是说,一个类,不管同一个依赖属性有多少个实例,均对应同一个DependencyProperty 。比如你创建100个Control ,每个Control 都有一个FontSize属性,但这100个FontSize均对应同一个FontSizeProperty实例
2 - DependencyProperty具体什么时候用?

比如你创建用户控件,然后呢,你需要传递到其中一些值,你怎么去处理,按照传统的方式你阔以去试试看看能否完成!所以这时候就提现出来了依赖属性的重要性
平常使用WPF已经封装好的那些的话更多时候是你拿来直接用的。
3 - DependencyProperty实现原理是什么?

实现原理的话要是解释的话很复杂。不如直接贴上源代码,自己分析去吧,哈哈
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. <p>using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Threading;
  9. using System.Globalization;
  10. using System.ComponentModel;
  11. using System.Windows.Markup;// For ValueSerializerAttribute
  12. using System.Windows.Threading; // For DispatcherObject
  13. using MS.Utility;
  14. using MS.Internal.WindowsBase;
  15. using System.Reflection;   // for IsInstanceOfType
  16. using MS.Internal;</p>
  17. <h1 id="pragma-warning-disable-1634-1691---suppressing-presharp-warnings">pragma warning disable 1634, 1691  // suppressing PreSharp warnings</h1>
  18. <p>namespace System.Windows
  19. {
  20. /// <summary>
  21. ///     An attached dependency-based property
  22. /// </summary>
  23. [TypeConverter("System.Windows.Markup.DependencyPropertyConverter, PresentationFramework, Version=" + BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")]
  24. [ValueSerializer(typeof(DependencyPropertyValueSerializer))]
  25. public sealed class DependencyProperty
  26. {
  27. /// <summary>
  28. ///     Register a Dependency Property
  29. /// </summary>
  30. /// <param name="name">Name of property</param>
  31. /// <param name="propertyType">Type of the property</param>
  32. /// <param name="ownerType">Type that is registering the property</param>
  33. /// <returns>Dependency Property</returns>
  34. public static DependencyProperty Register(string name, Type propertyType, Type ownerType)
  35. {
  36. // Forwarding
  37. return Register(name, propertyType, ownerType, null, null);
  38. }</p>
  39. [code]    /// <summary>
  40.     ///     Register a Dependency Property
  41.     /// </summary>
  42.     /// <param name="name">Name of property</param>
  43.     /// <param name="propertyType">Type of the property</param>
  44.     /// <param name="ownerType">Type that is registering the property</param>
  45.     /// <param name="typeMetadata">Metadata to use if current type doesn't specify type-specific metadata</param>
  46.     /// <returns>Dependency Property</returns>
  47.     public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
  48.     {
  49.         // Forwarding
  50.         return Register(name, propertyType, ownerType, typeMetadata, null);
  51.     }
  52.     /// <summary>
  53.     ///     Register a Dependency Property
  54.     /// </summary>
  55.     /// <param name="name">Name of property</param>
  56.     /// <param name="propertyType">Type of the property</param>
  57.     /// <param name="ownerType">Type that is registering the property</param>
  58.     /// <param name="typeMetadata">Metadata to use if current type doesn't specify type-specific metadata</param>
  59.     /// <param name="validateValueCallback">Provides additional value validation outside automatic type validation</param>
  60.     /// <returns>Dependency Property</returns>
  61.     public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
  62.     {
  63.         RegisterParameterValidation(name, propertyType, ownerType);
  64.         // Register an attached property
  65.         PropertyMetadata defaultMetadata = null;
  66.         if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
  67.         {
  68.             defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
  69.         }
  70.         DependencyProperty property = RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
  71.         if (typeMetadata != null)
  72.         {
  73.             // Apply type-specific metadata to owner type only
  74.             property.OverrideMetadata(ownerType, typeMetadata);
  75.         }
  76.         return property;
  77.     }
  78.     /// <summary>
  79.     ///  Simple registration, metadata, validation, and a read-only property
  80.     /// key.  Calling this version restricts the property such that it can
  81.     /// only be set via the corresponding overload of DependencyObject.SetValue.
  82.     /// </summary>
  83.     public static DependencyPropertyKey RegisterReadOnly(
  84.         string name,
  85.         Type propertyType,
  86.         Type ownerType,
  87.         PropertyMetadata typeMetadata )
  88.     {
  89.         return RegisterReadOnly( name, propertyType, ownerType, typeMetadata, null );
  90.     }
  91.     /// <summary>
  92.     ///  Simple registration, metadata, validation, and a read-only property
  93.     /// key.  Calling this version restricts the property such that it can
  94.     /// only be set via the corresponding overload of DependencyObject.SetValue.
  95.     /// </summary>
  96.     public static DependencyPropertyKey RegisterReadOnly(
  97.         string name,
  98.         Type propertyType,
  99.         Type ownerType,
  100.         PropertyMetadata typeMetadata,
  101.         ValidateValueCallback validateValueCallback )
  102.     {
  103.         RegisterParameterValidation(name, propertyType, ownerType);
  104.         PropertyMetadata defaultMetadata = null;
  105.         if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
  106.         {
  107.             defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
  108.         }
  109.         else
  110.         {
  111.             defaultMetadata = AutoGeneratePropertyMetadata(propertyType,validateValueCallback,name,ownerType);
  112.         }
  113.         //  We create a DependencyPropertyKey at this point with a null property
  114.         // and set that in the _readOnlyKey field.  This is so the property is
  115.         // marked as requiring a key immediately.  If something fails in the
  116.         // initialization path, the property is still marked as needing a key.
  117.         //  This is better than the alternative of creating and setting the key
  118.         // later, because if that code fails the read-only property would not
  119.         // be marked read-only.  The intent of this mildly convoluted code
  120.         // is so we fail securely.
  121.         DependencyPropertyKey authorizationKey = new DependencyPropertyKey(null); // No property yet, use null as placeholder.
  122.         DependencyProperty property = RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
  123.         property._readOnlyKey = authorizationKey;
  124.         authorizationKey.SetDependencyProperty(property);
  125.         if (typeMetadata == null )
  126.         {
  127.             // No metadata specified, generate one so we can specify the authorized key.
  128.             typeMetadata = AutoGeneratePropertyMetadata(propertyType,validateValueCallback,name,ownerType);
  129.         }
  130.         // Authorize registering type for read-only access, create key.
  131.         #pragma warning suppress 6506 // typeMetadata is never null, since we generate default metadata if none is provided.
  132.         // Apply type-specific metadata to owner type only
  133.         property.OverrideMetadata(ownerType, typeMetadata, authorizationKey);
  134.         return authorizationKey;
  135.     }
  136.     /// <summary>
  137.     ///  Simple registration, metadata, validation, and a read-only property
  138.     /// key.  Calling this version restricts the property such that it can
  139.     /// only be set via the corresponding overload of DependencyObject.SetValue.
  140.     /// </summary>
  141.     public static DependencyPropertyKey RegisterAttachedReadOnly(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
  142.     {
  143.         return RegisterAttachedReadOnly( name, propertyType, ownerType, defaultMetadata, null );
  144.     }
  145.     /// <summary>
  146.     ///  Simple registration, metadata, validation, and a read-only property
  147.     /// key.  Calling this version restricts the property such that it can
  148.     /// only be set via the corresponding overload of DependencyObject.SetValue.
  149.     /// </summary>
  150.     public static DependencyPropertyKey RegisterAttachedReadOnly(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
  151.     {
  152.         RegisterParameterValidation(name, propertyType, ownerType);
  153.         // Establish default metadata for all types, if none is provided
  154.         if (defaultMetadata == null)
  155.         {
  156.             defaultMetadata = AutoGeneratePropertyMetadata( propertyType, validateValueCallback, name, ownerType );
  157.         }
  158.         //  We create a DependencyPropertyKey at this point with a null property
  159.         // and set that in the _readOnlyKey field.  This is so the property is
  160.         // marked as requiring a key immediately.  If something fails in the
  161.         // initialization path, the property is still marked as needing a key.
  162.         //  This is better than the alternative of creating and setting the key
  163.         // later, because if that code fails the read-only property would not
  164.         // be marked read-only.  The intent of this mildly convoluted code
  165.         // is so we fail securely.
  166.         DependencyPropertyKey authorizedKey = new DependencyPropertyKey(null);
  167.         DependencyProperty property = RegisterCommon( name, propertyType, ownerType, defaultMetadata, validateValueCallback);
  168.         property._readOnlyKey = authorizedKey;
  169.         authorizedKey.SetDependencyProperty(property);
  170.         return authorizedKey;
  171.     }
  172.     /// <summary>
  173.     ///     Register an attached Dependency Property
  174.     /// </summary>
  175.     /// <param name="name">Name of property</param>
  176.     /// <param name="propertyType">Type of the property</param>
  177.     /// <param name="ownerType">Type that is registering the property</param>
  178.     /// <returns>Dependency Property</returns>
  179.     public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType)
  180.     {
  181.         // Forwarding
  182.         return RegisterAttached(name, propertyType, ownerType, null, null );
  183.     }
  184.     /// <summary>
  185.     ///     Register an attached Dependency Property
  186.     /// </summary>
  187.     /// <param name="name">Name of property</param>
  188.     /// <param name="propertyType">Type of the property</param>
  189.     /// <param name="ownerType">Type that is registering the property</param>
  190.     /// <param name="defaultMetadata">Metadata to use if current type doesn't specify type-specific metadata</param>
  191.     /// <returns>Dependency Property</returns>
  192.     public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
  193.     {
  194.         // Forwarding
  195.         return RegisterAttached(name, propertyType, ownerType, defaultMetadata, null );
  196.     }
  197.     /// <summary>
  198.     ///     Register an attached Dependency Property
  199.     /// </summary>
  200.     /// <param name="name">Name of property</param>
  201.     /// <param name="propertyType">Type of the property</param>
  202.     /// <param name="ownerType">Type that is registering the property</param>
  203.     /// <param name="defaultMetadata">Metadata to use if current type doesn't specify type-specific metadata</param>
  204.     /// <param name="validateValueCallback">Provides additional value validation outside automatic type validation</param>
  205.     /// <returns>Dependency Property</returns>
  206.     public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
  207.     {
  208.         RegisterParameterValidation(name, propertyType, ownerType);
  209.         return RegisterCommon( name, propertyType, ownerType, defaultMetadata, validateValueCallback );
  210.     }
  211.     private static void RegisterParameterValidation(string name, Type propertyType, Type ownerType)
  212.     {
  213.         if (name == null)
  214.         {
  215.             throw new ArgumentNullException("name");
  216.         }
  217.         if (name.Length == 0)
  218.         {
  219.             throw new ArgumentException(SR.StringEmpty, "name");
  220.         }
  221.         if (ownerType == null)
  222.         {
  223.             throw new ArgumentNullException("ownerType");
  224.         }
  225.         if (propertyType == null)
  226.         {
  227.             throw new ArgumentNullException("propertyType");
  228.         }
  229.     }
  230.     private static DependencyProperty RegisterCommon(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
  231.     {
  232.         FromNameKey key = new FromNameKey(name, ownerType);
  233.         lock (Synchronized)
  234.         {
  235.             if (PropertyFromName.Contains(key))
  236.             {
  237.                 throw new ArgumentException(SR.Format(SR.PropertyAlreadyRegistered, name, ownerType.Name));
  238.             }
  239.         }
  240.         // Establish default metadata for all types, if none is provided
  241.         if (defaultMetadata == null)
  242.         {
  243.             defaultMetadata = AutoGeneratePropertyMetadata( propertyType, validateValueCallback, name, ownerType );
  244.         }
  245.         else // Metadata object is provided.
  246.         {
  247.             // If the defaultValue wasn't specified auto generate one
  248.             if (!defaultMetadata.DefaultValueWasSet())
  249.             {
  250.                 defaultMetadata.DefaultValue = AutoGenerateDefaultValue(propertyType);
  251.             }
  252.             ValidateMetadataDefaultValue( defaultMetadata, propertyType, name, validateValueCallback );
  253.         }
  254.         // Create property
  255.         DependencyProperty dp = new DependencyProperty(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
  256.         // Seal (null means being used for default metadata, calls OnApply)
  257.         defaultMetadata.Seal(dp, null);
  258.         if (defaultMetadata.IsInherited)
  259.         {
  260.             dp._packedData |= Flags.IsPotentiallyInherited;
  261.         }
  262.         if (defaultMetadata.UsingDefaultValueFactory)
  263.         {
  264.             dp._packedData |= Flags.IsPotentiallyUsingDefaultValueFactory;
  265.         }
  266.         // Map owner type to this property
  267.         // Build key
  268.         lock (Synchronized)
  269.         {
  270.             PropertyFromName[key] = dp;
  271.         }
  272.         if( TraceDependencyProperty.IsEnabled )
  273.         {
  274.             TraceDependencyProperty.TraceActivityItem(
  275.                 TraceDependencyProperty.Register,
  276.                 dp,
  277.                 dp.OwnerType );
  278.         }
  279.         return dp;
  280.     }
  281.     private static object AutoGenerateDefaultValue(
  282.         Type propertyType)
  283.     {
  284.         // Default per-type metadata not provided, create
  285.         object defaultValue = null;
  286.         // Auto-assigned default value
  287.         if (propertyType.IsValueType)
  288.         {
  289.             // Value-types have default-constructed type default values
  290.             defaultValue = Activator.CreateInstance(propertyType);
  291.         }
  292.         return defaultValue;
  293.     }
  294.     private static PropertyMetadata AutoGeneratePropertyMetadata(
  295.         Type propertyType,
  296.         ValidateValueCallback validateValueCallback,
  297.         string name,
  298.         Type ownerType)
  299.     {
  300.         // Default per-type metadata not provided, create
  301.         object defaultValue = AutoGenerateDefaultValue(propertyType);
  302.         // If a validator is passed in, see if the default value makes sense.
  303.         if ( validateValueCallback != null &&
  304.             !validateValueCallback(defaultValue))
  305.         {
  306.             // Didn't work - require the caller to specify one.
  307.             throw new ArgumentException(SR.Format(SR.DefaultValueAutoAssignFailed, name, ownerType.Name));
  308.         }
  309.         return new PropertyMetadata(defaultValue);
  310.     }
  311.     // Validate the default value in the given metadata
  312.     private static void ValidateMetadataDefaultValue(
  313.         PropertyMetadata defaultMetadata,
  314.         Type propertyType,
  315.         string propertyName,
  316.         ValidateValueCallback validateValueCallback )
  317.     {
  318.         // If we are registered to use the DefaultValue factory we can
  319.         // not validate the DefaultValue at registration time, so we
  320.         // early exit.
  321.         if (defaultMetadata.UsingDefaultValueFactory)
  322.         {
  323.             return;
  324.         }
  325.         ValidateDefaultValueCommon(defaultMetadata.DefaultValue, propertyType,
  326.             propertyName, validateValueCallback, /*checkThreadAffinity = */ true);
  327.     }
  328.     // Validate the given default value, used by PropertyMetadata.GetDefaultValue()
  329.     // when the DefaultValue factory is used.
  330.     // These default values are allowed to have thread-affinity.
  331.     internal void ValidateFactoryDefaultValue(object defaultValue)
  332.     {
  333.         ValidateDefaultValueCommon(defaultValue, PropertyType, Name, ValidateValueCallback, false);
  334.     }
  335.     private static void ValidateDefaultValueCommon(
  336.         object defaultValue,
  337.         Type propertyType,
  338.         string propertyName,
  339.         ValidateValueCallback validateValueCallback,
  340.         bool checkThreadAffinity)
  341.     {
  342.         // Ensure default value is the correct type
  343.         if (!IsValidType(defaultValue, propertyType))
  344.         {
  345.             throw new ArgumentException(SR.Format(SR.DefaultValuePropertyTypeMismatch, propertyName));
  346.         }
  347.         // An Expression used as default value won't behave as expected since
  348.         //  it doesn't get evaluated.  We explicitly fail it here.
  349.         if (defaultValue is Expression )
  350.         {
  351.             throw new ArgumentException(SR.DefaultValueMayNotBeExpression);
  352.         }
  353.         if (checkThreadAffinity)
  354.         {
  355.             // If the default value is a DispatcherObject with thread affinity
  356.             // we cannot accept it as a default value. If it implements ISealable
  357.             // we attempt to seal it; if not we throw  an exception. Types not
  358.             // deriving from DispatcherObject are allowed - it is up to the user to
  359.             // make any custom types free-threaded.
  360.             DispatcherObject dispatcherObject = defaultValue as DispatcherObject;
  361.             if (dispatcherObject != null && dispatcherObject.Dispatcher != null)
  362.             {
  363.                 // Try to make the DispatcherObject free-threaded if it's an
  364.                 // ISealable.
  365.                 ISealable valueAsISealable = dispatcherObject as ISealable;
  366.                 if (valueAsISealable != null && valueAsISealable.CanSeal)
  367.                 {
  368.                     Invariant.Assert (!valueAsISealable.IsSealed,
  369.                            "A Sealed ISealable must not have dispatcher affinity");
  370.                     valueAsISealable.Seal();
  371.                     Invariant.Assert(dispatcherObject.Dispatcher == null,
  372.                         "ISealable.Seal() failed after ISealable.CanSeal returned true");
  373.                 }
  374.                 else
  375.                 {
  376.                     throw new ArgumentException(SR.Format(SR.DefaultValueMustBeFreeThreaded, propertyName));
  377.                 }
  378.             }
  379.         }
  380.         // After checking for correct type, check default value against
  381.         //  validator (when one is given)
  382.         if ( validateValueCallback != null &&
  383.             !validateValueCallback(defaultValue))
  384.         {
  385.             throw new ArgumentException(SR.Format(SR.DefaultValueInvalid, propertyName));
  386.         }
  387.     }
  388.     /// <summary>
  389.     ///     Parameter validation for OverrideMetadata, includes code to force
  390.     /// all base classes of "forType" to register their metadata so we know
  391.     /// what we are overriding.
  392.     /// </summary>
  393.     private void SetupOverrideMetadata(
  394.             Type forType,
  395.             PropertyMetadata typeMetadata,
  396.         out DependencyObjectType dType,
  397.         out PropertyMetadata baseMetadata )
  398.     {
  399.         if (forType == null)
  400.         {
  401.             throw new ArgumentNullException("forType");
  402.         }
  403.         if (typeMetadata == null)
  404.         {
  405.             throw new ArgumentNullException("typeMetadata");
  406.         }
  407.         if (typeMetadata.Sealed)
  408.         {
  409.             throw new ArgumentException(SR.TypeMetadataAlreadyInUse);
  410.         }
  411.         if (!typeof(DependencyObject).IsAssignableFrom(forType))
  412.         {
  413.             throw new ArgumentException(SR.Format(SR.TypeMustBeDependencyObjectDerived, forType.Name));
  414.         }
  415.         // Ensure default value is a correct value (if it was supplied,
  416.         // otherwise, the default value will be taken from the base metadata
  417.         // which was already validated)
  418.         if (typeMetadata.IsDefaultValueModified)
  419.         {
  420.             // Will throw ArgumentException if fails.
  421.             ValidateMetadataDefaultValue( typeMetadata, PropertyType, Name, ValidateValueCallback );
  422.         }
  423.         // Force all base classes to register their metadata
  424.         dType = DependencyObjectType.FromSystemType(forType);
  425.         // Get metadata for the base type
  426.         baseMetadata = GetMetadata(dType.BaseType);
  427.         // Make sure overriding metadata is the same type or derived type of
  428.         // the base metadata
  429.         if (!baseMetadata.GetType().IsAssignableFrom(typeMetadata.GetType()))
  430.         {
  431.             throw new ArgumentException(SR.OverridingMetadataDoesNotMatchBaseMetadataType);
  432.         }
  433.     }
  434.     /// <summary>
  435.     ///     Supply metadata for given type & run static constructors if needed.
  436.     /// </summary>
  437.     /// <remarks>
  438.     ///     The supplied metadata will be merged with the type's base
  439.     ///     metadata
  440.     /// </remarks>
  441.     public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata)
  442.     {
  443.         DependencyObjectType dType;
  444.         PropertyMetadata baseMetadata;
  445.         SetupOverrideMetadata(forType, typeMetadata, out dType, out baseMetadata);
  446.         if (ReadOnly)
  447.         {
  448.             // Readonly and no DependencyPropertyKey - not allowed.
  449.             throw new InvalidOperationException(SR.Format(SR.ReadOnlyOverrideNotAllowed, Name));
  450.         }
  451.         ProcessOverrideMetadata(forType, typeMetadata, dType, baseMetadata);
  452.     }
  453.     /// <summary>
  454.     ///     Supply metadata for a given type, overriding a property that is
  455.     /// read-only.  If property is not read only, tells user to use the Plain
  456.     /// Jane OverrideMetadata instead.
  457.     /// </summary>
  458.     public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata, DependencyPropertyKey key)
  459.     {
  460.         DependencyObjectType dType;
  461.         PropertyMetadata baseMetadata;
  462.         SetupOverrideMetadata(forType, typeMetadata, out dType, out baseMetadata);
  463.         if (key == null)
  464.         {
  465.             throw new ArgumentNullException("key");
  466.         }
  467.         if (ReadOnly)
  468.         {
  469.             // If the property is read-only, the key must match this property
  470.             //  and the key must match that in the base metadata.
  471.             if (key.DependencyProperty != this)
  472.             {
  473.                 throw new ArgumentException(SR.Format(SR.ReadOnlyOverrideKeyNotAuthorized, Name));
  474.             }
  475.             VerifyReadOnlyKey(key);
  476.         }
  477.         else
  478.         {
  479.             throw new InvalidOperationException(SR.PropertyNotReadOnly);
  480.         }
  481.         // Either the property doesn't require a key, or the key match was
  482.         //  successful.  Proceed with the metadata override.
  483.         ProcessOverrideMetadata(forType, typeMetadata, dType, baseMetadata);
  484.     }
  485.     /// <summary>
  486.     ///     After parameters have been validated for OverrideMetadata, this
  487.     /// method is called to actually update the data structures.
  488.     /// </summary>
  489.     private void ProcessOverrideMetadata(
  490.         Type forType,
  491.         PropertyMetadata typeMetadata,
  492.         DependencyObjectType dType,
  493.         PropertyMetadata baseMetadata)
  494.     {
  495.         // Store per-Type metadata for this property. Locks only on Write.
  496.         // Datastructure guaranteed to be valid for non-locking readers
  497.         lock (Synchronized)
  498.         {
  499.             if (DependencyProperty.UnsetValue == _metadataMap[dType.Id])
  500.             {
  501.                 _metadataMap[dType.Id] = typeMetadata;
  502.             }
  503.             else
  504.             {
  505.                 throw new ArgumentException(SR.Format(SR.TypeMetadataAlreadyRegistered, forType.Name));
  506.             }
  507.        }
  508.         // Merge base's metadata into this metadata
  509.         // CALLBACK
  510.         typeMetadata.InvokeMerge(baseMetadata, this);
  511.         // Type metadata may no longer change (calls OnApply)
  512.         typeMetadata.Seal(this, forType);
  513.         if (typeMetadata.IsInherited)
  514.         {
  515.             _packedData |= Flags.IsPotentiallyInherited;
  516.         }
  517.         if (typeMetadata.DefaultValueWasSet() && (typeMetadata.DefaultValue != DefaultMetadata.DefaultValue))
  518.         {
  519.             _packedData |= Flags.IsDefaultValueChanged;
  520.         }
  521.         if (typeMetadata.UsingDefaultValueFactory)
  522.         {
  523.             _packedData |= Flags.IsPotentiallyUsingDefaultValueFactory;
  524.         }
  525.     }
  526.     [FriendAccessAllowed]   // Built into Base, also used by Core & Framework.
  527.     internal object GetDefaultValue(DependencyObjectType dependencyObjectType)
  528.     {
  529.         if (!IsDefaultValueChanged)
  530.         {
  531.             return DefaultMetadata.DefaultValue;
  532.         }
  533.         return GetMetadata(dependencyObjectType).DefaultValue;
  534.     }
  535.     [FriendAccessAllowed]   // Built into Base, also used by Core & Framework.
  536.     internal object GetDefaultValue(Type forType)
  537.     {
  538.         if (!IsDefaultValueChanged)
  539.         {
  540.             return DefaultMetadata.DefaultValue;
  541.         }
  542.         return GetMetadata(DependencyObjectType.FromSystemTypeInternal(forType)).DefaultValue;
  543.     }
  544.     /// <summary>
  545.     ///     Retrieve metadata for a provided type
  546.     /// </summary>
  547.     /// <param name="forType">Type to get metadata</param>
  548.     /// <returns>Property metadata</returns>
  549.     public PropertyMetadata GetMetadata(Type forType)
  550.     {
  551.         if (forType != null)
  552.         {
  553.             return GetMetadata(DependencyObjectType.FromSystemType(forType));
  554.         }
  555.         throw new ArgumentNullException("forType");
  556.     }
  557.     /// <summary>
  558.     ///     Retrieve metadata for a provided DependencyObject
  559.     /// </summary>
  560.     /// <param name="dependencyObject">DependencyObject to get metadata</param>
  561.     /// <returns>Property metadata</returns>
  562.     public PropertyMetadata GetMetadata(DependencyObject dependencyObject)
  563.     {
  564.         if (dependencyObject != null)
  565.         {
  566.             return GetMetadata(dependencyObject.DependencyObjectType);
  567.         }
  568.         throw new ArgumentNullException("dependencyObject");
  569.     }
  570.     /// <summary>
  571.     /// Reteive metadata for a DependencyObject type described by the
  572.     /// given DependencyObjectType
  573.     /// </summary>
  574.     public PropertyMetadata GetMetadata(DependencyObjectType dependencyObjectType)
  575.     {
  576.         // All static constructors for this DType and all base types have already
  577.         // been run. If no overriden metadata was provided, then look up base types.
  578.         // If no metadata found on base types, then return default
  579.         if (null != dependencyObjectType)
  580.         {
  581.             // Do we in fact have any overrides at all?
  582.             int index = _metadataMap.Count - 1;
  583.             int Id;
  584.             object value;
  585.             if (index < 0)
  586.             {
  587.                 // No overrides or it's the base class
  588.                 return _defaultMetadata;
  589.             }
  590.             else if (index == 0)
  591.             {
  592.                 // Only 1 override
  593.                 _metadataMap.GetKeyValuePair(index, out Id, out value);
  594.                 // If there is overriden metadata, then there is a base class with
  595.                 // lower or equal Id of this class, or this class is already a base class
  596.                 // of the overridden one. Therefore dependencyObjectType won't ever
  597.                 // become null before we exit the while loop
  598.                 while (dependencyObjectType.Id > Id)
  599.                 {
  600.                     dependencyObjectType = dependencyObjectType.BaseType;
  601.                 }
  602.                 if (Id == dependencyObjectType.Id)
  603.                 {
  604.                     // Return the override
  605.                     return (PropertyMetadata)value;
  606.                 }
  607.                 // Return default metadata
  608.             }
  609.             else
  610.             {
  611.                 // We have more than 1 override for this class, so we will have to loop through
  612.                 // both the overrides and the class Id
  613.                 if (0 != dependencyObjectType.Id)
  614.                 {
  615.                     do
  616.                     {
  617.                         // Get the Id of the most derived class with overridden metadata
  618.                         _metadataMap.GetKeyValuePair(index, out Id, out value);
  619.                         --index;
  620.                         // If the Id of this class is less than the override, then look for an override
  621.                         // with an equal or lower Id until we run out of overrides
  622.                         while ((dependencyObjectType.Id < Id) && (index >= 0))
  623.                         {
  624.                             _metadataMap.GetKeyValuePair(index, out Id, out value);
  625.                             --index;
  626.                         }
  627.                         // If there is overriden metadata, then there is a base class with
  628.                         // lower or equal Id of this class, or this class is already a base class
  629.                         // of the overridden one. Therefore dependencyObjectType won't ever
  630.                         // become null before we exit the while loop
  631.                         while (dependencyObjectType.Id > Id)
  632.                         {
  633.                             dependencyObjectType = dependencyObjectType.BaseType;
  634.                         }
  635.                         if (Id == dependencyObjectType.Id)
  636.                         {
  637.                             // Return the override
  638.                             return (PropertyMetadata)value;
  639.                         }
  640.                     }
  641.                     while (index >= 0);
  642.                 }
  643.             }
  644.         }
  645.         return _defaultMetadata;
  646.     }
  647.     /// <summary>
  648.     ///     Associate another owner type with this property
  649.     /// </summary>
  650.     /// <remarks>
  651.     ///     The owner type is used when resolving a property by name (<see cref="FromName"/>)
  652.     /// </remarks>
  653.     /// <param name="ownerType">Additional owner type</param>
  654.     /// <returns>This property</returns>
  655.     public DependencyProperty AddOwner(Type ownerType)
  656.     {
  657.         // Forwarding
  658.         return AddOwner(ownerType, null);
  659.     }
  660.     /// <summary>
  661.     ///     Associate another owner type with this property
  662.     /// </summary>
  663.     /// <remarks>
  664.     ///     The owner type is used when resolving a property by name (<see cref="FromName"/>)
  665.     /// </remarks>
  666.     /// <param name="ownerType">Additional owner type</param>
  667.     /// <param name="typeMetadata">Optional type metadata to override on owner's behalf</param>
  668.     /// <returns>This property</returns>
  669.     public DependencyProperty AddOwner(Type ownerType, PropertyMetadata typeMetadata)
  670.     {
  671.         if (ownerType == null)
  672.         {
  673.             throw new ArgumentNullException("ownerType");
  674.         }
  675.         // Map owner type to this property
  676.         // Build key
  677.         FromNameKey key = new FromNameKey(Name, ownerType);
  678.         lock (Synchronized)
  679.         {
  680.             if (PropertyFromName.Contains(key))
  681.             {
  682.                 throw new ArgumentException(SR.Format(SR.PropertyAlreadyRegistered, Name, ownerType.Name));
  683.             }
  684.         }
  685.         if (typeMetadata != null)
  686.         {
  687.             OverrideMetadata(ownerType, typeMetadata);
  688.         }
  689.         lock (Synchronized)
  690.         {
  691.             PropertyFromName[key] = this;
  692.         }
  693.         return this;
  694.     }
  695.     /// <summary>
  696.     ///     Name of the property
  697.     /// </summary>
  698.     public string Name
  699.     {
  700.         get { return _name; }
  701.     }
  702.     /// <summary>
  703.     ///     Type of the property
  704.     /// </summary>
  705.     public Type PropertyType
  706.     {
  707.         get { return _propertyType; }
  708.     }
  709.     /// <summary>
  710.     ///     Owning type of the property
  711.     /// </summary>
  712.     public Type OwnerType
  713.     {
  714.         get { return _ownerType; }
  715.     }
  716.     /// <summary>
  717.     ///     Default metadata for the property
  718.     /// </summary>
  719.     public PropertyMetadata DefaultMetadata
  720.     {
  721.         get { return _defaultMetadata; }
  722.     }
  723.     /// <summary>
  724.     ///     Value validation callback
  725.     /// </summary>
  726.     public ValidateValueCallback ValidateValueCallback
  727.     {
  728.         get { return _validateValueCallback; }
  729.     }
  730.     /// <summary>
  731.     ///     Zero-based globally unique index of the property
  732.     /// </summary>
  733.     public int GlobalIndex
  734.     {
  735.         get { return (int) (_packedData & Flags.GlobalIndexMask); }
  736.     }
  737.     internal bool IsObjectType
  738.     {
  739.         get { return (_packedData & Flags.IsObjectType) != 0; }
  740.     }
  741.     internal bool IsValueType
  742.     {
  743.         get { return (_packedData & Flags.IsValueType) != 0; }
  744.     }
  745.     internal bool IsFreezableType
  746.     {
  747.         get { return (_packedData & Flags.IsFreezableType) != 0; }
  748.     }
  749.     internal bool IsStringType
  750.     {
  751.         get { return (_packedData & Flags.IsStringType) != 0; }
  752.     }
  753.     internal bool IsPotentiallyInherited
  754.     {
  755.         get { return (_packedData & Flags.IsPotentiallyInherited) != 0; }
  756.     }
  757.     internal bool IsDefaultValueChanged
  758.     {
  759.         get { return (_packedData & Flags.IsDefaultValueChanged) != 0; }
  760.     }
  761.     internal bool IsPotentiallyUsingDefaultValueFactory
  762.     {
  763.         get { return (_packedData & Flags.IsPotentiallyUsingDefaultValueFactory) != 0; }
  764.     }
  765.     /// <summary>
  766.     ///     Serves as a hash function for a particular type, suitable for use in
  767.     ///     hashing algorithms and data structures like a hash table
  768.     /// </summary>
  769.     /// <returns>The DependencyProperty's GlobalIndex</returns>
  770.     public override int GetHashCode()
  771.     {
  772.         return GlobalIndex;
  773.     }
  774.     /// <summary>
  775.     ///     Used to determine if given value is appropriate for the type of the property
  776.     /// </summary>
  777.     /// <param name="value">Value to check</param>
  778.     /// <returns>true if value matches property type</returns>
  779.     public bool IsValidType(object value)
  780.     {
  781.         return IsValidType(value, PropertyType);
  782.     }
  783.     /// <summary>
  784.     ///     Used to determine if given value is appropriate for the type of the property
  785.     ///     and the range of values (as specified via the ValidateValueCallback) within that type
  786.     /// </summary>
  787.     /// <param name="value">Value to check</param>
  788.     /// <returns>true if value is appropriate</returns>
  789.     public bool IsValidValue(object value)
  790.     {
  791.         if (!IsValidType(value, PropertyType))
  792.         {
  793.             return false;
  794.         }
  795.         if (ValidateValueCallback != null)
  796.         {
  797.             // CALLBACK
  798.             return ValidateValueCallback(value);
  799.         }
  800.         return true;
  801.     }
  802.     /// <summary>
  803.     ///     Set/Value value disabling
  804.     /// </summary>
  805.     public bool ReadOnly
  806.     {
  807.         get
  808.         {
  809.             return (_readOnlyKey != null);
  810.         }
  811.     }
  812.     /// <summary>
  813.     ///     Returns the DependencyPropertyKey associated with this DP.
  814.     /// </summary>
  815.     internal DependencyPropertyKey DependencyPropertyKey
  816.     {
  817.         get
  818.         {
  819.             return _readOnlyKey;
  820.         }
  821.     }
  822.     internal void VerifyReadOnlyKey( DependencyPropertyKey candidateKey )
  823.     {
  824.         Debug.Assert( ReadOnly, "Why are we trying to validate read-only key on a property that is not read-only?");
  825.         if (_readOnlyKey != candidateKey)
  826.         {
  827.             throw new ArgumentException(SR.ReadOnlyKeyNotAuthorized);
  828.         }
  829.     }
  830.     /// <summary>
  831.     ///     Internal version of IsValidValue that bypasses IsValidType check;
  832.     ///     Called from SetValueInternal
  833.     /// </summary>
  834.     /// <param name="value">Value to check</param>
  835.     /// <returns>true if value is appropriate</returns>
  836.     internal bool IsValidValueInternal(object value)
  837.     {
  838.         if (ValidateValueCallback != null)
  839.         {
  840.             // CALLBACK
  841.             return ValidateValueCallback(value);
  842.         }
  843.         return true;
  844.     }
  845.     /// <summary>
  846.     ///     Find a property from name
  847.     /// </summary>
  848.     /// <remarks>
  849.     ///     Search includes base classes of the provided type as well
  850.     /// </remarks>
  851.     /// <param name="name">Name of the property</param>
  852.     /// <param name="ownerType">Owner type of the property</param>
  853.     /// <returns>Dependency property</returns>
  854.     [FriendAccessAllowed]   // Built into Base, also used by Framework.
  855.     internal static DependencyProperty FromName(string name, Type ownerType)
  856.     {
  857.         DependencyProperty dp = null;
  858.         if (name != null)
  859.         {
  860.             if (ownerType != null)
  861.             {
  862.                 FromNameKey key = new FromNameKey(name, ownerType);
  863.                 while ((dp == null) && (ownerType != null))
  864.                 {
  865.                     // Ensure static constructor of type has run
  866.                     MS.Internal.WindowsBase.SecurityHelper.RunClassConstructor(ownerType);
  867.                     // Locate property
  868.                     key.UpdateNameKey(ownerType);
  869.                     lock (Synchronized)
  870.                     {
  871.                         dp = (DependencyProperty)PropertyFromName[key];
  872.                     }
  873.                     ownerType = ownerType.BaseType;
  874.                 }
  875.             }
  876.             else
  877.             {
  878.                 throw new ArgumentNullException("ownerType");
  879.             }
  880.         }
  881.         else
  882.         {
  883.             throw new ArgumentNullException("name");
  884.         }
  885.         return dp;
  886.     }
  887.     /// <summary>
  888.     ///    String representation
  889.     /// </summary>
  890.     public override string ToString()
  891.     {
  892.         return _name;
  893.     }
  894.     internal static bool IsValidType(object value, Type propertyType)
  895.     {
  896.         if (value == null)
  897.         {
  898.             // Null values are invalid for value-types
  899.             if (propertyType.IsValueType &&
  900.                 !(propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == NullableType))
  901.             {
  902.                 return false;
  903.             }
  904.         }
  905.         else
  906.         {
  907.             // Non-null default value, ensure its the correct type
  908.             if (!propertyType.IsInstanceOfType(value))
  909.             {
  910.                 return false;
  911.             }
  912.         }
  913.         return true;
  914.     }
  915.     private class FromNameKey
  916.     {
  917.         public FromNameKey(string name, Type ownerType)
  918.         {
  919.             _name = name;
  920.             _ownerType = ownerType;
  921.             _hashCode = _name.GetHashCode() ^ _ownerType.GetHashCode();
  922.         }
  923.         public void UpdateNameKey(Type ownerType)
  924.         {
  925.             _ownerType = ownerType;
  926.             _hashCode = _name.GetHashCode() ^ _ownerType.GetHashCode();
  927.         }
  928.         public override int GetHashCode()
  929.         {
  930.             return _hashCode;
  931.         }
  932.         public override bool Equals(object o)
  933.         {
  934.             if ((o != null) && (o is FromNameKey))
  935.             {
  936.                 return Equals((FromNameKey)o);
  937.             }
  938.             else
  939.             {
  940.                 return false;
  941.             }
  942.         }
  943.         public bool Equals(FromNameKey key)
  944.         {
  945.             return (_name.Equals(key._name) && (_ownerType == key._ownerType));
  946.         }
  947.         private string _name;
  948.         private Type _ownerType;
  949.         private int _hashCode;
  950.     }
  951.     private DependencyProperty(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
  952.     {
  953.         _name = name;
  954.         _propertyType = propertyType;
  955.         _ownerType = ownerType;
  956.         _defaultMetadata = defaultMetadata;
  957.         _validateValueCallback = validateValueCallback;
  958.         Flags packedData;
  959.         lock (Synchronized)
  960.         {
  961.             packedData = (Flags) GetUniqueGlobalIndex(ownerType, name);
  962.             RegisteredPropertyList.Add(this);
  963.         }
  964.         if (propertyType.IsValueType)
  965.         {
  966.             packedData |= Flags.IsValueType;
  967.         }
  968.         if (propertyType == typeof(object))
  969.         {
  970.             packedData |= Flags.IsObjectType;
  971.         }
  972.         if (typeof(Freezable).IsAssignableFrom(propertyType))
  973.         {
  974.             packedData |= Flags.IsFreezableType;
  975.         }
  976.         if (propertyType == typeof(string))
  977.         {
  978.             packedData |= Flags.IsStringType;
  979.         }
  980.         _packedData = packedData;
  981.     }
  982.     // Synchronized: Covered by DependencyProperty.Synchronized
  983.     internal static int GetUniqueGlobalIndex(Type ownerType, string name)
  984.     {
  985.         // Prevent GlobalIndex from overflow. DependencyProperties are meant to be static members and are to be registered
  986.         // only via static constructors. However there is no cheap way of ensuring this, without having to do a stack walk. Hence
  987.         // concievably people could register DependencyProperties via instance methods and therefore cause the GlobalIndex to
  988.         // overflow. This check will explicitly catch this error, instead of silently malfuntioning.
  989.         if (GlobalIndexCount >= (int)Flags.GlobalIndexMask)
  990.         {
  991.             if (ownerType != null)
  992.             {
  993.                 throw new InvalidOperationException(SR.Format(SR.TooManyDependencyProperties, ownerType.Name + "." + name));
  994.             }
  995.             else
  996.             {
  997.                 throw new InvalidOperationException(SR.Format(SR.TooManyDependencyProperties, "ConstantProperty"));
  998.             }
  999.         }
  1000.         // Covered by Synchronized by caller
  1001.         return GlobalIndexCount++;
  1002.     }
  1003.     /// <summary>
  1004.     /// This is the callback designers use to participate in the computation of property
  1005.     /// values at design time. Eg. Even if the author sets Visibility to Hidden, the designer
  1006.     /// wants to coerce the value to Visible at design time so that the element doesn't
  1007.     /// disappear from the design surface.
  1008.     /// </summary>
  1009.     internal CoerceValueCallback DesignerCoerceValueCallback
  1010.     {
  1011.         get {  return _designerCoerceValueCallback; }
  1012.         set
  1013.         {
  1014.             if (ReadOnly)
  1015.             {
  1016.                 throw new InvalidOperationException(SR.Format(SR.ReadOnlyDesignerCoersionNotAllowed, Name));
  1017.             }
  1018.             _designerCoerceValueCallback = value;
  1019.         }
  1020.     }
  1021.     /// <summary> Standard unset value </summary>
  1022.     public static readonly object UnsetValue = new NamedObject("DependencyProperty.UnsetValue");
  1023.     private string _name;
  1024.     private Type _propertyType;
  1025.     private Type _ownerType;
  1026.     private PropertyMetadata _defaultMetadata;
  1027.     private ValidateValueCallback _validateValueCallback;
  1028.     private DependencyPropertyKey _readOnlyKey;
  1029.     [Flags]
  1030.     private enum Flags : int
  1031.     {
  1032.         GlobalIndexMask                           = 0x0000FFFF,
  1033.         IsValueType                               = 0x00010000,
  1034.         IsFreezableType                           = 0x00020000,
  1035.         IsStringType                              = 0x00040000,
  1036.         IsPotentiallyInherited                    = 0x00080000,
  1037.         IsDefaultValueChanged                     = 0x00100000,
  1038.         IsPotentiallyUsingDefaultValueFactory     = 0x00200000,
  1039.         IsObjectType                              = 0x00400000,
  1040.         // 0xFF800000   free bits
  1041.     }
  1042.     private Flags _packedData;
  1043.     // Synchronized (write locks, lock-free reads): Covered by DependencyProperty instance
  1044.     // This is a map that contains the IDs of derived classes that have overriden metadata
  1045.     /* property */ internal InsertionSortMap _metadataMap = new InsertionSortMap();
  1046.     private CoerceValueCallback _designerCoerceValueCallback;
  1047.     // Synchronized (write locks, lock-free reads): Covered by DependencyProperty.Synchronized
  1048.     /* property */ internal static ItemStructList<DependencyProperty> RegisteredPropertyList = new ItemStructList<DependencyProperty>(768);
  1049.     // Synchronized: Covered by DependencyProperty.Synchronized
  1050.     private static Hashtable PropertyFromName = new Hashtable();
  1051.     // Synchronized: Covered by DependencyProperty.Synchronized
  1052.     private static int GlobalIndexCount;
  1053.     // Global, cross-object synchronization
  1054.     internal static object Synchronized = new object();
  1055.     // Nullable Type
  1056.     private static Type NullableType = typeof(Nullable<>);
  1057.     /// <summary>
  1058.     ///     Returns the number of all registered properties.
  1059.     /// </summary>
  1060.     internal static int RegisteredPropertyCount {
  1061.         get {
  1062.             return RegisteredPropertyList.Count;
  1063.         }
  1064.     }
  1065.     /// <summary>
  1066.     ///     Returns an enumeration of properties that are
  1067.     ///     currently registered.
  1068.     ///     Synchronized (write locks, lock-free reads): Covered by DependencyProperty.Synchronized
  1069.     /// </summary>
  1070.     internal static IEnumerable RegisteredProperties {
  1071.         get {
  1072.             foreach(DependencyProperty dp in RegisteredPropertyList.List) {
  1073.                 if (dp != null) {
  1074.                     yield return dp;
  1075.                 }
  1076.             }
  1077.         }
  1078.     }
复制代码
}
}
[/code]
4 - 依赖属性的好处怎么提现?

WPF的设计理念是:数据驱动,UI与逻辑松耦合。我们从这个上边可以去研究一下。
  1. public class Person
  2. {
  3.     private string _Name;
  4.     public string Name
  5.     {
  6.         get
  7.         {
  8.              return _Name;
  9.          }
  10.          set
  11.          {
  12.             _Name = value;
  13.          }
  14.      }
  15. }
复制代码
但是呢,CLR属性有个特点,在多级继承的情况下,每次继承,父类的字段都被继承,孙孙辈对象占用内存空间不可避免的膨胀。
那么说在基于这个缺点的情况下,依赖属性呢解决了一部分问题

  • 在多级继承,大多数字段并没有被修改的情况下,如何少对象的体积。
  • 数据驱动指导思想下,数据如何保存简单一致,同步
  1. // 1. 使类型继承DependencyObject类
  2. public class Person : DependencyObject
  3. {
  4.     // 2. 声明一个静态只读的DependencyProperty 字段
  5.     public static readonly DependencyProperty nameProperty;
  6.     static Person()
  7.     {
  8.         // 3. 注册定义的依赖属性
  9.         nameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Person),
  10.             new PropertyMetadata("Learning Hard",OnValueChanged));
  11.     }
  12.     // 4. 属性包装器,通过它来读取和设置我们刚才注册的依赖属性
  13.     public string Name
  14.     {
  15.         get { return (string)GetValue(nameProperty); }
  16.         set { SetValue(nameProperty, value); }
  17.     }
  18.     private static void OnValueChanged(DependencyObject dpobj, DependencyPropertyChangedEventArgs e)
  19.     {
  20.         // 当只发生改变时回调的方法
  21.     }
  22. }
复制代码
优势在那里呢?
1、解决多级继承,且大多数字段值不改变的情况下,减少内存占比
将一个DependencyProperty对象存储在一个全局的Hashtable中;通过依赖对象(DependencyObject)的GetValue和SetValue存取数据;
2、以数据为中心,当数据源改变时,所以关联的UI数据改变;
依赖属性值可以通过Binding依赖于其它对象上,这就使得数据源一变动;依赖于此数据源的依赖属性全部进行更新
这里呢贴一个链接可以参考参考:
https://www.cnblogs.com/Zhouyongh/archive/2009/09/10/1564099.html5 - 依赖属性怎么解决内存占比问题呢?

首先呢,我们先确认一下对于依赖属性而言,到底有没有节约内存。我们写个Demo就能明显看出来
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Data;
  9. using System.Windows.Documents;
  10. using System.Windows.Input;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Imaging;
  13. using System.Windows.Navigation;
  14. using System.Windows.Shapes;
  15. <p>namespace FifthWPFDemo
  16. {
  17. /// <summary>
  18. /// MainWindow.xaml 的交互逻辑
  19. /// </summary>
  20. public partial class MainWindow : Window
  21. {
  22. Person per;
  23. public MainWindow()
  24. {
  25. InitializeComponent();
  26. List<Person> list = new List<Person>();
  27. for (int i = 0; i < 10000000; i++)
  28. {
  29. per = new Person();
  30. list.Add(per);
  31. }
  32. }
  33. }
  34. public class Person
  35. {
  36. public double Name { get; set; }
  37. public double Name1 { get; set; }
  38. public double Name2 { get; set; }
  39. public double Name3 { get; set; }
  40. public double Name4 { get; set; }
  41. public double Name5 { get; set; }
  42. public double Name6 { get; set; }
  43. public double Name7 { get; set; }
  44. public double Name8 { get; set; }
  45. public double Name9 { get; set; }
  46. public double Name10 { get; set; }
  47. }
  48. }</p>
复制代码

此时我们将普通属性换位依赖属性我们再看看
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Data;
  9. using System.Windows.Documents;
  10. using System.Windows.Input;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Imaging;
  13. using System.Windows.Navigation;
  14. using System.Windows.Shapes;
  15. <p>namespace FifthWPFDemo
  16. {
  17. /// <summary>
  18. /// MainWindow.xaml 的交互逻辑
  19. /// </summary>
  20. public partial class MainWindow : Window
  21. {
  22. Person per;
  23. public MainWindow()
  24. {
  25. InitializeComponent();
  26. List<Person> list = new List<Person>();
  27. for (int i = 0; i < 10000000; i++)
  28. {
  29. per = new Person();
  30. list.Add(per);
  31. }
  32. }
  33. }
  34. public class Person : DependencyObject
  35. {
  36. public double Name
  37. {
  38. get
  39. {
  40. return (double)GetValue(NameProperty);
  41. }
  42. set
  43. {
  44. SetValue(NameProperty, value);
  45. }
  46. }
  47. public double Name1
  48. {
  49. get
  50. {
  51. return (double)GetValue(Name1Property);
  52. }
  53. set
  54. {
  55. SetValue(Name1Property, value);
  56. }
  57. }
  58. public double Name2
  59. {
  60. get
  61. {
  62. return (double)GetValue(Name2Property);
  63. }
  64. set
  65. {
  66. SetValue(Name2Property, value);
  67. }
  68. }
  69. public double Name3
  70. {
  71. get
  72. {
  73. return (double)GetValue(Name3Property);
  74. }
  75. set
  76. {
  77. SetValue(Name3Property, value);
  78. }
  79. }</p>
  80. [code]    public double Name4
  81.     {
  82.         get
  83.         {
  84.             return (double)GetValue(Name4Property);
  85.         }
  86.         set
  87.         {
  88.             SetValue(Name4Property, value);
  89.         }
  90.     }
  91.     public double Name5
  92.     {
  93.         get
  94.         {
  95.             return (double)GetValue(Name5Property);
  96.         }
  97.         set
  98.         {
  99.             SetValue(Name5Property, value);
  100.         }
  101.     }
  102.     public double Name6
  103.     {
  104.         get
  105.         {
  106.             return (double)GetValue(Name6Property);
  107.         }
  108.         set
  109.         {
  110.             SetValue(Name6Property, value);
  111.         }
  112.     }
  113.     public double Name7
  114.     {
  115.         get
  116.         {
  117.             return (double)GetValue(Name7Property);
  118.         }
  119.         set
  120.         {
  121.             SetValue(Name7Property, value);
  122.         }
  123.     }
  124.     public double Name8
  125.     {
  126.         get
  127.         {
  128.             return (double)GetValue(Name8Property);
  129.         }
  130.         set
  131.         {
  132.             SetValue(Name8Property, value);
  133.         }
  134.     }
  135.     public double Name9
  136.     {
  137.         get
  138.         {
  139.             return (double)GetValue(Name9Property);
  140.         }
  141.         set
  142.         {
  143.             SetValue(Name9Property, value);
  144.         }
  145.     }
  146.     public double Name10
  147.     {
  148.         get
  149.         {
  150.             return (double)GetValue(Name10Property);
  151.         }
  152.         set
  153.         {
  154.             SetValue(Name10Property, value);
  155.         }
  156.     }
  157.     public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  158.     public static readonly DependencyProperty Name1Property = DependencyProperty.Register("Name1", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  159.     public static readonly DependencyProperty Name2Property = DependencyProperty.Register("Name2", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  160.     public static readonly DependencyProperty Name3Property = DependencyProperty.Register("Name3", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  161.     public static readonly DependencyProperty Name4Property = DependencyProperty.Register("Name4", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  162.     public static readonly DependencyProperty Name5Property = DependencyProperty.Register("Name5", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  163.     public static readonly DependencyProperty Name6Property = DependencyProperty.Register("Name6", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  164.     public static readonly DependencyProperty Name7Property = DependencyProperty.Register("Name7", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  165.     public static readonly DependencyProperty Name8Property = DependencyProperty.Register("Name8", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  166.     public static readonly DependencyProperty Name9Property = DependencyProperty.Register("Name9", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  167.     public static readonly DependencyProperty Name10Property = DependencyProperty.Register("Name10", typeof(double), typeof(Person), new PropertyMetadata((double)55.55));
  168. }
  169. //public class Person
  170. //{
  171. //    public double Name { get; set; }
  172. //    public double Name1 { get; set; }
  173. //    public double Name2 { get; set; }
  174. //    public double Name3 { get; set; }
  175. //    public double Name4 { get; set; }
  176. //    public double Name5 { get; set; }
  177. //    public double Name6 { get; set; }
  178. //    public double Name7 { get; set; }
  179. //    public double Name8 { get; set; }
  180. //    public double Name9 { get; set; }
  181. //    public double Name10 { get; set; }
  182. //}
复制代码
}
[/code]
然后我们再循环一千万次

那么WPF的属性到底是如何节约内存的呢。因为CLR属性是在实例声明的时候就分配好了内存空间的。所以就算实例里面没有写入值,或者仍然是默认值,仍然会分配好内存空间。但是WPF的依赖属性不同。
所以依赖属性正在节约内存就在于这儿的依赖属性是一个static readonly 属性。所以不需要在对象每次实例化的时候都分配相关属性的内存空间,而是提供一个入口点。
6 - 依赖属性的回写和强制转换
  1. //注册依赖属性
  2. PropertyMetadata propertyMetadata = new PropertyMetadata();
  3. propertyMetadata.DefaultValue = Brushes.DeepSkyBlue;
  4. //属性值改变回写
  5. propertyMetadata.PropertyChangedCallback = ((s, e) =>
  6. {
  7.     Debug.WriteLine(String.Format("PropertyChanged - 属性:{0} 新值:{1} 旧值:{2}", e.Property.Name, e.NewValue, e.OldValue));
  8. });
  9. //强制转换
  10. propertyMetadata.CoerceValueCallback = (s, e) =>
  11. {
  12.     Debug.WriteLine(String.Format("CoerceValue - {0}", e));
  13.     return e;
  14. };
  15. <p>MyColorProperty =
  16. DependencyProperty.Register("MyColor", typeof(Brush), typeof(MyButton), propertyMetadata, (o) => {
  17. Brush brush = o as Brush;
  18. if (brush== Brushes.Yellow||brush== Brushes.Blue)
  19. {
  20. return false;
  21. }
  22. else
  23. {
  24. return true;
  25. }
  26. });</p>
复制代码
在写代码是都会考虑可能发生的错误。在定义属性时,也需要考虑错误设置属性的可能性。对于传统.NET属性,可以在属性的设置器中进行属性值的验证,不满足条件的值可以抛出异常。但对于依赖属性来说,这种方法不合适,因为依赖属性通过SetValue方法来直接设置其值的。然而WPF有其代替的方式,WPF中提供了两种方法来用于验证依赖属性的值。
1、ValidateValueCallback:该回调函数可以接受或拒绝新值。该值可作为DependencyProperty.Register方法的一个参数。
2、CoerceValueCallback:该回调函数可将新值强制修改为可被接受的值。例如某个依赖属性工作年龄的值范围是25到55,在该回调函数中,可以对设置的值进行强制修改,对于不满足条件的值,强制修改为满足条件的值。如当设置为负值时,可强制修改为0。该回调函数PropertyMetadata构造函数参数进行传递。

来源:https://www.cnblogs.com/iceamos/archive/2023/03/15/17218242.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具