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

Blog

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.

How to create the Prism Bootstrapper

First of all the Prism Bootstrapper is the starting point of the application.  Here you will instantiate the objects which are required for Prism to execute and support your application.  Once you have implemented your bootstrapper, the Run() method will be called and the bootstrapper will begin executing.  An example of the following discussion will be provided for you to download.  You can either download the Bootstrapper class or the full project below.

You will need Visual Studio 2010 or the Visual Studio Express development environment to implemented the following.

To use Prism you will need to create a reference to the following libraries:

  • Microsft.Practices.Prism
  • Microsft.Practices.Prism.Interactivity
  • Microsft.Practices.Prism.UnityExtensions
  • Microsft.Practices.ServiceLocation

These DLL libraries can be found in the Prism download at Patterns & Practices – Prism V 4.1, alternatively you can use Manage NuGet Packages directly in Visual Studio to acquire the Prism package.

The AppBootstrapper.cs class object

Create a class object called AppBootstrapper and derive from UnityBootstrapper, this will enable you to override the bootstrapper methods and inherit the correct properties and methods.

The full class object which is discuss below can be downloaded here: AppBootstrapper.cs.  You can download the full project example here Prism Bootstrapper Solution.  There are some extra features developed in the project which is purely to get a working example of Prism and to display a Shell.  You can ignore these extras and just focus on creating your bootstrapper and displaying your Shell.

public class AppBootstrapper : UnityBootstrapper
{
...
}

Once you have created your AppBootstrapper object you can now override the CreateModuleCatalog() method. This method will configure our catalog of modules for the application. For the purpose of modularization we will be creating modules for each section of our application. For now just return new ConfigurationModuleCatalog(), this will read the application modules configuration from the application App.config.

protected override IModuleCatalog CreateModuleCatalog()
{
    return new ConfigurationModuleCatalog();
}

It is now important to register our types with our IOC (Inversion of Control) container.  This will allow object coupling at runtime by an assembler object whereby the object is not known at compile time.  If we override the ConfigureContainer() method here we can register our types.  To register a type first you must pass in the interface and then the type which inherits the interface.  I will not explain at this stage why it is important to register objects and their interfaces at this point in this article. This will be covered in detail later.

protected override void ConfigureContainer()
{
base.ConfigureContainer();

RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true);
RegisterTypeIfMissing(typeof(IModuleInitializer), typeof(ModuleInitializer), true);
RegisterTypeIfMissing(typeof(IModuleManager), typeof(ModuleManager), true);
RegisterTypeIfMissing(typeof(RegionAdapterMappings), typeof(RegionAdapterMappings), true);
RegisterTypeIfMissing(typeof(IRegionManager), typeof(RegionManager), true);
RegisterTypeIfMissing(typeof(IEventAggregator), typeof(EventAggregator), true);
RegisterTypeIfMissing(typeof(IRegionViewRegistry), typeof(RegionViewRegistry), true);
RegisterTypeIfMissing(typeof(IRegionBehaviorFactory), typeof(RegionBehaviorFactory), true);
}

There are two other methods which can be overridden in the AppBootstrapper class these are; ConfigureRegionAdapterMappings() and ConfigureDefaultRegionBehaviors().  These two functions are very useful when adding region context to UIElements.  Again this is out of scope for this article.

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
...
}

protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
{
...
}

The next method is very important, this method will create our shell object. The shell object can be seen as the most outer-container or our visual root item of the application; i.e the shell. To enable us to create the shell we first need to instantiate an object to the RegionManager. The region manager allows us to register our views to a particular region within our region manager. Once a view has been registered to that region this is where it will be visible when activated.

protected override DependencyObject CreateShell()
{
IRegionManager regionManager = Container.Resolve();
regionManager.RegisterViewWithRegion(RegionNames.ShellRegion, typeof(MainWindowView));
regionManager.RegisterViewWithRegion(RegionNames.ClientRegion, typeof(DockingLayoutView));

return ServiceLocator.Current.GetInstance();
}

In order for your regions to work, you will need to register your regions with specific UIElement controls.  Prism has built in region adapters which can be attached to UIElement ContentControl.  To attach a prism region to the control you will first need to create a view.  Create a ShellView.xaml file and declare the following namespace;  “xmlns:region=”clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism”.  Once you have declared the namespace you are then able to attach the region to the content control. This will allow you to host views within this region.  See below for the following code.  You must give you region a name, this is used to reference the region in the region manager.  In the code below a static class has been created to hold the region name.

ShellView.xaml code
<Window x:Class="Orcas.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:region="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism"
xmlns:core="clr-namespace:Orcas.Core;assembly=Orcas.Core"
mc:Ignorable="d"
d:DesignHeight="700"
d:DesignWidth="1000"
WindowStartupLocation="CenterScreen">

<Grid x:Name="AppRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<ContentControl region:RegionManager.RegionName="{x:Static core:RegionNames.ShellRegion}" />
</Grid>
</Window>

Our final function will initialize our Shell view in the application and display it. In the create shell function we resolve our RegionManager and register our MainWindowView with the ShellRegion. Now we take our Shell parameter which has been instantiated in our base object (UnityBootstrapper) and we cast this over to the application MainWindow object to display.

protected override void InitializeShell()
{
Application.Current.MainWindow = (Window)Shell;
Application.Current.MainWindow.Show();
}

Introduction to PRISM

Categories: PRISM
Comments: No

Why use PRISM?

When designing and developing software it is important that your approach involves developing the architecture as loosely coupled modules or components.  Prism assists these loosely coupled components, instantiating, delivering and communicating between the application modules.  Prism can help developers design feature rich, maintainable and flexible applications.  WPF has adopted the MVVM (Model View – View – Model) pattern, prism 4.0 co-operates with this pattern and helps the developer to manage the modules and navigation whilst using the MVVM pattern.

Prism should be used when you are looking to develop an application which must be extensible, or will require future changes.  Due to the nature of prism you are able to create new modules and attach them to your application, if you have adopted the correct infrastructure your modules should slot in and extend the functionality of your application.  If you are developing applications as “Software as a Service” Prism can be of benefit to you.  At runtime the modules can be discovered and then loaded into Prism, therefore recently downloaded modules (the services) can be extended into the application.  Although Prism does not provided the functionality to discover new modules it does however provide methods to assist in attaching the modules which are available.