WPF dependency properties and dependent objects

Source: Internet
Author: User

Before I introduce the dependency properties, let me introduce the history of the properties

Attribute history: Early C + + classes, only fields and methods, exposing the data is the method, but the direct exposure of the field is not safe, so the method to expose, in the setting of the time to add some constraints, in MFC is the case. However, in order to access a field, there are always set up and get two methods, too fragmented, not conducive to management.     So the concept of attributes is introduced in C #, and later WPF introduces dependency properties, which can save the memory overhead of an instance, and can be relied upon on other objects through binding. Note: A field is a memory overhead for each instance, and a property is like a method (which can be deserialized to view, which is actually two methods, which means that the property is just a syntax icing), whether it is a static method or an instance method, with only one memory overhead. If there are no default fields for the property, the compiler will add one itself. The dependency property looks at what the dependency property is and how the dependency property is used:
1   /// <summary>2     ///the interactive logic of MainWindow.xaml3     /// </summary>4      Public Partial classMainwindow:window5     {6          PublicMainWindow ()7         {8 InitializeComponent ();9         }Ten  One         Private voidBtnclick_click (Objectsender, RoutedEventArgs e) A         { -Mydependencyobject MYDP =NewMydependencyobject (); -Mydp.setvalue (Mydependencyobject.flagproperty, This. Txt1. Text); theTxt2. Text = (string) Mydp.getvalue (mydependencyobject.flagproperty); -         } -     } -  +      Public classMydependencyobject:dependencyobject -     { +          Public Static ReadOnlyDependencyProperty Flagproperty = ADependencyproperty.register ("Flag",typeof(string),typeof(Mydependencyobject)); at  -}
View Code

From the above example, we can know that the dependent object is the host of the dependency property, in order to form the complete binding target is driven by the data.

Where DependencyObject is a base class with a fairly low level of WPF, all UI controls are inherited with it. It is also inherited and Dispatchobject.

That is, all UI controls, in WPF, properties are dependency properties.

In addition, as can be seen from the above example, mainly consists of three parts:

1) Register dependency properties (there are other overloaded methods):

Dependencyproperty.register (string name, type PropertyType, type ownertype)

The first parameter is the name of the registered property (the name is the same as the name of the CLR property to be wrapped in the future), the second parameter is the return type of the property, and the third is the type of the pinned class for the property.

It is important to note that the object name of this dependency property is usually more than the registered name, which is a latent rule, although it can also be used for other values.

Also registered dependency property objects are public static readonly.

2) The SetValue method of the dependent object.

The first parameter is the name of the object (with the property suffix) of the registered dependency attribute, and the second is the value of the dependency property to set.

3) The GetValue method of the dependent object.

The parameter is the name of the object (with the property suffix) of the registered dependency attribute.

Speaking of which, let's put aside for the time being, let's first look at what the properties of a generic UI control look like:

For example, the TextBox.Text property, which is a CLR attribute, what is the relationship to the dependency property, originally in the Text property inside, also called the SetValue, GetValue method,

A type conversion (string type) is also performed, which is equivalent to exposing the dependency property to the outside world as an instance attribute, so that a dependency property becomes the path to the data source.

Let's look at the textbox to set the binding method, it has a setbinding method, is actually called in the internal Bindingoperations.setbinding method, which also shows that Microsoft wants to be able to

Sets the bound object when the UI object. When we construct our own dependent objects, we can also construct a setbinding method to facilitate the invocation.

If you use Bindingoperations directly:

Mydependencyobject Mydpo = new Mydependencyobject ();
private void Directlybinding ()
{
Bindingoperations.setbinding (MYDPO, Mydependencyobject.flagproperty, New Binding ("Text") {Source = txt1});
Bindingoperations.setbinding (Txt2, Textbox.textproperty, New Binding ("Flag") {Source = Mydpo});
}

Note that the first sentence of setbinding is to bind the Txt1 text CLR property to the Flagproperty dependency property of the Mydpo dependent object.

The second sentence of SetBinding is to bind the MYDPO flag CLR property to the Textproperty dependency property of the Txt2 dependent object.

In particular, the second parameter must not be mistaken, it is the dependency property in the first parameter.

In addition, this Mydpo object cannot be placed inside the local variable, otherwise it will not reach the effect.

Also, if I have entered a character in the txt2 beforehand, the input character in the TXT1 will not be updated to TXT2, do not know why?

From the above we can see that the CLR attribute is actually a dependency property of the spokesperson, there is no such spokesperson, dependency properties are present.

Why is it that the dependency property does not implement the INotifyPropertyChanged interface, and the binding object associated with it can still be notified when the value of the property is changed? Why is dependency property inherently a qualified data source?

In addition, when the dependency property is registered, finally there is a fourth parameter, which is not listed here, what can it do?

What is the advantage of a dependency property over a CLR attribute, and why is it possible to save memory overhead, and why is it possible to rely on a binding dependency on other objects (WinForm)?

With these doubts, we dig deeper into the secret of dependency property dependent objects.

Digging deeper:

First of all, from the registration dependency property, when registering, where is the registration?

By delving into the source code, it is found that the most central place is a function (static method of DependencyProperty):

