NoesisGUI

DependencyProperty

Introduction

The purpose of dependency properties is to provide a way to compute the value of a property based on the value of other inputs. These other inputs might include system properties such as themes and user preference, just-in-time property determination mechanisms such as data binding and animations/storyboards, multiple-use templates such as resources and styles, or values known through parent-child relationships with other elements in the element tree. In addition, a dependency property can be implemented to provide self-contained validation, default values, callbacks that monitor changes to other properties, and a system that can coerce property values based on potentially runtime information. Derived classes can also change some specific characteristics of an existing property by overriding dependency property metadata, rather than overriding the actual implementation of existing properties or creating new properties.

Implementation

Noesis Engine implements dependency property system over reflection metadata support. Every dependency object stores its dependency properties inside a reflection TypeMetaData derived class, the DependencyData. This class provides functionality to register dependency properties associated with a reflection type.

To create a new derived DependencyObject class we begin defining the public dependency properties it will have:

// DelayedButton.h

////////////////////////////////////////////////////////////////////////////////////////////////////
class DelayedButton: public Button
{
public:
    /// Dependency properties
    //@{
    static const DependencyProperty* DelayProperty;
    //@}
};

Then we must register the property in the dependency system:

// DelayedButton.cpp

////////////////////////////////////////////////////////////////////////////////////////////////////
NS_IMPLEMENT_REFLECTION(DelayedButton)
{
    Ptr<DependencyData> data = NsMeta<DependencyData>(TypeOf<SelfClass>());
    data->RegisterProperty<NsFloat32>(DelayProperty, "Delay", PropertyMetaData::Create(1.0f));
}

The previous code does three things:

  • NsMeta creates a metadata associated with the reflection of DelayedButton class, that would be used by dependency system to look for dependency properties registered by this class.
  • RegisterProperty creates a property in the dependency system named "Delay", with a default value of 1.0f, and it is associated to DelayedButton class.
  • RegisterProperty also assigns the created property to the DelayProperty public member.

After this we can use that class from a xaml like this:

<DelayedButton Delay="1.5"/>

Or in code:

Ptr<DelayedButton> btn = NsCreateComponent<DelayedButton>();
btn->SetValue<NsFloat32>(DelayedButton::DelayProperty, 1.5f);

The function SetValue is a templated method of DependencyObject that sets the local value of the specified dependency property in the object. To make it easier to modify and access dependency property values, we usually wrap them with getter/setter methods in the owner class (we omit the above code to make it more clear):

// DelayedButton.h

////////////////////////////////////////////////////////////////////////////////////////////////////
class DelayedButton: public Button
{
public:
    /// Gets or sets button click delay in seconds
    //@{
    NsFloat32 GetDelay() const;
    void SetDelay(NsFloat32 delay);
    //@}
};

// DelayedButton.cpp

////////////////////////////////////////////////////////////////////////////////////////////////////
NsFloat32 DelayedButton::GetDelay() const
{
    return GetValue<NsFloat32>(DelayProperty);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
void DelayedButton:SetDelay(NsFloat32 delay)
{
    SetValue<NsFloat32>(DelayProperty, delay);
}

// in use...
Ptr<DelayedButton> btn = NsCreateComponent<DelayedButton>();
btn->SetDelay(1.5f);

As we see in the example, dependency properties can have extra information associated with a reflection type. This metadata is stored in a PropertyMetaData object.

WPF Compatibility

http://msdn.microsoft.com/en-us/library/system.windows.dependencyproperty.aspx


Methods:
Name Sup Comments
AddOwner Yes Implemented as DependencyData::AddOwner
GetMetadata Yes  
IsValidType No  
OverrideMetadata Yes Implemented as DependencyData::OverrideMetadata
Register Yes Implemented as DependencyData::RegisterProperty
RegisterAttached No Current implementation treats attached properties as normal dependency properties
RegisterAttachedReadOnly No Current implementation treats attached properties as normal dependency properties
RegisterReadOnly Yes Implemented as DependencyData::RegisterPropertyRO

Properties:
Name Sup Comments
DefaultMetadata No  
GlobalIndex No  
Name Yes  
OwnerType Yes  
PropertyType Yes  
ReadOnly Yes  
ValidateValueCallback Yes  
© 2017 Noesis Technologies