View this website on your mobile or tablet | Follow me on twitter @SyntaxArt

Archive for December, 2012

Overview

A toggle image button is similar to a button, combined with a check box.  When you press the button it will have an IsChecked property which will toggle with each subsequent press.  In this tutorial we will discuss creating a toggle button using images as its UI interface.

Download

You can download the full project source code here: ToggleImageButton

Development

Creating an image toggle button in WPF requires the developer to create a custom control.  Custom controls allow the visual design of the control to be separated from the functional part. In this tutorial I will be creating our control part in our code behind file (.cs) and the visual part in our xaml file (.xaml).

First create a wpf custom control using visual studio. This will set up the default files which are required to create the custom control. Name your custom control ToggleImageButton.xaml, this will generate a ToggleImageButton.cs file and a generic.xaml file, which will contain some basic xaml code for the visual part of your control.

In our Windows controls namespace (System.Window.Controls) you are able to derive from the Button class. You will inherit all of the Button properties and methods. As we would like the Toggle ability for this type of control we can us a primitive of this type.  This primitive is found in System.Window.Controls.Primitives namespace. This will enable us to bind to the IsChecked property of the ToggleButton. I will explain this property later on. We will now derive from this control and create our own dependency properties.

As we would like to toggle between two images on our control we should create two dependency properties to hold our Image Sources. Create two dependency properties called ActiveIcon and InActiveIcon. The code below is an example of how to create two dependency properties.

You can see that we have registered our dependency property as a type of ImageSource and this dependency will be found in out class which is type of  ToggleImageButton.  This property will require us to only use Bitmap or SourceUri references to the images which we would like to display on our button.

        private static readonly DependencyProperty ActiveIconProperty = DependencyProperty.Register("ActiveIcon", typeof(ImageSource), typeof(ToggleImageButton));
        private static readonly DependencyProperty InActiveIconProperty = DependencyProperty.Register("InActiveIcon", typeof(ImageSource), typeof(ToggleImageButton));

        /// <summary>
        /// Gets or sets the active icon dependency property.
        /// </summary>
        /// <value>
        /// The active icon.
        /// </value>
        public ImageSource ActiveIcon
        {
            get
            {
                return (ImageSource)GetValue(ActiveIconProperty);
            }
            set
            {
                SetValue(ActiveIconProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the in active icon dependency property.
        /// </summary>
        /// <value>
        /// The in active icon.
        /// </value>
        public ImageSource InActiveIcon
        {
            get
            {
                return (ImageSource)GetValue(InActiveIconProperty);
            }
            set
            {
                SetValue(InActiveIconProperty, value);
            }
        }

Once we have created our dependency properties we can then move onto creating our control template. Open the xaml file and you will see a <style> tag. The target type of this should be set to ToggleImageButton. You may need to prefix this with a namespace declaration, this has been set to local in this example.  A code snippet of this is below.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:SyntaxStudio.ToggleImageButton">

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

                    </Border>                   
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

We are now going to override the content template of the control style so that we can create our own view from the control. In our content template we will add an image control so that we can display the ActiveIcon and the InActiveIcon on demand. Set the source of the image control to the InActiveIcon dependency property as its default.

When the button is toggled the IsChecked property will become true.  When this parameter is true we want to change the icon of the button to the active state.  A trigger gives us the ability to bind to properties and alter the UI according to the condition.  We will now create two trigger conditions which will change the image of the control when the button is toggled.  To get a reference to the Image UI element you can give the control an x:Name value, it is good practice to name any UI element which you wish to reference with a prefix of PART_.  You can see from the trigger below that the condition is to listen to the IsChecked state of the ToggleButton and change the Source property of the Image control named PART_Icon.

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

                        <Image x:Name="PART_Icon"
                               Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=InActiveIcon}" 
                               Width="{TemplateBinding Width}" 
                               Height="{TemplateBinding Height}" />
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter TargetName="PART_Icon" Property="Source" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActiveIcon}" />
                        </Trigger>
                        <Trigger Property="IsChecked" Value="False">
                            <Setter TargetName="PART_Icon" Property="Source" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=InActiveIcon}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Once we have finished creating our custom control we can now instantiate the control to see if it works. Its is good measure to test your control in a window or some other form of unit testing before integrating into your production application.

To instantiate you control make a reference to the namespace of your custom control. If the custom control is local to your test view use the local namespace declaration as described above. Once you have declared your namespace you can instantiate your control with the following.

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/SyntaxStudio.ToggleImageButton;component/Themes/Generic.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <local:ToggleImageButton InActiveIcon="{DynamicResource Play}"
                                 ActiveIcon="{DynamicResource Pause}"
                                 Width="46"
                                 Height="46" />
    </Grid>

You can see that in the above I am using a DynamicResource declaration to reference my image file. I have done this so that we can change the image at its location without having to change the code here in the future. This is an important point when theming your application.  I have saved my images as BitmapImage in the Generic.xaml file with their associated Uri paths.  The x:Key maps the UriSource path with the name.

    <BitmapImage x:Key="Play" UriSource="/SyntaxStudio.ToggleImageButton;component/Images/play.png" />
    <BitmapImage x:Key="Pause" UriSource="/SyntaxStudio.ToggleImageButton;component/Images/pause.png" />

Please feel free to download the example code and read this tutorial again to get a better understanding. The project will compile and run so that you can test out the control and debug it.

Thanks for reading.