WPF-Property Systems (4 of 4)

Source: Internet
Author: User

Override of dependency property

In C #-based programming, overriding a property is often an effective solution: we need to redefine the accessor of a property when the property accessor implementation provided by the base class does not meet the current requirements.

However, for dependency properties, the redefinition of the property execution logic does not exist in the CLR property wrapper: WPF internal implementation of dependency properties requires that the CLR wrapper implementation of a dependency property simply calls GetValue () and the SetValue () property, rather than providing additional custom logic. Instead, we need to specify custom attribute execution logic by changing the metadata passed in at creation time, and even under some more demanding requirements, such as changing the type of a dependency property, redefining a dependency property with the same name.

Overriding a dependency property is straightforward. If a type inherits a dependency property from its base class, the software developer can finish overwriting the property metadata in the derived class through the OverrideMetadata () method. When overriding metadata, the system merges or replaces the new metadata with the information from the previous dependency property metadata:

1) Merge Propertychangedcallback.

2) Replace the DefaultValue.

3) Replace the Coercevaluecallback implementation.

4) Merge ValidationCallback.

5) for Frameworkpropertymetadata, the FRAMEWORKPROPERTYMETADATAOPTIONS flag combination is a bitwise OR operation.

The operations mentioned here are divided into two main types: merge and Replace. Here, merging means that all assignments to that composition in the inheritance hierarchy of the type will be preserved. When the composition is required, the WPF property system calls the composition in turn, according to the type's inheritance hierarchy. Instead, the substitution means that the current declaration of that composition will completely replace the component declared in all of its base classes. Next, the WPF property system simply invokes the composition declared by the highest-level type in the type inheritance hierarchy.

Now let's take a look at the reasons for merging or replacing each component in the metadata. The first thing to discuss is propertychangedcallback. What this callback does is refresh other dependency properties that the type contains when a dependency property has changed. Of course, this logic is the most normal idea to implement in the type of a dependency property declaration: Calling the function in the same type, refreshing other dependency property values guarantees that the type instance is in a normal state.

When the property changes, the system will first invoke the Propertychangedcallback callback set in the highest-level derived class and call each base class in turn to implement each callback provided along the type hierarchy. As the instance code in the previous sections shows, these callbacks are often updated by calling CoerceValue to complete other associated dependency properties. With this series of callbacks, each type in the inheritance hierarchy of that type will be in a normal state.

The substitution of DefaultValue is very easy to understand: Because a property cannot have more than one default value at a time, replacing the default value declared in the base class with the new default value is a very normal choice.

The next is coercevaluecallback. When the dependency property changes, the property system will only invoke the coercevaluecallback of the most direct metadata. This is because the Coercevaluecallback callback in the base class does not understand the individual properties in the derived class, so once a new coercevaluecallback callback is defined, the logic defined in the base class will no longer be appropriate to constrain the value of the dependency property.

The next component to be discussed is the ValidationCallback callback. Since this function is passed in when the property is registered, it is not stored in the property system as data stored in the metadata. Therefore, it cannot be overwritten by the new property registration. The reason for not adding it to the metadata at the same time: In case of overwriting, it is also necessary to rewrite all the logic in the original ValidationCallback callback.

The last one to be explained is the processing of the metadata option. All metadata options are merged when you manipulate the individual metadata options recorded by the OverrideMetadata () method. Of course, one of the things here is to eliminate the meta-data options that you set earlier. When this is required, we need to set the property of the metadata option to false. For example, a software developer can set a dependency property in metadata that cannot be bound by a notdatabindable tag. However, if you need to clear this option through the OverrideMetadata () function, the software developer will need to set the Isnotdatabinable property to false on the incoming metadata.

Of course, the OverrideMetadata () function is just a way to reuse the original dependency property. Another way to reuse is Addowner (). This function adds dependency properties from other types to the current type. The signature of the function is as follows:

 Public DependencyProperty AddOwner (Type ownertype, PropertyMetadata typemetadata);

This function is used to add a DependencyProperty to the type represented by ownertype and can change the behavior of the dependency property by Typemetadata.

When using markup of the DependencyProperty type that flags the dependency property, it is best to use the dependency property tag returned by the Addowner () function instead of the dependency property tag that was saved in the original registered type. The main purpose of doing this is more semantic-based considerations. In fact, the result of the operation returned by the dependency property tag returned by the original dependency property tag and Addowner () is the same.

Significantly different from the OverrideMetadata () function, the function does not inherit the metadata of the original property. So when using the Addowner () function, the most thing a software developer needs to consider is whether or not to specify the metadata for the new attribute. Of course, if the software developer calls Addowner on the base class's dependency object, the metadata will be inherited and merged with the new meta-data.

dependency property of a reference type

Implementing a dependency property of a reference type is no different from the steps to implement a normal dependency property: Define a CLR property wrapper and complete the get and set of the dependency property value through GetValue () and the SetValue () function in the property wrapper. The only one by one point is that a software developer should not provide a default value for a dependency property when it is registered, but instead explicitly assign a value to the dependency property in the initialization function of the type.