private static DependencyProperty Registercommon (string name, type PropertyType, type ownertype, PropertyMetadata Defaultmetadata, Validatevaluecallback Validatevaluecallback)
{
Fromnamekey key = new Fromnamekey (name, ownertype);
Lock (Synchronized)
{
if (Propertyfromname.contains (key))
{
throw new ArgumentException (SR. Get (SRID. propertyalreadyregistered, name, Ownertype.name));
}
}
....
Create Property
DependencyProperty DP = new DependencyProperty (name, PropertyType, OwnerType, Defaultmetadata, Validatevaluecallback);

Build Key
Lock (Synchronized)
{
Propertyfromname[key] = DP;
}
......
return DP;
}

Where: private static Hashtable propertyfromname = new Hashtable ();

When we register a dependency property, we generate a hashcode by Fromnamekey (by registering the name XOR the host), construct a dependency property, and save it to Propertyfroamname.

Hash table, which also checks whether the dependency property is unique.

Inside the constructor of the dependency property:

Private DependencyProperty (string name, type PropertyType, type ownertype, PropertyMetadata defaultmetadata, Validatevaluecallback validatevaluecallback)
{
This._name = name;
This._propertytype = PropertyType;
This._ownertype = ownertype;
This._defaultmetadata = Defaultmetadata;
This._validatevaluecallback = Validatevaluecallback;
Dependencyproperty.flags Flags;
Lock (dependencyproperty.synchronized)
{
Flags = (dependencyproperty.flags) dependencyproperty.getuniqueglobalindex (ownertype, name);
DEPENDENCYPROPERTY.REGISTEREDPROPERTYLIST.ADD (this);
}
if (Propertytype.isvaluetype)
{
Flags |= DependencyProperty.Flags.IsValueType;
}
if (PropertyType = = typeof (object))
{
Flags |= DependencyProperty.Flags.IsObjectType;
}
if (typeof (Freezable). IsAssignableFrom (PropertyType))
{
Flags |= DependencyProperty.Flags.IsFreezableType;
}
if (PropertyType = = typeof (String))
{
Flags |= DependencyProperty.Flags.IsStringType;
}
This._packeddata = flags;
}

where the Getuniqueglobalindex () method allows us to obtain a unique index number of the dependency property, and then adds the dependency property to the Registeredpropertylist list, which is a static member;

Internal static itemstructlist<dependencyproperty> registeredpropertylist = new itemstructlist< Dependencyproperty> (768);

Once the registration is complete, a dependency property instance is registered in a global Hashtable (guaranteed uniqueness by name and host), and each dependency property has a unique index number to represent, then the next

How the SetValue and GetValue of dependent objects are used to save and read values with this dependency property instance.

It is natural to follow the GetValue method of the dependent object:

public Object GetValue (DependencyProperty dp)
{
Base. VerifyAccess ();
if (DP = = NULL)
{
throw new ArgumentNullException ("DP");
}
return this. Getvalueentry (this. LookupEntry (DP. Globalindex), DP, NULL, requestflags.fullyresolved). Value;
}

With an instance of the dependency property, we can get the corresponding value of this instance, the key is the last return of the sentence, which used the DP. Globalindex.

Where DependencyObject has an array of effectivevalueentry[] _effectivevalueentry, this variable holds the value and index (that is, Globalindex), via DP. Globalindex we can get the corresponding effectivevalueentry, whose value is what we are looking for. If the array does not contain this value, it returns the default value of the dependency property, which is provided by Defaultmetadata.

The mystery of the SetValue method, similar to GetValue, is that we must also store the value in the Effectivevalueentry array.

Here, let me give you an example of a dependency object class A that declares 10 dependent objects, A has 5 dependency properties registered, another dependent object class B declares 8 dependent objects, and B registers 4 dependency properties.

Then after AB is registered, DependencyProperty's static members Propertyfromname and Registerpropertylist have 5+4=9 members.

In a declaration of the 10 dependent objects, each dependent object will have effectivevalueentry this collection, that is to say, each object has the ability to access 5 values, that is, each object can open 5 room access value.

The same is true of the 8 dependent objects that each object has the ability to access 4 values, each of which has the same index of access values, meaning that the B1 object and the B2 object have the same index for the same dependency property.

Assuming that the first object of a A1 set the value of 3 dependency properties, then the object A1 effectivevalueentry only 3 members, and the other objects that do not have the value of the dependent property, their effectivevalueentry are not members.

In the past if the use of properties, then the total memory cost (assuming that each field consumes 1 bytes), 10*5+8*4 = 82 bytes, then now because only set the 3 property values of an object, then actually only consumes 3 bytes, so this also explains why the dependency property can save space reasons. , in exchange for space in time.

Summarize:

So far, we know that dependent objects are closely related to dependency properties, and we know why it is possible to save space, all UI control properties are dependency properties, so if we want to write our own controls, dependency properties are essential to write, and we know the underlying principle of dependency properties. Next time it will not be so hard to write, but also the registration of the last parameter there is no explanation, I believe it is not difficult, here is skipped. The example is not included.

WPF dependency properties and dependent objects

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.