NoesisGUI

Custom Controls

Custom controls should be created to extend default controls functionality, in situations where modifying its style, template, dependency properties or triggers is not enough. To start with, the Control Authoring Overview (http://msdn.microsoft.com/en-us/library/ms745025.aspx) article is a must read for all control developers.

Below are some of the practices that are useful when creating custom controls.

Event-handling practices

  • Use RoutedEvents, Commands and CommandManager whenever possible.
  • Use TemplatePartAttribute:
  • Name the controls that are used inside the custom control with something like "PART_SubControlName". The PART_ prefix is a convention.
  • This is useful if you want your control to be styled using a Designer.
  • Specify the TemplatePartMetaData for the custom control class. This meta data indicates to template designers the type required for the named parts.
  • Override OnTemplateChanged() and check for existence of the subcontrols in use. Check using the FindName() method over the template root. If a part by that name is absent, throw an exception.
  • Attach event handlers on the sub control.

Theme (styles) practices

  • Create a ResourceDictionary for resources and styles used by your custom controls.
  • Organize multiple resources using MergedDictionaries.
  • Override the DefaultStyleKeyProperty for your custom controls:
NS_IMPLEMENT_REFLECTION(MyCustomControl)
{
    // ...

    const TypeClass* type = TypeOf<SelfClass>();
    Ptr<ResourceKeyType> defaultStyleKey = NsCreateComponent<ResourceKeyType>(type);

    Ptr<UIElementData> data = NsMeta<UIElementData>(type);
    data->OverrideMetadata<Ptr<ResourceKeyType>, FrameworkPropertyMetaData>(
        FrameworkElement::DefaultStyleKeyProperty, "DefaultStyleKey", type, defaultStyleKey);
}
  • Create a component that implements IControlLibrary and that has the ControlLibrary category. This component will indicate where to find associated resources for your custom controls:
class MyControlLibrary: public Core::BaseComponent, public Gui::IControlLibrary
{
public:
    /// From IControlLibrary
    //@{
    const NsChar* GetResourceFile(const NsChar* themeName) const
    {
        // Use the same resources for all themes
        return NST("Module/ControlLibrary/Resources.xaml");
    }
    //@}

    NS_IMPLEMENT_INLINE_REFLECTION(MyControlLibrary, Core::BaseComponent)
    {
        NsMeta<Core::TypeId>("MyControlLibrary");
        NsMeta<Core::Category>("ControlLibrary");
        NsImpl<IControlLibrary>();
    }
};
© 2017 Noesis Technologies