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
!
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.