MultiTriggerImageControl

Some time ago I started creating this decorator that takes an image and splits it in five parts (default, normal, disabled, clicked, over (I’m not sure about the order)) and creates an animation between the states of the control. This control also is able to strech part of the image so that you can stretch buttons with round edges.

 I’m leaving the code here so you can explore a bit, it is not very good and not very well implemented yet, I hope I can finish it by the end of the month and repost again. I just wanted start sharing some stuff. 🙂

Here it is!

Advertisements

Family.Show

Yesterday, Vertigo released a new version of Family.Show, the reference application used to demonstrate the power of WPF. Yes, this means that you can go and grab the source code! You can find the click once installation and source code at Vertigo’s web site. This version introduces an approach to skinning, for now you’re only able to change mostly colors, I hope that a version 3.0 is released with full customization support (even if the user can’t create new skins).

Window Templates

After a long time away from an Internet connection (thanks to Optimus – Kanguru) I’m back!!

 So, we have complete customization control over our controls, now, wouldn’t it he great if we could do the same kind of customization to our window? The answer is ‘you can’! And Pavan Podila has the solution. You need to be aware because he makes use of AlphaBlended windows, this has a major performance issues on large windows, using it for small windows like message boxes would be fine.

How to allow full customization with a Resource Dictionary? (Part IV)

I know I’m a bit late with this, but I had no time at all to post this earlier. So, with no more delays I present you the source code for the customization application I promissed.

Remember, this is a pretty simple example of how to implement something like this.