Why did you do it? This is because in this case, the reference type dependency property on multiple instances may return an instance of the same reference type. The cause of this problem is generated by the combination of the two attributes of the dependency property: 1. In the absence of an assignment, the value returned by a dependency property is the default value passed in when the dependency property is registered. 2. The value passed in during dependency property registration is actually a reference to the instance of the reference type and will be the default value for all of that dependency property, pointing to the same reference type instance.

Therefore, when implementing a dependency property of a reference type, we need to explicitly assign a value to the dependency property of the reference type in the constructor. In this case, you have two options: first to see if the type of the dependency property is a custom type, and can be changed from class to struct. If not, the default value is marked Null in the dependency property registration process, and it is set to the desired default value in the constructor.

The first approach is very common in WPF implementations. Take the padding attribute of the control class as an example:

 Public Static ReadOnly DependencyProperty paddingproperty = DependencyProperty    . Register ("Padding"typeoftypeof(Control),         New Frameworkpropertymetadata (new  Thickness (),        frameworkpropertymetadataoptions.affectsparentmeasure));

The above code registers a dependency property of type thickness, paddingproperty, and passes a default value in the metadata for that property. When you look at the definition of a thickness type, you can see that it is actually a struct. In C #, the structure is allocated on the stack, preventing multiple instances of the same reference type being referenced by the UI element in which the property resides.

But things can't always be so lucky. First, the type of the dependency property may not be a user-defined type, so we don't have the opportunity to convert it to a struct. In addition, a type may contain very much information, in which case it is not appropriate to implement a type as a struct. So when you have to create a dependency property of a reference type, we need to assign a value to the property in the constructor. For example, ItemsControl provides a Itemspanel dependency property. If the dependency property is initialized by a constructor, the function call that creates the dependency property and the constructor definition will look like the following code:

 public  static  readonly  DependencyProperty itemspanelproperty = DependencyProperty. Register (  itemspanel   ", typeof  (itemspaneltemplate), typeof   (ItemsControl),  new  Frameworkpropertymetadata (null   public   ItemsControl () {SetValue (Itemspanelproperty,    StackPanel ());  

However, this violates WPF's best practices for dependency property container type constructor definitions. Software developers can set callback functions for dependency properties during the registration of a dependency property, and during a derived class's override of the property. These callback functions are executed at the same time, each time the dependency property has changed. Because these callback functions are triggered in the constructor of the base class, the functions that they call may be overridden by derived classes, so the execution of these functions may be in a situation where the derived class is not fully initialized.

To avoid this problem, WPF presents a standard for defining a safe constructor:

1. Provide a default constructor for your type:

Public Myclass:somebaseclass {

Public MyClass (): base () {

Initialization of all members, including data members or callback functions that may be assigned by other constructors

Data members that will be used



2. If a type provides a non-default constructor, the constructor first needs to call the type's default constructor, and then use functions such as SetValue () to set the value of each dependency property.

Public Myclass:somebaseclass {

Public MyClass (Object toSetProperty1): this () {

Note that the default constructor is called instead of the constructor of the base class

Property1 = toSetProperty1;



Just who can guarantee that the user is familiar with these rules and write the types according to these rules when writing custom types?

If the type of the dependency property is a collection, the other point to note is that the XAML parser does not know how to invoke a generic function. That is, if the type of a dependency property is List<t>, then WPF does not know how to call list<t>. ADD (T Item), and only know how to invoke non-generic interface members. So if a software developer wants a property to be a collection, the collection type needs to implement a non-generic IList interface, such as collection<t> or list<t>.

And when implementing a property of a collection type, whether it is implemented as a read-only dependency property or a read-write dependency property affects how the property is used in XAML. Take the following two types of XAML markup as an example:

<Toolbar>  <Toolbar.items>    <ToolbarItem.../>  </Toolbar.items></Toolbar><Toolbar>  <Toolbar.items>    <toolbaritemcollection>      <ToolbarItem/>    </toolbaritemcollection>  </Toolbar.items></Toolbar>

Of course, the above XAML code is only used as an example, not the actual WPF code. Suppose the toolbar type here has an items property, which is used to record all child elements of the ToolbarItem type. When XAML parses the first piece of XAML, WPF first invokes the get accessor of the Toolbar.items property , and then adds the child elements declared in the section XAML to the Items property is recorded in the collection. When parsing the second piece of XAML, WPF will first create a toolbaritemcollectionand add all the child elements to the collection. After the collection has been created, WPF invokes the set accessor of the Toolbar.items property to set the collection to the value of the Toolbar.items property.

Reprint please specify the original address: http://www.cnblogs.com/loveis715/p/4343374.html

Commercial reprint please contact me in advance:[email protected], I will only ask to add the author name and blog Home link.

WPF-Property Systems (4 of 4)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.