Archive

Archive for October, 2009

The Three-State CheckBox

October 21, 2009 2 comments

In my previous post I explained why you should use the ‘CustomControl (WPF)’ template from the Add New Item dialog when you want to create a custom control. But of course there’s an exception to this rule! When you only want to make (minor) changes to the functionality of a base control, you don’t always need the stuff that Visual Studio generates for you. That stuff is generated so you can create your own presentation (ControlTemplate) for your control. But what if you only want to change the logic?

Consider the following scenario:

Some people want to use the CheckBox’s ‘Indeterminate’ state as a representation for ‘the user hasn’t made a choice yet’. And if you’re like me, if I click on a checkbox I expect it to go into its Checked state. And if you combine these facts you might find it annoying that when you click on an Indeterminate checkbox, it turns Unchecked, instead of Checked.

Now, can we fix this without all the stuff that Visual Studio generates for you? After all, we don’t want to change the presentation of the checkbox or its states, just the sequence order of the states. The answer is: yes, of course we can!

In this case we don’t use the ‘CustomControl’ template, but we just add a new Class to our project. Taking this road, we don’t have the automatically generated static constructor with the DefaultStyleKey override in our class, but that’s fine, because in our scenario we explicitly don’t want an override to tell WPF to use a custom control template. We just want the standard control template to be used.

Now we only have to make our class inherit from the standard CheckBox and implement our modification:

public class CustomThreeStateCheckBox : CheckBox
{
    public CustomThreeStateCheckBox()
    {
        // Always start in the 'Indeterminate' state
        base.IsChecked = null;
    }

    protected override void OnToggle()
    {
        // Change the sequence from: Unchecked - Checked - Indeterminate
        // to: Indeterminate - Checked - Unchecked
        if (this.IsChecked == false)
        {
            this.IsChecked = this.IsThreeState ? null : ((bool?)true);
        }
        else
        {
            this.IsChecked = new bool?(!this.IsChecked.HasValue);
        }
    }
}

Another example of a ‘semi-custom’ control could be a numeric TextBox. If you just want to ignore any character that cannot be parsed to a double, this simple class might be all you need:

public class NumericTextBox : TextBox
{
    protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
    {
        // Ignore any character that fails to parse to a double
        double value;
        if (!Double.TryParse(e.Text, out value))
            e.Handled = true;
        base.OnPreviewTextInput(e);
    }
}

The advantage of these kinds of custom controls is that it’s less work and they will respect the Windows theme your application is running in, without having to create several different theme-styles for them.

So, every time you’re about to create a custom control, take the time to check if you really need a new control template, because it’s time well spent!

Download source code.

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!

Categories: Advanced Tags:

Important concepts of the ItemsControl

October 11, 2009 Leave a comment

The ItemsControl is the most versatile control in the WPF toolbox. This control, or one of its descendents like the ListBox, is so flexible in combination with custom controltemplates, datatemplates and panels that it can be used in countless situations. Well, countless… Dr. WPF has a great article with a test that you really should try!

Since the good doctor is the real specialist here when it comes to the ItemsControl, I just want to explain the basic concepts, because I noticed that a good number of questions on the WPF Forum wouldn’t have been asked if people new this.

There are enough examples on the internet that deal with directly adding items in xaml, so in the rest of this article I’m only going to talk about situations where the ItemsControl will get its items through DataBinding.

One of the key things to know about the ItemsControl is that every data item in your collection will get wrapped in another control. In case of an ItemsControl this is just a ContentPresenter, in case of ListBox or ComboBox it’s a ListBoxItem or ComboBoxItem respectively; both descendents of ContentControl.

What some people seem to forget is the fact that the ItemsControl sets the value of the wrapper’s DataContext property to the data item itself. Without this the use of datatemplates would not have been possible, because it’s the DataContext that is inherited from the wrapper down to every element inside the datatemplate!

ItemsControlConcepts.png

Now this DataContext inheritance is also the solution to a fairly common question on the WPF forums. For example, you want a delete-button in your datatemplate to give the user on every item the option to delete that item. In your click-event handler (or better, a command handler) you need access to the data item that should be deleted. The ‘sender’ parameter in the handler will be equivalent with the Button element, because that’s the element that you clicked. So how to get to the data item? You’ll probably know by now that you can find it in the DataContext property of the ‘sender’! Just cast ‘sender’ back to a Button (or just a FrameworkElement) and cast the value of its DataContext property to your data item!

private void DelButton_Click(object sender, RoutedEventArgs e)
{
    Button delButton = sender as Button;
    Person person = delButton.DataContext as Person;
    _people.Remove(person);
}

If you want to take a look at the testproject, please make sure to rename its extension to .zip.

Categories: Beginner Tags: , ,