Lets see why this method is so good:

  • It allows designers to completely customize the application for each theme
  • It allows you to give functionality per theme
  • Desn’t require you to recompile your application each time you want to change something in a theme (in the real world apps this is a very important fact and I had to deal with that when building the Imokapa Slideshow Application).
  • Complete abstraction between visual and logic
  • You only have to plan for features and the designer only needs to implement them visually
  • Each control is planned to detail divided in features, this allows the designer to choose wich is the right feature for each visual or logical implementation
  • In the sample provided I wanted to show a bit of the last point, in the default template (contained in the generic.xaml file) I have 4 buttons and in the vista arrows ResourceDictionary I have only 2 buttons that implement back and forward. This permits the control to be reused for othe purposes without having to re-write it’s logic! Great, huh? 😉

    How to allow full customization with a Resource Dictionary? (Part III)

    Commands and Bindings:

     Using Commands and Bindings you can achieve any kind of visual you wish! That’s right! From a simple Windows Classic theme to a 3D completely interactive design :D!

    Let’s now create our control!

        1 public class DirectionNavigator : System.Windows.Controls.Control

        2 {

        3     static DirectionNavigator()

        4     {

        5         InitializeCommands();

        6         EventManager.RegisterClassHandler(typeof(DirectionNavigator),

        7         Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonDown), true);

        8         DefaultStyleKeyProperty.OverrideMetadata(typeof(DirectionNavigator), new FrameworkPropertyMetadata(typeof(DirectionNavigator)));

        9     }

       10     private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

       11     {

       12         DirectionNavigator control = (DirectionNavigator)sender;

       13         if (!control.IsKeyboardFocusWithin)

       14         {

       15             e.Handled = control.Focus() || e.Handled;

       16         }

       17     }

       18 

       19     private static void InitializeCommands()

       20     {

       21         _moveUpCommand = new RoutedCommand(“MoveUpCommand”, typeof(DirectionNavigator));

       22         CommandManager.RegisterClassCommandBinding(typeof(DirectionNavigator), new CommandBinding(_moveUpCommand, OnMoveUpCommand));

       23         CommandManager.RegisterClassInputBinding(typeof(DirectionNavigator), new InputBinding(_moveUpCommand, new KeyGesture(Key.Up)));

       24         _moveLeftCommand = new RoutedCommand(“MoveLeftCommand”, typeof(DirectionNavigator));

       25         CommandManager.RegisterClassCommandBinding(typeof(DirectionNavigator), new CommandBinding(_moveLeftCommand, OnMoveLeftCommand));

       26         CommandManager.RegisterClassInputBinding(typeof(DirectionNavigator), new InputBinding(_moveLeftCommand, new KeyGesture(Key.Left)));

       27         _moveDownCommand = new RoutedCommand(“MoveDownCommand”, typeof(DirectionNavigator));

       28         CommandManager.RegisterClassCommandBinding(typeof(DirectionNavigator), new CommandBinding(_moveDownCommand, OnMoveDownCommand));

       29         CommandManager.RegisterClassInputBinding(typeof(DirectionNavigator), new InputBinding(_moveDownCommand, new KeyGesture(Key.Down)));

       30 

       31         _moveRightCommand = new RoutedCommand(“MoveRightCommand”, typeof(DirectionNavigator));

       32         CommandManager.RegisterClassCommandBinding(typeof(DirectionNavigator), new CommandBinding(_moveRightCommand, OnMoveRightCommand));

       33         CommandManager.RegisterClassInputBinding(typeof(DirectionNavigator), new InputBinding(_moveRightCommand, new KeyGesture(Key.Right)));

       34     }

       35 

       36     private static RoutedCommand _moveUpCommand;

       37     private static RoutedCommand _moveLeftCommand;

       38     private static RoutedCommand _moveDownCommand;

       39     private static RoutedCommand _moveRightCommand;

       40 

       41     public static RoutedCommand MoveUpCommand

       42     {

       43         get { return _moveUpCommand; }

       44     }

       45 

       46     public static RoutedCommand MoveLeftCommand

       47     {

       48         get { return _moveLeftCommand; }

       49     }

       50 

       51     public static RoutedCommand MoveDownCommand

       52     {

       53         get { return _moveDownCommand; }

       54     }

       55 

       56     public static RoutedCommand MoveRightCommand

       57     {

       58         get { return _moveRightCommand; }

       59     }

       60 

       61     private static void OnMoveUpCommand(object sender, ExecutedRoutedEventArgs e)

       62     {

       63         DirectionNavigator control = sender as DirectionNavigator;

       64         if (control != null)

       65         {

       66             control.OnMoveUp();

       67         }

       68     }

       69 

       70     private static void OnMoveLeftCommand(object sender, ExecutedRoutedEventArgs e)

       71     {

       72         DirectionNavigator control = sender as DirectionNavigator;

       73         if (control != null)

       74         {

       75             control.OnMoveLeft();

       76         }

       77     }

       78 

       79     private static void OnMoveDownCommand(object sender, ExecutedRoutedEventArgs e)

       80     {

       81         DirectionNavigator control = sender as DirectionNavigator;

       82         if (control != null)

       83         {

       84             control.OnMoveDown();

       85         }

       86     }

       87 

       88     private static void OnMoveRightCommand(object sender, ExecutedRoutedEventArgs e)

       89     {

       90         DirectionNavigator control = sender as DirectionNavigator;

       91         if (control != null)

       92         {

       93             control.OnMoveRight();

       94         }

       95     }

       96 

       97     protected virtual void OnMoveUp()

       98     {

       99         DirectionPressedEventArgs e = new DirectionPressedEventArgs(Directions.Up, DirectionPressedEvent);

      100         this.OnDirectionPressed(e);

      101     }

      102 

      103     protected virtual void OnMoveLeft()

      104     {

      105         DirectionPressedEventArgs e = new DirectionPressedEventArgs(Directions.Left, DirectionPressedEvent);

      106         this.OnDirectionPressed(e);

      107     }

      108 

      109     protected virtual void OnMoveDown()

      110     {

      111         DirectionPressedEventArgs e = new DirectionPressedEventArgs(Directions.Down, DirectionPressedEvent);

      112         this.OnDirectionPressed(e);

      113     }

      114 

      115     protected virtual void OnMoveRight()

      116     {

      117         DirectionPressedEventArgs e = new DirectionPressedEventArgs(Directions.Right, DirectionPressedEvent);

      118         this.OnDirectionPressed(e);

      119     }

      120 

      121     public static readonly RoutedEvent DirectionPressedEvent = EventManager.RegisterRoutedEvent(

      122     “DirectionPressed”, RoutingStrategy.Bubble,

      123     typeof(DirectionPressedEventHandler), typeof(DirectionNavigator));

      124 

      125     public event DirectionPressedEventHandler DirectionPressed

      126     {

      127         add { AddHandler(DirectionPressedEvent, value); }

      128         remove { RemoveHandler(DirectionPressedEvent, value); }

      129     }

      130 

      131     protected virtual void OnDirectionPressed(DirectionPressedEventArgs args)

      132     {

      133         RaiseEvent(args);

      134     }

      135 }

      136 

      137 public class DirectionPressedEventArgs : RoutedEventArgs

      138 {

      139     public DirectionPressedEventArgs(Directions direction, RoutedEvent routedEvent)

      140     {

      141         _direction = direction;

      142         this.RoutedEvent = routedEvent;

      143     }

      144 

      145     private Directions _direction;

      146 

      147     public Directions Direction

      148     {

      149         get { return _direction; }

      150         set { _direction = value; }

      151     }

      152 }

      153 

      154 public delegate void DirectionPressedEventHandler(object sender, DirectionPressedEventArgs e);

      155 

      156 public enum Directions

      157 {

      158     Up,

      159     Left,

      160     Down,

      161     Right

      162 }

     

    This is a simple navigation control, it has 4 commands, each command could execute some code you wish, I opted to raise an event on each command and then implement the logic in the main window logic. I also registered some command bindings for the arrow keys in the static instanciator. Now, what good is this for? Now, in the Resource dictionary you can bind the commands to buttons or other elements you wish to create there! Lets see how!

        1 <Style TargetType="{x:Type local:DirectionNavigator}">

        2   <Setter Property="Width" Value="100" />

        3   <Setter Property="Height" Value="100" />

        4   <Setter Property="Template">

        5     <Setter.Value>

        6       <ControlTemplate TargetType="{x:Type local:DirectionNavigator}">

        7         <Canvas Background="{TemplateBinding Background}"

        8         Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" >

        9           <Button Command="{x:Static local:DirectionNavigator.MoveUpCommand}" Width="33" Height="33" Canvas.Top="0" Canvas.Left="33" />

       10           <Button Command="{x:Static local:DirectionNavigator.MoveLeftCommand}" Width="33" Height="33" Canvas.Top="33" Canvas.Left="0" />

       11           <Button Command="{x:Static local:DirectionNavigator.MoveDownCommand}" Width="33" Height="33" Canvas.Top="66" Canvas.Left="33" />

       12           <Button Command="{x:Static local:DirectionNavigator.MoveRightCommand}" Width="33" Height="33" Canvas.Top="33" Canvas.Left="66" />

       13         </Canvas>

       14       </ControlTemplate>

       15     </Setter.Value>

       16   </Setter>

       17 </Style>

    As you can see I created 4 buttons in a canvas and associated the command of each button to the right command in my control. Now you see here 4 buttons, but you could just put a template with some 3D and bind the commands to anything you wish. How cool is that? 😀 This is a pretty simple sample, any doubts just comment and I’ll help you! 🙂

    One thing I didn’t do in this control is Bindings, but it is pretty simple, imagine you have a property of type string and wanted it to display in a textblock somewhere, in the control template you would have to do something like

    <TextBlock Text="{Binding SomeStringProperty}" />

    This would display the text in the SomeStringProperty 🙂

    In the next and final post on this, I’ll post a complete sample in a zip file and explain why this approach is so good in terms of customization.

    How to allow full customization with a Resource Dictionary? (Part II)

    ResourceDictionary:

    In all my applications I’ve opted to center all the visual information in a single file for several reasons. First, it is easy for the designer to edit just one file. Second, you can load that file from the filesystem, this way the user has the chance to edit the file to fit his needs (assuming he knows XAML and all the commands implemented in the application). And even if you don’t want to give that option to the user it is easy to edit just one file to fix any kind of glitch.

    Now lets see a simple button:


    <Page xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">

      <Grid>

        <Grid.Resources>

          <Style x:Key="btnStyle" TargetType="{x:Type Button}">

            <Setter Property="Width" Value="120" />

            <Setter Property="Height" Value="25" />

            <Setter Property="Foreground" Value="#FFF" />

            <Setter Property="Template">

              <Setter.Value>

                <ControlTemplate TargetType="{x:Type Button}">

                  <Border CornerRadius="10">

                    <Border.Background>

                      <LinearGradientBrush EndPoint="0,1">

                        <GradientStop Color="#ACF" Offset="0" />

                        <GradientStop Color="#004499" Offset="1" />

                      </LinearGradientBrush>

                    </Border.Background>

                    <TextBlock Text="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center" />

                  </Border>

                </ControlTemplate>

              </Setter.Value>

            </Setter>   

          </Style>

        </Grid.Resources>

        <button Content="Hello World" Style="{StaticResource btnStyle}"/>

      </Grid>

    </Page>

    This is a very simple example to show how to create a style for a button, this style will result in a button with a gradient blue and rounded edges. The setters are used to set propeties of the class Button, as you can see the Template section is somewhat special, it has the ControlTemplate structure inside the value of the setter. You could put it outside and just reference the ControlTemplate’s key.
    The ControlTemplate is used to create the visual of the button from the ground up! Yep, that means you can put there anything you want, from 2D flat button to a 3D animated globe or cd etc..

    As you can imagine part of the secret for the customization is here! You can create anything you want for the button, but it still lacks the feature I’ll will cover in the next part, Bindings (yes, you can see one in the template) and Commands, these are the key points to have the visual you want without changing a single line of C# code after you compile :).

    Update:

    After I read what Thylux said I realised I wasn’t completely clear about everything and the code wasn’t quite right too.

    Thylux asked:
    How is the style you created being applied to the button at the end?

    Yep, the code wasn’t there, somehow wordpress removed that part of the code when I submitted the post. But you have two ways to make a button use a style. Imagine you want all buttons in your application to have the exact same look, you would set the key of Style to {x:Type Button} This way WPF recognizes I’m refering to the class Button and will implement that style to all references of Button (unless you have a specific button calling other style). If you want a specific button to have a specific look you can give a name to the key of the style, in this case “btnStyle”, and in the control, depending on the scope of the button and where the resources are you could use Style={StaticResource btnStyle} or Style={DynamicResource btnStyle}, the diference is in performance and in the scope, StaticResource looks in the same file where the control is, and the resource has to be defined in one of the button’s parents. DynamicResource will look everywhere, including ApplicationResources.

    About the Content property, in WPF Buttons don’t have a Text property anymore, instead they have a content property because this way you can put anything you want inside a button :). And no, you can’t create properties dynamically.

    How to allow full customization with a Resource Dictionary? (Part I)

    This is a problem that I’ve been dealing with for the past year, and I’ve found several ways to simplify the task, but I must say that the secret is binding and commands on custom controls!

    The Problem:

    Last year when I started planning for the Imokapa Slideshow (you can see three images of it in the first edition of the Portuguese Official Windows Vista Magazine, I’ll post about it soon) I was told that our costumers most of the time demand a product that has their image. With this in mind, I had to create a solution that could easily be customized to fit needs of our costumers.

    The Path:

    In the beginning I started by creating a small Resource Dictionary that would store control positioning, colors, brushes, templates and styles. At the time the solution seemed good, but somewhat limited because I had all the controls specified in each window of the application and had them in a grid to take care of the layout. This way I couldn’t swap objects, change positioning easily or even if I wanted to make a Slider behave like a Scrollbar the only chance I would have was to create a template for the slider to make it look like a Scrollbar.

    The solution:

    This is what I’ll be explaining you in this first post and the next two or three.

    First we need to create a small object to take care of the theme switching for us.
    In the FileSystem we’ll have a Folder called “Themes”, this folder will store all images, the ResourceDictionary and other resources for each Theme in it’s separate folder. So, let’s see what we got there!

    public static List<string> GetThemes()

    {

        List<string> themeNames = new List<string>();

        foreach (string dir in Directory.GetDirectories("Themes"))

        {

            DirectoryInfo directory = new DirectoryInfo(dir);

            if (directory.Attributes != FileAttributes.Hidden)

                themeNames.Add(directory.Name);

        }

        return themeNames;

    }

    So, now we have some strings with the name of each Theme. This portion of code is really simple, it just checks for the name of all directories that aren’t hidden in the Themes Folder.
    Now, for the cool stuff! Let’s Pick the Theme we like!

    public static void ChangeTheme(string themeName)

    {

        string strThemePath = "Themes\\" + themeName + "\\Theme.xaml";

        if (File.Exists(strThemePath))

            try

            {

                Application.Current.Resources = (ResourceDictionary)XamlReader.Load(new XmlTextReader(strThemePath));

            }

            catch (Exception ex)

            { throw ex; }

        else

            throw new FileNotFoundException("The Theme file was not found.\nPlease make sure the Theme is valid.");

    }

    Yep! I see the light! What did I do here? Simple! I use a XamlReader to load the theme.xaml file, cast it to a ResourceDictionary and then make those resources avaliable for all the application. Despite what you might think this process adds the resources in the theme.xaml file to the current app resources, then why not clear the app resources? For two reasons, first, because you might have styles specified in the app code that require the default WPF styles, second, because when you want to test a new theme that you’re creating you need to complete the theme before you can test parts of it. So, if you load the blue theme and then you have a red theme that you just started creating and it only has a template for the Button when you load the theme, the app will use the red template for the button and the blue template for the rest of the styles that aren’t found in the red theme.

    This concludes the first part of how to allow full customization with a Resource Dictionary, in the next post I’ll be covering the basics of the Resource dictionary. Stay tuned!