Archive

Archive for the ‘Advanced’ Category

Creating a Custom Control

October 17, 2009 1 comment

First of all, I would like to stress that there’s a difference between a ‘user control’ and a ‘custom control’. A user control is simply put a compilation of other existing controls. And in terms of templating and styling it should also be considered as such, instead of a single control.

If you have the need for a single control that should have more features than any of the standard WPF controls offer, you have the option to create a custom control. (There’s also the option of ‘attached behaviors’, but that’s beyond the scope is this post)

Also note that Visual Studio makes the distinction between a User Control and a Custom Control. If you choose ‘Add New Item’ from the Project (right click) menu, there’s a ‘User Control (WPF)’ template and a ‘Custom Control (WPF)’ template to choose from in the WPF category. The Custom Control template will create some additional stuff for you that you might otherwise overlook.

NewItemTemplate

When you pick the ‘Custom Control (WPF)’ template, there are a couple of things that Visual Studio creates for you:

  • The new class 🙂
  • A ‘Themes’ folder with a file called ‘Generic.xaml’
  • It updates ‘AssemblyInfo.cs’ with a ‘ThemeInfo’ attribute.

Let’s take a look at these goodies!

The new class

Please note that the class, by default, inherits from Control, instead of UserControl!

The Control’s most important property is probably the Template property, because through this property the Control is the first element in the inheritance tree that supports a visualization by using a ControlTemplate.

Now how does WPF know what controltemplate to use for your (actually any) control? Well, it’s the only thing that Visual Studio already added to your class: a static constructor which overrides some metadata of the DefaultStyleKey dependency property that it inherits from FrameworkElement. It tells WPF to look for a style that’s created for your custom control’s type. And Visual Studio was so helpful to create that style as well…

Generic.xaml

The default style that Visual Studio created for your control can be found in Generic.xaml. It’s a ResourceDictionary that holds all the default styles for your custom controls and their related stuff, like brushes and converters. I would advise you to use merged dictionaries to split your stuff in more manageable parts as your project grows…

What Visual Studio generated for you is a very fancy controltemplate, consisting of … just a Border :-(.

<Style TargetType="{x:Type local:CustomControl1}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Bummer! That means you’ll still have a lot of work to do, depending on how complex your control will be. But, what you have now is fully compilable and if you would use your custom control in your xaml right now, you would see a perfectly good border :-).

But… how did WPF know where to find your control’s style? You only told it the type of your control in the DefaultStyleKey metadata override!?

ThemeInfo attribute

The ThemeInfo attribute in the AssemblyInfo.cs file tells WPF where to look for the default styles (the second parameter). The default setting tells WPF to look for the default styles in the SourceAssembly, meaning the same assembly which contains your custom control’s class.

If you already looked in the AssemblyInfo file you might have noticed that the comments with the parameters also speak of ‘theme-specific’ styles. They also imply that Generic.xaml is the last place to look for your control’s style! How does that work?

Any consumer of your control can create a new controltemplate for your control and place it for example in the Window.Resources section or the App.xaml resource dictionary. WPF will then use that controltemplate in that window only or for the whole application respectively. Your preciously crafted controltemplate in Generic.xaml will not be used in that situation.

If WPF can’t find any consumer created controltemplate for your control, it will look for a theme-specific one, if the first ThemeInfo parameter is set to a value other than None. A theme-specific style is a style that you can create, so that your control will fit in nicely with a certain Windows theme, like the Aero theme on Vista or Luna Blue on XP. I will talk about theme-specific styles in another post. For now, you only have to know that if there’s no window-, app-, or theme-specific style for your control, WPF will finally end up at the style in Generic.xaml and use that to create the look of your control.

What’s left?

Now that the easy stuff is done, what should be your next step? Well, the first step is the most important one: choose the right base class to inherit from! You didn’t think you’d be stuck with just the Control class, now did you? 🙂 Fortunately there are a lot of other classes to choose from and you should pick the class that already has as much as possible of the features you need and extend from there. (But sometimes it’s easier to pick a class that offers even more, when you can easily turn off stuff you don’t need.)

Some examples: pick an ItemsControl if you need to present a list of items. Skip the ItemsControl and pick a ListBox if your control needs to support selection of items as well. Choosing the right base class can save you a lot of work!

If you have the right base class, all you have to do is modify the style/controltemplate to your liking and add the extra features that you want to your class. There are a lot of tips, best practices and coding conventions I could give you in this stage, but this post is already long enough as it is.

I hope this post showed you enough to start making your own custom controls and there will be plenty more about this stuff in the future. So stay tuned!

Advertisements
Categories: Advanced Tags: