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.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: