Cascade pattern / Method chaining

Cascade

Today, I am going to explain a simple programming pattern step by step.
Often the cascade pattern can be found in connection with consecutive data manipulation. It has many names. In C# I would put it in the same chapter as Extension Methods.

But let us start at the very beginning. Genesis 🙂

This is a simple integer calculation.

int r0 = 5;
r0 = ((((r0 + 2) * 4) - 8) / 2) + 1;
Console.WriteLine("Result is " + r0);  // 11

We could break it down into many separate calculation steps …

int r1 = 5;
r1 += 2; r1 *= 4; r1 -= 8; r1 /= 2; r1 += 1;
Console.WriteLine("Result is " + r1);  // 11

… and build a class to perform reoccurring calculations.

public class Classic {
  static public int add(int a, int b) { return a + b; }
  static public int sub(int a, int b) { return a - b; }
  static public int mul(int a, int b) { return a * b; }
  static public int div(int a, int b) { return a / b; }
} // class

int r2 = 5;
r2 = Classic.add(r2, 2);
r2 = Classic.mul(r2, 4);
r2 = Classic.sub(r2, 8);
r2 = Classic.div(r2, 2);
r2 = Classic.add(r2, 1);
Console.WriteLine("Result is " + r2);  // 11

Well, this is nice. But the code is clumsy. We could overload operators. Anyhow, this is not the way I would like to go today. What about a memory variable in form of a property called “Result”.

public class Cascade1 {
  public int Result { get; private set; }

  public Cascade1(int x) { Result = x; }
  public Cascade1 add(int x) { Result += x; return this; }
  public Cascade1 sub(int x) { Result -= x; return this; }
  public Cascade1 mul(int x) { Result *= x; return this; }
  public Cascade1 div(int x) { Result /= x; return this; }
} // class

int c1 = new Cascade1(5)
    .add(2)
    .mul(4)
    .sub(8)
    .div(2)
    .add(1)
    .Result;

Console.WriteLine("Result is " + c1);  // 11

This looks much better, doesn’t it?
We replace the integers by a simple class, which only has one public field called “Age”.

public class Data {
  public int Age;
} // class

We add IENumberable as parameter. Now, the program looks neat and more flexible.

public class Cascade2 {
 public static void add(IEnumerable<Data> xIENumberable, int xValue) { foreach (Data x in xIENumberable) x.Age += xValue; }
 public static void sub(IEnumerable<Data> xIENumberable, int xValue) { foreach (Data x in xIENumberable) x.Age -= xValue; }
 public static void mul(IEnumerable<Data> xIENumberable, int xValue) { foreach (Data x in xIENumberable) x.Age *= xValue; }
 public static void div(IEnumerable<Data> xIENumberable, int xValue) { foreach (Data x in xIENumberable) x.Age /= xValue; }
} // class

List<Data> lList = new List<Data>(); for (int i = 0; i < 10; i++) lList.Add(new Data() { Age = i });

Cascade2.add(lList, 2);
Cascade2.mul(lList, 4);
Cascade2.sub(lList, 8);
Cascade2.div(lList, 2);
Cascade2.add(lList, 1);

Console.Write("Array result is "); lList.ForEach(x => Console.Write(x.Age + " "));

But once again we face too many parameters. Should we add a memory field? No, C# offers Extension Methods. This is the way to go!

public static class Cascade3 {
  public static IEnumerable<Data> add(this IEnumerable<Data> xIENumberable, int xValue) {
    foreach (Data x in xIENumberable) x.Age += xValue;
    return xIENumberable;
  } //

  public static IEnumerable<Data> sub(this IEnumerable<Data> xIENumberable, int xValue) {
    foreach (Data x in xIENumberable) x.Age -= xValue;
    return xIENumberable;
  } // 

  public static IEnumerable<Data> mul(this IEnumerable<Data> xIENumberable, int xValue) {
    foreach (Data x in xIENumberable) x.Age *= xValue;
    return xIENumberable;
  } //

  public static IEnumerable<Data> div(this IEnumerable<Data> xIENumberable, int xValue) {
    foreach (Data x in xIENumberable) x.Age /= xValue;
    return xIENumberable;
  } //
} // class

List<Data> lList = new List<Data>(); for (int i = 0; i < 10; i++) lList.Add(new Data() { Age = i });
lList.add(2)
  .mul(4)
  .sub(8)
  .div(2)
  .add(1);

Console.Write("Array result is "); lList.ForEach(x => Console.Write(x.Age + " "));

Each List object can now use the extension methods. In C# you most likely have come across such pattern when using the namespace System.Linq. Adding this namespace automatically enables many methods for lists (IENumerable) and arrays. Here is an example of that namespace. You can chain together methods. Make sure the return parameter points to the same list each time, otherwise the chain is broken. For instance a Sum() would return a number rather an IENumerable, thus breaking the chain.

List<Data> lList = new List<Data>(); for (int i = 0; i < 10; i++) lList.Add(new Data() { Age = i });

// using System.Linq;
List<Data> lResult = lList.Where(x => x.Age % 2 == 0).Take(10).ToList();
Console.Write("Array result is "); lResult.ForEach(x => Console.Write(x.Age + " "));

Wiki

And here is the entire source code in one piece.

using System;
using System.Collections.Generic;
using System.Linq;

namespace CascadePattern {
  public class Data {
    public int Age;
  } // class

  public static class Cascade3 {
    public static IEnumerable<Data> add(this IEnumerable<Data> xIENumberable, int xValue) {
      foreach (Data x in xIENumberable) x.Age += xValue;
      return xIENumberable;
    } //
    public static IEnumerable<Data> sub(this IEnumerable<Data> xIENumberable, int xValue) {
      foreach (Data x in xIENumberable) x.Age -= xValue;
      return xIENumberable;
    } // 
    public static IEnumerable<Data> mul(this IEnumerable<Data> xIENumberable, int xValue) {
      foreach (Data x in xIENumberable) x.Age *= xValue;
      return xIENumberable;
    } //
    public static IEnumerable<Data> div(this IEnumerable<Data> xIENumberable, int xValue) {
      foreach (Data x in xIENumberable) x.Age /= xValue;
      return xIENumberable;
    } //
  } // class

  class Program {

    public class Classic {
      static public int add(int a, int b) { return a + b; }
      static public int sub(int a, int b) { return a - b; }
      static public int mul(int a, int b) { return a * b; }
      static public int div(int a, int b) { return a / b; }
    } // class

    public class Cascade1 {
      public int Result { get; private set; }

      public Cascade1(int x) { Result = x; }
      public Cascade1 add(int x) { Result += x; return this; }
      public Cascade1 sub(int x) { Result -= x; return this; }
      public Cascade1 mul(int x) { Result *= x; return this; }
      public Cascade1 div(int x) { Result /= x; return this; }

    } // class

    public class Cascade2 {
      public static void add(IEnumerable<Data> xIENumberable, int xValue) {
        foreach (Data x in xIENumberable) x.Age += xValue;
      } //
      public static void sub(IEnumerable<Data> xIENumberable, int xValue) {
        foreach (Data x in xIENumberable) x.Age -= xValue;
      } // 
      public static void mul(IEnumerable<Data> xIENumberable, int xValue) {
        foreach (Data x in xIENumberable) x.Age *= xValue;
      } //
      public static void div(IEnumerable<Data> xIENumberable, int xValue) {
        foreach (Data x in xIENumberable) x.Age /= xValue;
      } //
    } // class


    static void Main(string[] args) {

      int r0 = 5;
      r0 = ((((r0 + 2) * 4) - 8) / 2) + 1;
      Console.WriteLine("Result is " + r0);  // 11

      int r1 = 5;
      r1 += 2; r1 *= 4; r1 -= 8; r1 /= 2; r1 += 1;
      Console.WriteLine("Result is " + r1);  // 11

      int r2 = 5;
      r2 = Classic.add(r2, 2);
      r2 = Classic.mul(r2, 4);
      r2 = Classic.sub(r2, 8);
      r2 = Classic.div(r2, 2);
      r2 = Classic.add(r2, 1);
      Console.WriteLine("Result is " + r2);  // 11

      int c1 = new Cascade1(5)
      .add(2)
      .mul(4)
      .sub(8)
      .div(2)
      .add(1)
      .Result;

      Console.WriteLine("Result is " + c1);  // 11

      List<Data> lList = new List<Data>();
      for (int i = 0; i < 10; i++) lList.Add(new Data() { Age = i });

      Cascade2.add(lList, 2);
      Cascade2.mul(lList, 4);
      Cascade2.sub(lList, 8);
      Cascade2.div(lList, 2);
      Cascade2.add(lList, 1);

      Console.Write("Array result is ");
      lList.ForEach(x => Console.Write(x.Age + " "));
      Console.WriteLine();

      lList.Clear();
      for (int i = 0; i < 10; i++) lList.Add(new Data() { Age = i });
      lList.add(2)
      .mul(4)
      .sub(8)
      .div(2)
      .add(1);

      Console.Write("Array result is ");
      lList.ForEach(x => Console.Write(x.Age + " "));
      Console.WriteLine();

      // using System.Linq;
      lList.Clear();
      for (int i = 0; i < 50; i++) lList.Add(new Data() { Age = i });
      List<Data> lResult = lList.Where(x => x.Age % 2 == 0).Take(10).ToList();
      Console.Write("Array result is ");
      lResult.ForEach(x => Console.Write(x.Age + " "));
      Console.ReadLine();

    } //

  } // class
} // namespace

example output:
Result is 11
Result is 11
Result is 11
Result is 11
Array result is 1 3 5 7 9 11 13 15 17 19
Array result is 1 3 5 7 9 11 13 15 17 19
Array result is 0 2 4 6 8 10 12 14 16 18

Advertisements

Routed Events (part 2)

BubblingEvents

Referring back to Routed Events (to part 1), let’s have a closer look at this part of the example source code:

// bubbling
private void MyMouseUp(object sender, MouseButtonEventArgs e) {
  FrameworkElement lElement = sender as FrameworkElement;
  string lAppend = Environment.NewLine;
  if (sender is Window) lAppend += Environment.NewLine;
  Results.Text += e.RoutedEvent.RoutingStrategy.ToString() + ": " + lElement.ToString() + lAppend;
  e.Handled = false;
  Results.ScrollToEnd();
} //

 

Suppressing Events

e.Handled allows you to halt the event routing process. Set this boolean to true and the event stops traveling any further. A small change demonstrates the altered behavior:

// bubbling
private void MyMouseUp(object sender, MouseButtonEventArgs e) {
  FrameworkElement lElement = sender as FrameworkElement;
  string lAppend = Environment.NewLine;
  if (sender is Window) lAppend += Environment.NewLine;
  Results.Text += e.RoutedEvent.RoutingStrategy.ToString() + ": " + lElement.ToString() + lAppend;
  e.Handled = (e.ChangedButton == MouseButton.Right);
  Results.ScrollToEnd();
} //

If you use the right MouseButton now, the bubbling routing event process stops. The same applies to the tunneling process when you change the MyPreviewMouseUp() method accordingly.

 


Raising Suppressed Events

You can avoid the suppression of Routed Events. This cannot be done through XAML. Use the AddHandler() method instead. An overload accepts a boolean for its third parameter. Set this one to true and you will receive events even if the e.Handled flag was set to true.

Let’s slightly change our example source code to:

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:app="clr-namespace:DemoApp"
        Title="MainWindow" Height="500" Width="630"
        Name="MyWindow" PreviewMouseUp="MyPreviewMouseUp">
    ...
...
public MainWindow() {
 InitializeComponent();
 
 List<Data> lItems = new List<Data>() {
    new Data() {Name = "Otto", LastName = "Waalkes"},
    new Data() {Name = "Heinz", LastName = "Rühmann"},
    new Data() {Name = "Michael", LastName = "Herbig"},
    new Data() {Name = "Sky", LastName = "du Mont"},
    new Data() {Name = "Dieter", LastName = "Hallervorden"},
    new Data() {Name = "Diether", LastName = "Krebs"},
    new Data() {Name = "Helga", LastName = "Feddersen"},
    new Data() {Name = "Herbert", LastName = "Grönemeyer"},
  };
    
  MyListView.ItemsSource = lItems;
  MyWindow.AddHandler(UIElement.MouseUpEvent, new MouseButtonEventHandler(MyMouseUp), true);      
} //
...

Et voilà! The Routed Event gets executed despite the set e.Handled flag.

 
Attached Events

The Click event is defined in the ButtonBase class. It is a kind of combination of a Button press and release. But how can you use the bubbling behavior on a higher level like eg. a Grid that does not derive from the ButtonBase class? Attached events enable you to add event handlers to arbitrary elements, which do not define or inherit these.
Let’s add a Click event to the window level by adding Button.Click=”MyClick”:

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:app="clr-namespace:DemoApp"
        Title="MainWindow" Height="500" Width="630"
        Name="MyWindow" PreviewMouseUp="MyPreviewMouseUp"
        Button.Click="MyClick" >
    ...
private void MyClick(object sender, RoutedEventArgs e) {
  MessageBox.Show("Click received!");
} //

The program does not raise any Click events. We did even override the Click event of our TripleClickButton class. You won’t see a lot. But have a look at the two scroll bars. The scroll bar background (not the scroll bar itself) raises click events. As we are on the window level, we now receive these unexpected events. Indeed, this is a good example. A click of the scroll bar background bubbles through the hierarchy and finally raises the attached Click event on the window level.
Don’t forget to analyse the e.Source of your event parameter. You need to filter out the right Click event.

 

Style EventSetter

While Property setters are most common in Styles, EventSetters are rarely seen. They can be used for more complex problems. The simple ones should be solved by using Style.Triggers. Let’s say you want to change the color of a TextBlock when entering or leaving the area with the mouse cursor.

...
<Window.Resources>
    <Style x:Key="ChangeBackgroundColor" TargetType="TextBlock">
        <EventSetter Event="TextBlock.MouseEnter" Handler="ChangeBackgroundColorOnMouseEnter" /> // direct event
        <EventSetter Event="TextBlock.MouseLeave" Handler="ChangeBackgroundColorOnMouseLeave" /> // direct event
    </Style>
</Window.Resources>
...
<TextBlock Text="LastName:  " Grid.Column="2"  VerticalAlignment="Center" FontSize="16" Style="{StaticResource ChangeBackgroundColor}"/>
...
    private void ChangeBackgroundColorOnMouseEnter(object sender, MouseEventArgs e) { ((TextBlock)sender).Background = Brushes.Red; }
    private void ChangeBackgroundColorOnMouseLeave(object sender, MouseEventArgs e) { ((TextBlock)sender).Background = null; }

 

This example could be simplified. No C# code required:

...
<Window.Resources>
    <Style x:Key="ChangeBackgroundColor" TargetType="TextBlock">
        <Style.Triggers>
            <Trigger Property="TextBlock.IsMouseOver" Value="True">
                <Setter Property="TextBlock.Background" Value="Red" />
            </Trigger>
        </Style.Triggers>                       
    </Style>
</Window.Resources>
...
<TextBlock Text="LastName:  " Grid.Column="2"  VerticalAlignment="Center" FontSize="16" Style="{StaticResource ChangeBackgroundColor}"/>
...

 

I see the need for further explanations on Trigger types. I have just added a reminder on my To-Do-List.
But for now a simple list must suffice:

  • Trigger: Simplest trigger form. Reacts on DependencyProperty changes and then uses setters to change styles.
  • MultiTrigger: Combines multiple Triggers. All conditions must be met.
  • DataTrigger: Reacts on changes in bound data.
  • MultiDataTrigger: Combines multiple DataTriggers. All conditions must be met.
  • EventTrigger: Reacts on events. Used for animations.

In a nutshell: There are three trigger types. They use dependency properties, routed events or data binding.

Routed Events (part 1)

BubblingEvents

Events notify your code that something has happened. You subscribe to events like you subscribe eg. to a monthly magazine. Let’s say a new magazine comes out. The postal worker delivers it to your mail box. You don’t need to ask for the new magazine to be sent to you each time.
Something similar takes place in WPF. A button is pressed and the program delivers that information to your mail box, which is a callback method.

Links:
Events Part1
Events Part2
Events Part3
 

The classical event has a standard pattern:

public delegate void dMyDelegate();
public event dMyDelegate MyEvent;

public void addEvent() { MyEvent += Callback; }
public void removeEvent() { MyEvent -= Callback; }

public void CallEvent() {
  dMyDelegate d = MyEvent;
  if (d == null) return;
  d();
} //

void Callback() { Console.WriteLine("Event raised"); }

Or this:

private EventHandler _Handler;
public event EventHandler MyEvent {
  add { _Handler += value; }
  remove { _Handler -= value; }
} //

...

 
 

But what exactly is a “Routed Event”?

Routed Events are used in connection with WPF. They are required for a certain routing concept. In WinForms the callback is sent by the corresponding component (eg. the button). But in WPF event routing allows an event to take place in one element, but be raised by another one. That way you can handle events in the most convenient place.
A Button could be part of a template, which in turn is a part of a ListView. The Button could have an image, an ornated border, a grid and many extras. It does make sense to receive events on the group level sometimes.

We know direct events from WinForms. A mouse click raises an event. But in WPF there are two more types:

  1. Bubbling Events: They travel up the hierarchy of the visual tree. The click raises an event on the button, then on the grid, then on the window. It also raises events on all objects on the way.
  2. Tunneling Events: These events travel to the opposite direction. A keyboard entry would start at the window level, then travel through the grid towards the button.

 

Let’s just delve into a practical example. Run the code and observe what is happening.

RoutedEvents
 

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="500" Width="630"
        MouseUp="MyMouseUp" PreviewMouseUp="MyPreviewMouseUp">
    <Grid MouseUp="MyMouseUp" PreviewMouseUp="MyPreviewMouseUp">
        <Grid.RowDefinitions>
            <RowDefinition Height="300" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <ListView Name="MyListView" Margin="0,0,0,0" Grid.IsSharedSizeScope="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True" MouseUp="MyMouseUp"  PreviewMouseUp="MyPreviewMouseUp" Grid.Row="0">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <GroupBox Header="Item" FontSize="10">
                        <Grid PreviewMouseUp="MyPreviewMouseUp" MouseUp="MyMouseUp">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition SharedSizeGroup="A" />
                                <ColumnDefinition />
                                <ColumnDefinition SharedSizeGroup="A" />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="Name:  " Grid.Column="0" VerticalAlignment="Center"  FontSize="16" PreviewMouseUp="MyPreviewMouseUp"/>
                            <TextBlock Text="{Binding Name}" FontWeight="Bold" Grid.Column="1"  VerticalAlignment="Center" FontSize="16"/>
                            <TextBlock Text="LastName:  " Grid.Column="2"  VerticalAlignment="Center" FontSize="16"/>
                            <TextBlock Text="{Binding LastName}" FontWeight="Bold" Grid.Column="3" VerticalAlignment="Center" FontSize="16"/>
                            <TextBlock Text="Click me" Grid.Column="4" FontSize="16" MouseUp="MyMouseUp" Background="AliceBlue"/>
                        </Grid>
                    </GroupBox>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <TextBox Name="Results" IsReadOnly="True" FontSize="14" ScrollViewer.VerticalScrollBarVisibility="Auto" Height="Auto" Grid.Row="1" />
    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;

namespace DemoApp {
  public partial class MainWindow : Window {

    public class Data {
      public string Name { get; set; }
      public string LastName { get; set; }
    } //

    public MainWindow() {
      InitializeComponent();

      List<Data> lItems = new List<Data>() {
        new Data() {Name = "Otto", LastName = "Waalkes"},
        new Data() {Name = "Heinz", LastName = "Rühmann"},
        new Data() {Name = "Michael", LastName = "Herbig"},
        new Data() {Name = "Sky", LastName = "du Mont"},
        new Data() {Name = "Dieter", LastName = "Hallervorden"},
        new Data() {Name = "Diether", LastName = "Krebs"},
        new Data() {Name = "Helga", LastName = "Feddersen"},
        new Data() {Name = "Herbert", LastName = "Grönemeyer"},
      };
      MyListView.ItemsSource = lItems;
    } //

    // bubbling
    private void MyMouseUp(object sender, MouseButtonEventArgs e) {
      FrameworkElement lElement = sender as FrameworkElement;
      string lAppend = Environment.NewLine;
      if (sender is Window) lAppend += Environment.NewLine;
      Results.Text += e.RoutedEvent.RoutingStrategy.ToString() + ": " + lElement.ToString() + lAppend;
      e.Handled = false;
      Results.ScrollToEnd();
    } //

    // tunneling
    private void MyPreviewMouseUp(object sender, MouseButtonEventArgs e) {
      FrameworkElement lElement = sender as FrameworkElement;
      string lAppend = Environment.NewLine;
      if (sender.Equals(e.OriginalSource)) lAppend += Environment.NewLine;
      Results.Text += e.RoutedEvent.RoutingStrategy.ToString() + ": " + lElement.ToString() + lAppend;
      e.Handled = false;
      Results.ScrollToEnd();
    } //

  } // class
} // namespace

 
Tunneling Events are raised before Bubbling Events. The convention for Tunneling Events in .Net is that names have to start with the prefix “Preview”. Therefore The “MouseUp” event is a Bubbling Event and “PreviewMouseUp” is a Tunneling Event.
Today’s XAML source code subscribes to bubbling/tunneling events at several places. Compare the output with the code. In theory you could deal with all events on the window level. Use the e.OriginalSource field of the event argument MouseButtonEventArgs e to distinguish between the many possible events. You will also receive events that you did not explicitly subscribe to. Click into the lower textbox or on a scroll bar; this will raise events on the Grid, (ListView) and Window.

Now, let’s add a tunneling event to the “Click me” TextBlock.

<TextBlock Text="Click me" Grid.Column="4" FontSize="16" MouseUp="MyMouseUp" PreviewMouseUp="MyPreviewMouseUp" Background="AliceBlue"/>

 
This activates the code that was redundant so far:

if (sender.Equals(e.OriginalSource)) lAppend += Environment.NewLine;

 
 
Custom Routed Events

How can we add a custom routed event? Just follow this pattern:

  • Inherit an element from another class.
  • Define a public static readonly RoutedEvent.
  • Register that Event by using the EventManager.
  • Add an “old school” C# event that forwards “old school” subscriptions to your WPF routed event.

 
And here we go. Let’s add a button with a triple click event.

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace DemoApp {
  public class TripleClickButton : Button {

    /*
     * The methods AddHandler, RemoveHandler and RaiseEvent are inherited from UIElement
     */

    // public static readonly !
    public static readonly RoutedEvent TripleClickEvent = EventManager.RegisterRoutedEvent("TripleClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TripleClickButton));

    // Link classical approach to the above WPF RoutedEvent.
    // Do not add any complex code here!
    public event RoutedEventHandler TripleClick {
      add { AddHandler(TripleClickEvent, value); }
      remove { RemoveHandler(TripleClickEvent, value); }
    } //

    // How to trigger our Routed Event. 
    void RaiseTripleClickEvent() {
      RoutedEventArgs lRoutedEventArgs = new RoutedEventArgs(TripleClickButton.TripleClickEvent);
      RaiseEvent(lRoutedEventArgs);
    } //

    private List<DateTime> _Clicks = new List<DateTime>();
    protected override void OnClick() {
      lock (_Clicks) { // In theory we do not need a lock, because the event is always raised on the Dispatcher thread.
        DateTime lNow = DateTime.Now;
        _Clicks.Add(lNow);
        if (_Clicks.Count < 3) return;
        if (lNow.Subtract(_Clicks[0]).TotalMilliseconds < 1000) {
          _Clicks.Clear();
          RaiseTripleClickEvent();
          return;
        }
        _Clicks.RemoveAt(0);
      }      
    } //

  } // class
} // namespace

 
Declare the new class in the XAML window namespace and replace the rightmost TextBlock by our new custom button.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:app="clr-namespace:DemoApp"
        ...
       <TextBlock Text="{Binding LastName}" FontWeight="Bold" Grid.Column="3" VerticalAlignment="Center" FontSize="16"/>
       <app:TripleClickButton Content="TripleClick me" Grid.Column="4" FontSize="16" Background="Salmon" TripleClick="TripleClickButton_TripleClick" Tag="{Binding Name}" />
     </Grid>
     ...

 

Define the event itself in the main window. Here is the full code:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;

namespace DemoApp {
  public partial class MainWindow : Window {

    public class Data {
      public string Name { get; set; }
      public string LastName { get; set; }
    } //

    public MainWindow() {
      InitializeComponent();

      List<Data> lItems = new List<Data>() {
        new Data() {Name = "Otto", LastName = "Waalkes"},
        new Data() {Name = "Heinz", LastName = "Rühmann"},
        new Data() {Name = "Michael", LastName = "Herbig"},
        new Data() {Name = "Sky", LastName = "du Mont"},
        new Data() {Name = "Dieter", LastName = "Hallervorden"},
        new Data() {Name = "Diether", LastName = "Krebs"},
        new Data() {Name = "Helga", LastName = "Feddersen"},
        new Data() {Name = "Herbert", LastName = "Grönemeyer"},
      };
      MyListView.ItemsSource = lItems;

      
    } //

    // bubbling
    private void MyMouseUp(object sender, MouseButtonEventArgs e) {
      FrameworkElement lElement = sender as FrameworkElement;
      string lAppend = Environment.NewLine;
      if (sender is Window) lAppend += Environment.NewLine;
      Results.Text += e.RoutedEvent.RoutingStrategy.ToString() + ": " + lElement.ToString() + lAppend;
      e.Handled = false;
      Results.ScrollToEnd();
    } //

    // tunneling
    private void MyPreviewMouseUp(object sender, MouseButtonEventArgs e) {
      FrameworkElement lElement = sender as FrameworkElement;
      string lAppend = Environment.NewLine;
      if (sender.Equals(e.OriginalSource)) lAppend += Environment.NewLine;
      Results.Text += e.RoutedEvent.RoutingStrategy.ToString() + ": " + lElement.ToString() + lAppend;
      e.Handled = false;
      Results.ScrollToEnd();
    }

    // custom event
    private void TripleClickButton_TripleClick(object sender, RoutedEventArgs e) {
      Button lButton = e.OriginalSource as Button;
      if (lButton == null) return;
      
      Results.Text = "TripleClick received from " + lButton.Tag;
    } //

  } // class
} // namespace

 

And the full XAML:

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:app="clr-namespace:DemoApp"
        Title="MainWindow" Height="500" Width="630"
        MouseUp="MyMouseUp" PreviewMouseUp="MyPreviewMouseUp">
    <Grid MouseUp="MyMouseUp" PreviewMouseUp="MyPreviewMouseUp">
        <Grid.RowDefinitions>
            <RowDefinition Height="300" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <ListView Name="MyListView" Margin="0,0,0,0" Grid.IsSharedSizeScope="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True" MouseUp="MyMouseUp"  PreviewMouseUp="MyPreviewMouseUp" Grid.Row="0">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <GroupBox Header="Item" FontSize="10">
                        <Grid PreviewMouseUp="MyPreviewMouseUp" MouseUp="MyMouseUp">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition SharedSizeGroup="A" />
                                <ColumnDefinition />
                                <ColumnDefinition SharedSizeGroup="A" />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="Name:  " Grid.Column="0" VerticalAlignment="Center"  FontSize="16" PreviewMouseUp="MyPreviewMouseUp"/>
                            <TextBlock Text="{Binding Name}" FontWeight="Bold" Grid.Column="1"  VerticalAlignment="Center" FontSize="16"/>
                            <TextBlock Text="LastName:  " Grid.Column="2"  VerticalAlignment="Center" FontSize="16"/>
                            <TextBlock Text="{Binding LastName}" FontWeight="Bold" Grid.Column="3" VerticalAlignment="Center" FontSize="16"/>
                            <app:TripleClickButton Content="TripleClick me" Grid.Column="4" FontSize="16" Background="Salmon" TripleClick="TripleClickButton_TripleClick" Tag="{Binding Name}" />
                        </Grid>
                    </GroupBox>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <TextBox Name="Results" IsReadOnly="True" FontSize="14" ScrollViewer.VerticalScrollBarVisibility="Auto" Height="Auto" Grid.Row="1" />
    </Grid>
</Window>

 

TripleClick

 

The next post will be about:

  • Marking Routed Events as handled to avoid further processing.
  • Suppressing the suppression of the Handled flag.
  • Attached Events
  • Style EventSetters

Stay tuned 😉

Moq (basics, part 1)

How to perform tests when classes or interfaces cannot be instantiated properly?

Let’s say you want to run a test, which has dependencies to something that is not available. You are programming a chess game. A certain constellation needs to be tested, but to get there you need to play the game for at least 20 minutes. Surely, you cannot afford waiting that long. The game has to start right away at the required constellation. This can only be done by simulating certain conditions like the piece positions. The game is still being programmed. It does not have load/save functionality yet.
Assume there is a class called “PositionOfTheQueen”. We need to override existing code without touching the class source code.

And here comes Moq into play.

With Moq you can instantiate classes or interfaces and change their behaviour externally. Method “GetPosition” would not return a calculated value, but a constant that we injected from a test class.

Reference to Inversion of Control
Wiki Mock object
Moq quickstart

In Visual Studio 2013 go to your “Project” menu. Then click “Manage NuGet Packages” and a new window will open. Enter “Moq” in the “Search Online” text box. There are many Moq packages out there. We select the first one from Daniel Cazzulino. It has more than 1.3 million downloads and seems to have gone through teething troubles a long time ago. Press the “Install” button.

Moq

The Moq library will be added to your References automatically. You don’t have to do anything. Have a quick look at your Solution Explorer:

SolutionExplorer

Here is the example source code. It is self-explanatory. I have added several tests to highlight issues.

  • Moq uses standard default values for anything that has not been Setup().
  • Methods with arguments are only defined when they were part of a Setup(). The argument has to be the same when the method is called. Otherwise the method will return the default value. You can define ranges for valid arguments with the class It.
  • You can only moq something when it is public virtual. ((“private” is possible but generally of no use.))
  • By using Moq you disregard program code. Classes behave like interfaces.
  • SetupProperty() can be used for properties that have setters and getters. Use SetupGet() or SetupSet() where this is not the case.
  • Set a setter of a property to see if a specific value will be set later on. Change the string in row t2.SetOnly = “xxx”; lMock.Verify(); to observe the behavior. An exception will be raised to tell that the expected value has not been set during any set operation.
using System;

namespace Moq {

  public interface ITestInterface {
    string GetValue();
    string GetValue2();
  } // interface

  public class TestClass {

    public virtual string GetValue() { return "Genuine as genuine can be"; }
    public virtual string GetValue2() { return GetValue(); }
    public virtual string GetValue3(int x) { return x.ToString(); }
    public virtual string GetValue4(string x) { return x; }
    public virtual string SetOrGet { get; set; }
    public virtual string GetOnly { get { return "Value 6"; } }
    public virtual string SetOnly { set { } }

  } // class

  class Program {

    static void Main(string[] args) {

      // unaltered class
      TestClass t1 = new TestClass();
      Console.WriteLine("unaltered class:");
      Console.WriteLine("GetValue() == " + t1.GetValue());
      Console.WriteLine("GetValue2() == " + t1.GetValue2());
      Console.WriteLine("GetValue3(99) == " + t1.GetValue3(99));

      // mocked class
      Mock<TestClass> lMock = new Mock<TestClass>();
      lMock.Setup(x => x.GetValue()).Returns("You have been mocked!");
      TestClass t2 = lMock.Object;
      Console.WriteLine("\nMocked class:");
      Console.WriteLine("GetValue() == " + t2.GetValue());
      Console.WriteLine("GetValue2() == " + t2.GetValue2());
      Console.WriteLine("GetValue3(99) == " + t2.GetValue3(99));
      lMock.Setup(x => x.GetValue2()).Returns("You have been mocked again!");
      lMock.Setup(x => x.GetValue3(99)).Returns("11");
      //lMock.Setup(x => x.GetValue2()).Returns(() => "You have been mocked again!"); 
      Console.WriteLine("GetValue2() == " + t2.GetValue2());
      Console.WriteLine("GetValue3(99) == " + t2.GetValue3(99));
      Console.WriteLine("GetValue3(22) == " + t2.GetValue3(22));
      Console.WriteLine("After defining the range 22 to 200:");
      lMock.Setup(x => x.GetValue3(It.IsInRange(22, 200, Range.Inclusive))).Returns("in range from 22 to 200");
      Console.WriteLine("GetValue3(22) == " + t2.GetValue3(22));
      Console.WriteLine("GetValue3(99) == " + t2.GetValue3(99));
      lMock.Setup(x => x.GetValue4(It.IsAny<string>())).Returns("no");
      Console.WriteLine("GetValue4(\"yes\") == " + t2.GetValue4("yes"));


      // mocked interface
      Console.WriteLine("\nMocked interface:");
      Mock<ITestInterface> lMock2 = new Mock<ITestInterface>();
      lMock2.Setup(x => x.GetValue()).Returns("Fictitious result from the happy hunting ground");
      ITestInterface t3 = lMock2.Object;
      Console.WriteLine("GetValue() == " + t3.GetValue());
      Console.WriteLine("GetValue2() == " + t3.GetValue2());
      Console.WriteLine("After diverting GetValue2():");
      lMock2.Setup(x => x.GetValue2()).Returns(() => t3.GetValue());
      Console.WriteLine("GetValue2() == " + t3.GetValue2());


      // callbacks
      Console.WriteLine("\nCallbacks:");
      Action lBefore = () => Console.WriteLine("before callback");
      Action lAfter = () => Console.WriteLine("after callback");
      lMock.Setup(x => x.GetValue()).Returns("return value\n").Callback(lAfter);
      Console.WriteLine(t2.GetValue());
      lMock.Setup(x => x.GetValue()).Callback(lBefore).Returns("return value\n");
      Console.WriteLine(t2.GetValue());
      lMock.Setup(x => x.GetValue()).Callback(lBefore).Returns("return value\n").Callback(lAfter);
      Console.WriteLine(t2.GetValue());


      // Properties
      Console.WriteLine("\nProperties:");
      lMock.SetupProperty(x => x.SetOrGet, "initial value");
      // lMock.SetupProperty(x => x.GetOnly, "initial value");  throws exception, because GetOnly is readonly
      // instead use:
      lMock.SetupGet(x => x.GetOnly).Returns("initial value");
      lMock.SetupSet(x => x.SetOnly = "xxx").Verifiable(); // expect a value
      t2.SetOnly = "xxx"; lMock.Verify();
      //t2.SetOnly = "yyy"; lMock.Verify(); // exception: expected value does not match if t2.SetOnly was NEVER set to "xxx"
      t2.SetOrGet = "altered value";
      Console.WriteLine("SetOrGet == " + t2.SetOrGet);

      Console.ReadLine();
    } //

  } // class
} // namespace

example output:
unaltered class:
GetValue() == Genuine as genuine can be
GetValue2() == Genuine as genuine can be
GetValue3(99) == 99

Mocked class:
GetValue() == You have been mocked!
GetValue2() ==
GetValue3(99) ==
GetValue2() == You have been mocked again!
GetValue3(99) == 11
GetValue3(22) ==
After defining the range 22 to 200:
GetValue3(22) == in range from 22 to 200
GetValue3(99) == in range from 22 to 200
GetValue4(“yes”) == no

Mocked interface:
GetValue() == Fictitious result from the happy hunting ground
GetValue2() ==
After diverting GetValue2():
GetValue2() == Fictitious result from the happy hunting ground

Callbacks:
after callback
return value

before callback
return value

before callback
after callback
return value

Properties:
SetOrGet == altered value

Google Authenticator

GoogleAuthenticator

 

As promised a while ago I am going to describe the Google Authenticator today. I do not use my own example source code this time. There is a really nice one here that I will explain. Download the source code and get some extra information from this post. This should be enough know-how to use the Google Authenticator in your own application afterwards.

What is the Google Authenticator?
The Google Authenticator is a program that allows time based passwords. It makes the online identification process much safer. You enter your Id, your password and an extra time based password. A third-party can hardly know the time based password. Even if there is a spy program on your PC that reads all your key inputs, then the hacker only has less than 30 seconds to exploit the opportunity. Otherwise he cannot use your credentials. The time component changes constantly. This is a pretty safe approach.
To steal your identity, the hacker needs to get access to the server database and decrypt your information. This is much more difficult than reading your password by using a key Trojan.

What is TOTP?

Once again our example program is using WPF.
The XAML is pretty much straight forward. Each element (TextBlock or Image) is using Binding to the underlying object. Just the Hmac TextBlock is less intuitive. The text consists of 3 TextBlocks, which in fact look like one. The green text is the second TextBlock. There is no method to write all text into one TextBlock and then color it. This would be far more complex than this 3 TextBlock solution.

 

label


property binding


type


Identity Identity string
Secret Secret string
QR code QRCodeUrl Image
Timestamp Timestamp string
Hmac HmacPart1, HmacPart2, HmacPart3 string
One-time password OneTimePassword string
Seconds to go SecondsToGo string

 

The C# source code has some hyperlinks. You should follow them in case you want to learn some detailed background information. You don’t have to do this. To apply the code in your program it should be enough to study and replicate the example source code. This code is really short and I appreciate this a lot. Many programmers make things far more complicated than needed. Are they trying to show off? I don’t know.

Let’s start from the top now.
The DispatcherTimer is the corresponding class for the good old System.Windows.Forms.Timer class. We are not using WinForms anymore. The idea behind the DispatcherTimer is that the timer fires on the Dispatcher thread. This thread is the same that your window is using. Any other thread could freeze your application.
Do not use the System.Threading.Timer class. This class is neither WPF nor WinForms related. It fires on any thread. You must not access WPF elements on arbitrary threads. On the other hand you should use the System.Threading.Timer class in case you do not want to access WPF. Don’t waste precious time of the Dispatcher thread.

The DispatcherTimer fires each 500 ms (=half second) and assigns the actual value of the 30 second countdown to the property SecondsToGo.

The properties Secret and Identity are initialized with arbitrary example data.
Then the DataContext is set. This enables the data binding between the (XAML) window and the (C#) code.

public MainWindow() {
   InitializeComponent();

   var timer = new DispatcherTimer();
   timer.Interval = TimeSpan.FromMilliseconds(500);
   timer.Tick += (s, e) => SecondsToGo = 30 - Convert.ToInt32(GetUnixTimestamp() % 30);
   timer.IsEnabled = true;

   Secret = new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21, 0xDE, 0xAD, 0xBE, 0xEF };
   Identity = "user@host.com";

   DataContext = this;
}

You may have noticed already that the MainWindow class implements the interface INotifyPropertyChanged. This exposes a WPF event called PropertyChanged, which is used to notify clients via binding that a property value has changed.

namespace System.ComponentModel {
  public interface INotifyPropertyChanged {
    // Occurs when a property value changes.
    event PropertyChangedEventHandler PropertyChanged;
  }
}

You notify a client (UI) with the property name (string) rather than a delegate.
The standard WPF pattern looks like this:

public event PropertyChangedEventHandler PropertyChanged;  // INotifyPropertyChanged implementation

protected void OnPropertyChanged(string xPropertyName) {
   PropertyChangedEventHandler h = PropertyChanged;
   if (h == null) return;
   h(this, new PropertyChangedEventArgs(xPropertyName));
} //


private string _MyProperty;
public string  MyProperty { 
  get{ return _MyProperty; } 
  set { _MyProperty = value; OnPropertyChanged(“MyProperty”); } 
} //

And here is the source code from the GoogleAuthenticator example:

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged(string propertyName) {
 if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

private int _secondsToGo;
public int SecondsToGo {
   get { return _secondsToGo; }
   private set { _secondsToGo = value; OnPropertyChanged("SecondsToGo"); if (SecondsToGo == 30) CalculateOneTimePassword(); }
}

You can find that pattern many times in today’s example source code. Be aware that all properties use the same event, which is PropertyChanged. This makes your code look neat, but on the other hand you unfortunately start working with strings instead of delegates. It is part of the MVVM concept to separate code and GUI. For sure it makes debugging much more difficult and code execution slower.

Just to highlight it again. The Hmac consists of three elements. Therefore the property looks like this:

public byte[] Hmac {
  get { return _hmac; }
  private set { _hmac = value; OnPropertyChanged("Hmac"); OnPropertyChanged("HmacPart1"); OnPropertyChanged("HmacPart2"); OnPropertyChanged("HmacPart3"); }
}

What is an Hmac? To make complex interrelations easier, let’s reduce the Hmac description to “a long calculated key”, which is used to determine our time based password. Therefore to generate the key you need some kind of time input. The other component is a static password (=Secret). I added comments in the following code excerpt:

private void CalculateOneTimePassword() {
  // Get the number of seconds since 1/1/1970 and devide them by 30 seconds.
  // Thus one Timestamp unit is 30 seconds.
  Timestamp = Convert.ToInt64(GetUnixTimestamp() / 30);

  // Convert the 64 bit integer Timestamp to a byte array (8 bytes).
  // eg. ba d9 c7 02 00 00 00 00
  // Then reverse them (=> 00 00 00 00 02 c7 d9 ba) and write the result to the byte array "data".
   var data = BitConverter.GetBytes(Timestamp).Reverse().ToArray();

  // Generate the Hmac key from your password (byte array) and time (byte array).
  Hmac = new HMACSHA1(Secret).ComputeHash(data);

  // Bit-operation: Get the last 4 bits of the Hmac. The results are always equal to or between 0 and 15.
  // The offset determines the area of the Hmac that is used to generate the time based password.
  Offset = Hmac.Last() & 0x0F;

  // The Hmac is 20 bytes long. A block of 4 bytes is used for the OneTimePassword, which changes each 30 seconds.
  // 15 is the highest Offset. Therefore the last used byte is number 18 (first byte is zero based).
  // The 19th (=last) byte is the Offset. More precisely the <a href="http://en.wikipedia.org/wiki/Nibble" title="Wiki Nibble Byte" target="_blank">right nibble</a> of the 19th byte is the Offset value.
  // Bit masks are applied on the selected Hmac block to limit the number. The resulting bits are rotated to the left and added together.
  // Basically we are looking at a manual "bit to integer" conversion.
  // the result is then devided by 1,000,000 and only the remainder is taken. Consequently all results are less than 1,000,000.
  // (The bit mask 0xff is useless. I guess it was used to emphasize the technique for readability purposes. 0x7f does make sense.)
  OneTimePassword = (
         ((Hmac[Offset + 0] & 0x7f) << 24) |
         ((Hmac[Offset + 1] & 0xff) << 16) |
         ((Hmac[Offset + 2] & 0xff) << 8) |
         (Hmac[Offset + 3] & 0xff)) % 1000000;
}

When I looked at the program I was trying to find the bitmap for the QR code. You would expect a method somewhere to convert bytes to an image. But this is not the case.
The GetQRCodeUrl method generates a Url. Follow this Url and you will see that it opens an image in your browser. Google does the work for you.
The programmer of that example code has also added the Url to the description on how to generate such QR code Url. Well done! My advice is to have a quick look at it.

private string GetQRCodeUrl() {
  // https://code.google.com/p/google-authenticator/wiki/KeyUriFormat
  var base32Secret = Base32.Encode(Secret);
  return String.Format("https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/{0}%3Fsecret%3D{1}", Identity, base32Secret);
}

Now we have all bits and pieces to use the Google Authenticator. But how?

1) Ask for a user identification and a password. For instance user “super@man.com” and password “Strong5rThan$trong!”.
2) Convert the password to a byte array.
3) Generate the QR code.
4) The user can scan this QR code with his android cell phone. Press “Set up account” followed by “Scan a barcode” in the Google Authenticator app.
5) The new account appears and updates in the Authenticator app. The Identity and Secret were encoded in the QR code. This is why the app knows your name already.
 
Android
 
6) From now on you can ask for the Id, the password and the time based password.
7) Make sure to have a plan B in place. The user might lose access to his Google Authenticator app. You have to provide a new login then.

Btw. I do know some people, who do not lock their tablet PC or cell phone. The Google Authenticator obviously is not for these kind of people. The problem is not behind the screen … it is in front of the screen.

WPF Datagrid formatting (part 2, advanced)

Datagrid2

We stick to the previous DataGrid example and enhance it now.

The improvements/additions are:

  • Cells are vertically centered now.
  • Copy/paste includes the header text.
    ClipboardCopyMode="IncludeHeader"
    
  • Templates cannot be copied/pasted. The DataGrid does not know what property it has to read. Therefore a ClipboardContentBinding was added.
    ClipboardContentBinding="{Binding Birthday}
    
  • A yellow smiley is drawn on a Canvas with ellipses and a Bézier curve.
  • The birthday string is formatted.
  • The DataGrid rows use alternating colors.
  • CheckBoxes are centered in the cells.
  • A bit closer to hardcore: DatePicker
    The method to remove all borders requires slightly more know-how. The required information was taken from my earlier post WPF Control Templates (part 1). Also the background color of the DatePickerTextBox is made transparent. This is done without defining a new template for the DatePicker.

    The XAML definition

    <DatePicker SelectedDate="{Binding Birthday, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"  BorderThickness="0" Loaded="DataGrid_DatePicker_Loaded" />
    

    calls:

        private void DataGrid_DatePicker_Loaded(object sender, RoutedEventArgs e) {...}
    

    which in turn calls:

            private static void RemoveBorders(DependencyObject xDependencyObject) {...}
    
  • RowHeaders were added. On the internet you can find a lot of ToggleButton examples. You face the same code roots over and over again. To avoid coming up with a similar example I used a button with a +/- sign instead. This way you can easily change the code and replace the text by custom images.
  • My advice here is: Play with the FrozenColumnCount property. I am sure you will need it someday.
  • This example uses more templates than the last one.
  • RowDetailsTemplate was added. This enables expanding DataGrid rows to eg. show or enter additional information.
  • UpdateSourceTrigger makes sure you can see DataGridCell changes immediately on the RowDetailsTemplate.
    To achieve this, the class Person needs to inherit INotifyPropertyChanged.
<Window x:Class="WpfDatagrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        Language="en-GB"
        Loaded="Window_Loaded"
        Closed="Window_Closed"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>

        <!-- DataGrid: header style -->
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="VerticalContentAlignment" Value="Center" />
            <Setter Property="SeparatorBrush" Value="WhiteSmoke" />
            <Setter Property="FontWeight" Value="Bold" />
        </Style>

        <!--DataGrid: vertical/horizontal text alignment -->
        <Style x:Key="AlignRight" TargetType="{x:Type TextBlock}">
            <Setter Property="HorizontalAlignment" Value="Right" />
            <Setter	Property="VerticalAlignment" Value="Center" />
        </Style>
        <Style x:Key="AlignLeft" TargetType="{x:Type TextBlock}">
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter	Property="VerticalAlignment" Value="Center" />
        </Style>

        <!--DataGrid: center the CheckBox -->
        <Style x:Key="AlignCheckBox" TargetType="{x:Type DataGridCell}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridCell}">
                        <Grid Background="{TemplateBinding Background}">
                            <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- DataGrid: template for expandable area -->
        <DataTemplate x:Key="TemplateRowDetails">
            <DockPanel>
                <Canvas DockPanel.Dock="Left" Width="60">
                    <Canvas.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#FF061246" Offset="0.497"/>
                            <GradientStop Color="#FF7F7FC9" Offset="1"/>
                        </LinearGradientBrush>
                    </Canvas.Background>
                    <Ellipse Fill="Yellow" Height="50" Width="50" StrokeThickness="2" Stroke="Black" Canvas.Left="5" Canvas.Top="5" />
                    <Ellipse Fill="Black" Height="12" Width="8" Canvas.Left="17" Canvas.Top="20" />
                    <Ellipse Fill="Black" Height="12" Width="8" Canvas.Left="37" Canvas.Top="20" />
                    <Path Stroke="Black" StrokeThickness="3">
                        <Path.Data>
                            <PathGeometry>
                                <PathGeometry.Figures>
                                    <PathFigureCollection>
                                        <PathFigure StartPoint="15,37">
                                            <PathFigure.Segments>
                                                <PathSegmentCollection>
                                                    <QuadraticBezierSegment Point1="30,52" Point2="45,37" />
                                                </PathSegmentCollection>
                                            </PathFigure.Segments>
                                        </PathFigure>
                                    </PathFigureCollection>
                                </PathGeometry.Figures>
                            </PathGeometry>
                        </Path.Data>
                    </Path>
                </Canvas>
                <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold"	Text="{Binding FirstName}" />
                <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold"	Text="{Binding LastName}" />
                <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold"	Text="{Binding Birthday, StringFormat={}{0:dd MMMM yyyy}}" />
                <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold"	Text="{Binding Homepage}" />
            </DockPanel>
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <!-- advice: play with the property FrozenColumnCount -->
        <DataGrid AlternatingRowBackground="PeachPuff" 
                  AutoGenerateColumns="False" 
                  ItemsSource="{Binding}" 
                  CanUserAddRows="False" 
                  CanUserReorderColumns="True" 
                  CanUserResizeColumns="True" 
                  CanUserResizeRows="False" 
                  SelectionUnit="Cell" 
                  SelectionMode="Extended"
                  ClipboardCopyMode="IncludeHeader"
                  RowDetailsTemplate="{StaticResource TemplateRowDetails}"
                  ColumnHeaderHeight="{Binding RowHeight, RelativeSource={RelativeSource Self}}">


            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="DetailsVisibility" Value="Collapsed" />
                </Style>
            </DataGrid.RowStyle>

            <!-- DataGrid: RowHeader -->
            <DataGrid.RowHeaderTemplate>
                <DataTemplate>
                    <Button Click="DataGridRowHeader_Button_Click" Cursor="Hand" HorizontalAlignment="Center" >
                        <Button.Style>
                            <Style TargetType="Button">
                                <Style.Setters>
                                    <Setter Property="VerticalAlignment" Value="Top" />
                                    <Setter Property="Content" Value="+" />
                                    <Setter Property="FontStretch" Value="UltraExpanded" />
                                    <Setter Property="FontWeight" Value="Bold" />
                                    <Setter Property="Height" Value="20" />
                                    <Setter Property= "Width" Value="20" />
                                    <!-- <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}" /> -->
                                </Style.Setters>
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}},Path=DetailsVisibility}" Value="Visible">
                                        <Setter Property="Background" Value="Salmon" />
                                        <Setter Property="Content" Value="-" />
                                        <Setter Property="Height" Value="86" />
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </Button.Style>
                    </Button>
                </DataTemplate>
            </DataGrid.RowHeaderTemplate>

            <!-- DataGrid: Row color when selected -->
            <DataGrid.CellStyle>
                <Style>
                    <Style.Setters>
                        <Setter Property="DataGridCell.VerticalContentAlignment" Value="Center" />
                    </Style.Setters>
                    <Style.Triggers>
                        <Trigger Property="DataGridCell.IsSelected" Value="True">
                            <Setter Property="DataGridCell.Background" Value="SteelBlue" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.CellStyle>

            <DataGrid.Columns>
                <!-- Column: Alive -->
                <DataGridCheckBoxColumn Header="Alive" Binding="{Binding Alive, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" CellStyle="{StaticResource AlignCheckBox}" />

                <!-- Column: Name -->
                <DataGridTextColumn Header="Name" Binding="{Binding FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" ElementStyle="{StaticResource AlignLeft}" />

                <!-- Column: LastName -->
                <DataGridTextColumn Header="LastName" Binding="{Binding LastName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" ElementStyle="{StaticResource AlignLeft}" />

                <!-- Column: Birthday -->
                <DataGridTemplateColumn Header="Birthday" SortMemberPath="Birthday.Day" ClipboardContentBinding="{Binding Birthday}">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding Birthday, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"  BorderThickness="0" Loaded="DataGrid_DatePicker_Loaded" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

                <!-- Column: Age -->
                <DataGridTextColumn Header="Age" Binding="{Binding Age, StringFormat=N2}" ElementStyle="{StaticResource AlignRight}" IsReadOnly="True" />

                <!-- Column: Homepage -->
                <DataGridHyperlinkColumn Header="Homepage" Binding="{Binding Homepage}" IsReadOnly="True">
                    <DataGridHyperlinkColumn.ElementStyle>
                        <Style>
                            <EventSetter Event="Hyperlink.Click" Handler="Hyperlink_Clicked"/>
                            <Setter Property="TextBlock.HorizontalAlignment" Value="Left" />
                            <Setter Property="TextBlock.VerticalAlignment" Value="Center" />
                        </Style>
                    </DataGridHyperlinkColumn.ElementStyle>
                </DataGridHyperlinkColumn>

            </DataGrid.Columns>
        </DataGrid>
    </Grid>

</Window>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Media;

namespace WpfDatagrid {

  public partial class MainWindow : Window {

    public class Person : INotifyPropertyChanged {
      public event PropertyChangedEventHandler PropertyChanged;
      protected void OnPropertyChanged(string xName) {
        PropertyChangedEventHandler h = PropertyChanged;
        if (h == null) return;
        h(this, new PropertyChangedEventArgs(xName));
      } //

      private bool _Alive;
      public bool Alive { get { return _Alive; } set { _Alive = value; OnPropertyChanged("Alive"); } }

      private string _FirstName;
      public string FirstName { get { return _FirstName; } set { _FirstName = value; OnPropertyChanged("FirstName"); } }

      private string _LastName;
      public string LastName { get { return _LastName; } set { _LastName = value; OnPropertyChanged("LastName"); } }

      public double Age { get { return DateTime.Now.Subtract(Birthday).TotalDays / 365; } }
      
      public string Homepage { get; set; }

      private DateTime _Birthday;
      public DateTime Birthday { get { return _Birthday; } set { _Birthday = value; OnPropertyChanged("Birthday"); } }

      
    } // class


    public MainWindow() {
      InitializeComponent();
    } //

    // set the window DataContext
    private void Window_Loaded(object sender, RoutedEventArgs e) {
      List<Person> lPersons = new List<Person>();
      lPersons.Add(new Person() { FirstName = "Liza", LastName = "Minnelli", Birthday = new DateTime(1946, 03, 12), Alive = true, Homepage = "www.officiallizaminnelli.com" });
      lPersons.Add(new Person() { FirstName = "Bastian", LastName = "Ohta", Birthday = new DateTime(1975, 03, 13), Alive = true, Homepage = "www.ohta.de" });
      lPersons.Add(new Person() { FirstName = "Albert", LastName = "Einstein", Birthday = new DateTime(1879, 03, 14), Alive = false, Homepage = "www.alberteinsteinsite.com" });
      lPersons.Add(new Person() { FirstName = "Coenraad", LastName = "van Houten", Birthday = new DateTime(1801, 03, 15), Alive = false, Homepage = "www.vanhoutendrinks.com" });
      lPersons.Add(new Person() { FirstName = "Andrew", LastName = "Miller-Jones", Birthday = new DateTime(1910, 03, 16), Alive = false, Homepage = "dead as a Dodo" });
      lPersons.Add(new Person() { FirstName = "Gottlieb", LastName = "Daimler", Birthday = new DateTime(1834, 03, 17), Alive = false, Homepage = "www.daimler.com" });
      lPersons.Add(new Person() { FirstName = "Rudolf", LastName = "Diesel", Birthday = new DateTime(1858, 03, 18), Alive = false, Homepage = "http://en.wikipedia.org/wiki/Rudolf_Diesel" });
      DataContext = lPersons;
    } //

    // exit the application
    private void Window_Closed(object sender, EventArgs e) {
      Application.Current.Shutdown(0);
    } //

    // open the hyperlink in a browser
    private void Hyperlink_Clicked(object sender, RoutedEventArgs e) {
      try {
        Hyperlink lHyperlink = e.OriginalSource as Hyperlink;
        string lUri = lHyperlink.NavigateUri.OriginalString;
        Process.Start(lUri);
      }
      catch (Exception ex) { MessageBox.Show(ex.Message); }
    } //

    // find the correct DataGridRow and set the DetailsVisibility
    private void DataGridRowHeader_Button_Click(object sender, RoutedEventArgs e) {
      DependencyObject lDependencyObject = e.OriginalSource as DependencyObject;
      //Button lButton = lDependencyObject as Button;      
      //if (lButton == null) return;            
      while (!(lDependencyObject is DataGridRow) && lDependencyObject != null) lDependencyObject = VisualTreeHelper.GetParent(lDependencyObject);
      DataGridRow lRow = lDependencyObject as DataGridRow;
      if (lRow == null) return;
      //lRow.IsSelected = (lRow.DetailsVisibility != Visibility.Visible);            
      lRow.DetailsVisibility = lRow.DetailsVisibility == System.Windows.Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
      Console.WriteLine(lRow.ActualHeight);
    } //

    private void DataGrid_DatePicker_Loaded(object sender, RoutedEventArgs e) {
      // get the DatePicker control
      DatePicker lDatePicker = sender as DatePicker;
      lDatePicker.VerticalContentAlignment = System.Windows.VerticalAlignment.Center;

      // find the inner textbox and adjust the Background colour
      DatePickerTextBox lInnerTextBox = lDatePicker.Template.FindName("PART_TextBox", lDatePicker) as DatePickerTextBox;
      lInnerTextBox.Background = Brushes.Transparent;
      lInnerTextBox.VerticalContentAlignment = System.Windows.VerticalAlignment.Center;
      lInnerTextBox.Height = lDatePicker.ActualHeight - 2;

      // remove watermark
      ContentControl lWatermark = lInnerTextBox.Template.FindName("PART_Watermark", lInnerTextBox) as ContentControl;
      lWatermark.IsHitTestVisible = false;
      lWatermark.Focusable = false;
      lWatermark.Visibility = System.Windows.Visibility.Collapsed;
      lWatermark.Opacity = 0;

      // just as demo
      ContentControl lContentHost = lInnerTextBox.Template.FindName("PART_ContentHost", lInnerTextBox) as ContentControl;

      // remove ugly borders
      RemoveBorders(lInnerTextBox);  // hardcore 🙂      
    } //

    private static void RemoveBorders(DependencyObject xDependencyObject) {
      for (int i = 0, n = VisualTreeHelper.GetChildrenCount(xDependencyObject); i < n; i++) {
        DependencyObject lDependencyObject = VisualTreeHelper.GetChild(xDependencyObject, i);
        RemoveBorders(lDependencyObject);
        Border lBorder = lDependencyObject as Border;
        if (lBorder == null) continue;
        lBorder.BorderBrush = Brushes.Transparent;
      }
    } //

  } // class
} // namespace

WPF Datagrid formatting (part 1)

WpfDataGrid1

This source code demonstrates the use of a simple DataGrid. You can sort the rows by any column. The Age column is horizontally aligned to the right. The column headers are using a bold font.

The DataGrid element itself is very flexible. You can add all kinds of columns. The most interesting one is DataGridTemplateColumn, which allows you to add any template. The example template only uses a DatePicker, but you could add far more complexity to it.

Set the SortMemberPath to enable sorting, otherwise the DataGrid sorting algorithm cannot know what data to look at. Remember, we are using a template and not a clearly identifiable data type. In today’s example SortMemberPath is set to “Birthday.Day”, which sorts by the day of the month. In case you prefer to sort by date in general, use SortMemberPath=”Birthday” instead.

I changed the selection color, because the dark blue had a low contrast compared to the web-links. This is dealt with by style triggers. The advantage of triggers is that they only override properties temporarily. As soon as the trigger becomes invalid the control element returns to its previous formatting.

<Window x:Class="WpfDatagrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Language="en-GB"
        Loaded="Window_Loaded"
        Closed="Window_Closed"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="VerticalContentAlignment" Value="Center" />
            <Setter Property="SeparatorBrush" Value="WhiteSmoke" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Height" Value="30" />
        </Style>
        <Style x:Key="AlignRight" TargetType="{x:Type TextBlock}">
            <Setter Property="HorizontalAlignment" Value="Right" />
        </Style>
    </Window.Resources>

    <Grid>
        <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding}" CanUserAddRows="False" CanUserReorderColumns="True" CanUserResizeColumns="True" CanUserResizeRows="False" SelectionUnit="Cell" SelectionMode="Extended">
            <DataGrid.CellStyle>
                <Style>
                    <Style.Triggers>
                        <Trigger Property="DataGridCell.IsSelected" Value="True">
                            <Setter Property="DataGridCell.Background" Value="SteelBlue" />
                            <Setter Property="DataGridCell.BorderBrush" Value="GreenYellow" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.CellStyle>

            <DataGrid.Columns>
                <DataGridCheckBoxColumn Header="Alive" Binding="{Binding Alive}" />
                <DataGridTextColumn Header="Name" Binding="{Binding FirstName}" />
                <DataGridTextColumn Header="LastName" Binding="{Binding LastName}" />

                <!--<DataGridTemplateColumn Header="Birthday" SortMemberPath="Birthday">-->
                <DataGridTemplateColumn Header="Birthday" SortMemberPath="Birthday.Day">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding Birthday}" BorderThickness="0" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

                <DataGridTextColumn Header="Age" Binding="{Binding Age, StringFormat=N2}" ElementStyle="{StaticResource AlignRight}" IsReadOnly="True" />

                <DataGridHyperlinkColumn Header="Homepage" Binding="{Binding Homepage}" IsReadOnly="True">
                    <DataGridHyperlinkColumn.ElementStyle>
                        <Style>
                            <EventSetter Event="Hyperlink.Click" Handler="Hyperlink_Clicked"/>
                        </Style>
                    </DataGridHyperlinkColumn.ElementStyle>
                </DataGridHyperlinkColumn>



            </DataGrid.Columns>
        </DataGrid>
    </Grid>

</Window>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Documents;

namespace WpfDatagrid {

  public partial class MainWindow : Window {

    public class Person {
      public bool Alive { get; set; }
      public string FirstName { get; set; }
      public string LastName { get; set; }
      public DateTime Birthday { get; set; }
      public double Age { get { return DateTime.Now.Subtract(Birthday).TotalDays / 365; } }
      public string Homepage { get; set; }
    } //

    public MainWindow() {
      InitializeComponent();
    } //

    private void Window_Loaded(object sender, RoutedEventArgs e) {
      List<Person> lPersons = new List<Person>();
      lPersons.Add(new Person() { FirstName = "Liza", LastName = "Minnelli", Birthday = new DateTime(1946, 03, 12), Alive = true, Homepage = "www.officiallizaminnelli.com" });
      lPersons.Add(new Person() { FirstName = "Bastian", LastName = "Ohta", Birthday = new DateTime(1975, 03, 13), Alive = true, Homepage = "www.ohta.de" });
      lPersons.Add(new Person() { FirstName = "Albert", LastName = "Einstein", Birthday = new DateTime(1879, 03, 14), Alive = false, Homepage = "www.alberteinsteinsite.com" });
      lPersons.Add(new Person() { FirstName = "Coenraad", LastName = "van Houten", Birthday = new DateTime(1801, 03, 15), Alive = false, Homepage = "www.vanhoutendrinks.com" });
      lPersons.Add(new Person() { FirstName = "Andrew", LastName = "Miller-Jones", Birthday = new DateTime(1910, 03, 16), Alive = false, Homepage = "dead as a Dodo" });
      lPersons.Add(new Person() { FirstName = "Gottlieb", LastName = "Daimler", Birthday = new DateTime(1834, 03, 17), Alive = false, Homepage = "www.daimler.com" });
      lPersons.Add(new Person() { FirstName = "Rudolf", LastName = "Diesel", Birthday = new DateTime(1858, 03, 18), Alive = false, Homepage = "http://en.wikipedia.org/wiki/Rudolf_Diesel" });
      DataContext = lPersons;
    } //

    private void Window_Closed(object sender, EventArgs e) {
      Application.Current.Shutdown(0);      
    } //

    private void Hyperlink_Clicked(object sender, RoutedEventArgs e) {
      try {
        Hyperlink lHyperlink = e.OriginalSource as Hyperlink;
        string lUri = lHyperlink.NavigateUri.OriginalString;
        Process.Start(lUri);
      }
      catch (Exception ex) { MessageBox.Show(ex.Message); }
    } //

  } // class
} // namespace

WPF Control Templates (part 1)

ControlTemplate

Styles and Templates can change the appearance of elements. So what is the difference then?
Templates are far more complex. Styles are mainly adjusting existing properties. You could say that Styles are like Face-Lifting whereas Templates are rather entire face replacements. Elements get new visual trees that can consist of other elements. This is not the case for Styles.

Before we start creating our own templates let’s have a look at the existing standard control templates. Today’s example code reads these Templates from the assembly and prints them in a TextBox.

Take a stroll and get a feeling for them.
Surely this is not for beginners. My advice is to copy, paste and reuse existing professional XAML rather than spending your precious time to figure out every little issue yourself. And today’s source code aims at exactly that approach.

<Application x:Class="WpfTemplates.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             ShutdownMode="OnMainWindowClose"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>



<Window x:Class="WpfTemplates.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="Window_Loaded"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel LastChildFill="True">
        <ListBox DockPanel.Dock="Left" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" MinWidth="100" />
        <Grid DockPanel.Dock="Right" Name="dummyGrid" Width="0" />
        <TextBox DockPanel.Dock="Left" Text="{Binding XAML}" TextWrapping="NoWrap" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" FontFamily="Courier New" />
    </DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Xml;

namespace WpfTemplates {
  public partial class MainWindow : Window {

    private class Data {
      public Type Type { get; set; }
      public string XAML { get; set; }

      public Data(Type xType) { this.Type = xType; XAML = "#N/A"; }
      public override string ToString() { return Type.Name; }
    } // class

    public MainWindow() {
      InitializeComponent();
    } //

    private void Window_Loaded(object sender, RoutedEventArgs e) {
      List<Data> lData = new List<Data>();

      Assembly lAssembly = Assembly.GetAssembly(typeof(Control));
      Type lControlType = typeof(Control);
      List<Data> lTypes = (from t in lAssembly.GetTypes().AsParallel()
                           where t.IsSubclassOf(lControlType) && t.IsPublic && !t.IsAbstract
                           orderby t.Name ascending
                           select new Data(t)).ToList();

      InsertXaml(lTypes);
      DataContext = lTypes;
    } //

    private void InsertXaml(List<Data> xTypes) {
      XmlWriterSettings lXmlWriterSettings = new XmlWriterSettings();
      lXmlWriterSettings.Indent = true;
      StringBuilder lStringBuilder = new StringBuilder(); // for output      

      foreach (Data lData in xTypes) {
        try {
          ConstructorInfo lConstructorInfo = lData.Type.GetConstructor(System.Type.EmptyTypes);
          if (lConstructorInfo == null) {
            lData.XAML = lData.Type.Name + " control cannot be instantiated.";
            continue;
          }
          Control lControl = lConstructorInfo.Invoke(null) as Control;  // create an instance
          lControl.Visibility = System.Windows.Visibility.Collapsed;
          bool lIsNullTemplate = (lControl.Template == null);          
          if (lIsNullTemplate) dummyGrid.Children.Add(lControl); // add a collapsed (invisible) control to get access to the template
          ControlTemplate lControlTemplate = lControl.Template; // now not null anymore
          using (XmlWriter lXmlWriter = XmlWriter.Create(lStringBuilder, lXmlWriterSettings)) { // will write to StringBuilder
            XamlWriter.Save(lControlTemplate, lXmlWriter);
            lData.XAML = lStringBuilder.ToString();
          }
          lStringBuilder.Clear();
          if (lIsNullTemplate) dummyGrid.Children.Remove(lControl);
        }
        catch (Exception ex) {
          lData.XAML = lData.Type.Name + " control cannot be added to the grid.\n\nException message:\n" + ex.Message;
        }
      }
    } //

  } // class
} // namespace

WPF Commands (part 2)

Let’s start with a program that uses Cut, Copy and Paste in two TextBoxes without writing any C# code. This is not a typo. We only need XAML for this.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="400">    
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut it!"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy it!"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste it!"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>
    </DockPanel>
</Window>

Editor

 

I added a Toolbar with some dummy labels just to keep the learning curve going. You remove them without any risk.

What is happening here?

Some input controls handle command events on their own. Everything is built-in already. All you need to do is to provide the Buttons or MenuItems which call these commands. The elements even enable/disable themselves. We have two textboxes in the example. These commands are applied to the element that has the focus.
How can this be achieved? The element finds the window instance and then determines what element was focused previously. This only works for Toolbars and Menus UNLESS you set the CommandTarget property  manually.

Let’s add standard buttons now. You cannot see any effect when you press them. The buttons are even ghosted. To solve this we assign the names TextBox1 and TextBox2 and link the Button CommandTargets to these elements.

 

NotWorking

 

You can now cut or copy from TextBox1 and paste it into TextBox2.
 

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="400">    
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
<!-- changed -->
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
            <Button Command="{x:Static ApplicationCommands.Cut}" CommandTarget="{Binding ElementName=TextBox1}" Content="Cut" />
            <Button Command="{x:Static ApplicationCommands.Copy}" CommandTarget="{Binding ElementName=TextBox1}" Content="Copy" />
            <Button Command="{x:Static ApplicationCommands.Paste}" CommandTarget="{Binding ElementName=TextBox2}"  Content="Paste" />
        </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
<!-- changed -->
            <TextBox Name="TextBox1" TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
<!-- changed -->
            <TextBox Name="TextBox2" TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>

    </DockPanel>
</Window>

But hardcoding is a really bad approach. Therefore we are going to use FocusManager.IsFocusScope=”True” instead. WPF then checks the parent focus. By default, the Window class is a focus scope as are the Menu, ContextMenu, and ToolBar classes.
The following example is flawless.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="400">    
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
<!-- changed -->
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" FocusManager.IsFocusScope="True">
            <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
            <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
            <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
        </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>

    </DockPanel>
</Window>

The IsFocusScope approach has the advantage that the same commands apply to several controls.

 
 
Custom Commands
 

We are going to write our own commands now. For this we need to create a class and add a property that returns a RoutedUICommand instance. This property needs to be static. And to initialize this class you also need a static constructor.

using System.Windows.Input;

namespace CustomCommands {
 
  public class PlaySound {

    static PlaySound() {
      KeyGesture lShortCut = new KeyGesture(Key.P, ModifierKeys.Control, "Ctrl+p");
      InputGestureCollection InputGestureCollection = new InputGestureCollection();
      InputGestureCollection.Add(lShortCut);
      PlaySoundCommand = new RoutedUICommand("Play", "PlaySound", typeof(PlaySound), InputGestureCollection);      
    } // static constructor

    public static RoutedUICommand PlaySoundCommand { get; private set; }
  } // class

} // namespace

The MainWindow class should look like this. The method CommandBinding_PlaySound_Executed plays the system beep sound.

using System.Windows;
using System.Windows.Input;

namespace DemoApp {

  public partial class MainWindow : Window {

    public MainWindow() {
      InitializeComponent();
    }

   private void CommandBinding_PlaySound_Executed(object sender, ExecutedRoutedEventArgs e) {
      System.Media.SystemSounds.Beep.Play();      
      MessageBox.Show("Source: " + e.Source.ToString() + Environment.NewLine + 
        "OriginalSource: " + e.OriginalSource.ToString() + Environment.NewLine + 
        "Parameter: " + e.Parameter.ToString());
    } //

  } // class
} // namespace

Add the class in your XAML namespace. I used xmlns:c=”clr-namespace:CustomCommands” .

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:c="clr-namespace:CustomCommands"
        Title="MainWindow" Height="400" Width="400">
<!-- above was changed -->
    <Window.CommandBindings>
<!-- changed -->
        <CommandBinding Command="c:PlaySound.PlaySoundCommand" Executed="CommandBinding_PlaySound_Executed" />
    </Window.CommandBindings>
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste"/>
            </MenuItem>
            <MenuItem Header="_Media">
                <MenuItem Command="c:PlaySound.PlaySoundCommand" CommandParameter="Play"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" FocusManager.IsFocusScope="True">
            <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
            <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
            <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
<!-- changed -->
            <Button Command="c:PlaySound.PlaySoundCommand" Content="Play" CommandParameter="What a lovely song!" />
        </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>

    </DockPanel>
</Window>

PlaySound

There is a shortcut to calling commands. You can create an ICommand instance and provide it via a property. The downside – what did you expect? – is that you have no shortcut key or any other comfort.

Step 1: Create a class that inherits from interface ICommand.

using System;
using System.Windows.Input;

namespace CustomCommands {

  public class PlaySound2 : ICommand {
    object _DependencyObject;

    public PlaySound2(object xDependencyObject) {
      _DependencyObject = xDependencyObject;
    } // constructor

    public event EventHandler CanExecuteChanged {
      add { CommandManager.RequerySuggested += value; }
      remove { CommandManager.RequerySuggested -= value; }
    } //

    public bool CanExecute(object xParameter) {
      return (DateTime.Now.Second % 2 == 0); // timer based example
    } //

    public void Execute(object xParameter) {
      //_DependencyObject.DoSomething();
      System.Windows.MessageBox.Show("Parameter: " + xParameter.ToString());
      System.Media.SystemSounds.Beep.Play();
    } //


  } // class
} // namespace

Step 2: instantiate that class and provide it via a property. You do not need to expose the class in your MainWindow. You can use any class. Set the DataContext to your class where the property is (or use a precise path that leads to that object).

using CustomCommands;
using System;
using System.Windows;
using System.Windows.Input;

namespace DemoApp {

  public partial class MainWindow : Window {

    public MainWindow() {
      InitializeComponent();
      SimpleExecution = new PlaySound2("dummy");
      DataContext = this;
    }

    private void CommandBinding_PlaySound_Executed(object sender, ExecutedRoutedEventArgs e) {
      System.Media.SystemSounds.Beep.Play();
      MessageBox.Show("Source: " + e.Source.ToString() + Environment.NewLine +
        "OriginalSource: " + e.OriginalSource.ToString() + Environment.NewLine +
        "Parameter: " + e.Parameter.ToString());
    } //

    public ICommand SimpleExecution { get; private set; }

  } // class
} // namespace

Step 3: Bind the command in XAML.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:c="clr-namespace:CustomCommands"
        Title="MainWindow" Height="400" Width="400">
    <Window.CommandBindings>
        <CommandBinding Command="c:PlaySound.PlaySoundCommand" Executed="CommandBinding_PlaySound_Executed" />
    </Window.CommandBindings>
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste"/>
            </MenuItem>
            <MenuItem Header="_Media">
                <MenuItem Command="c:PlaySound.PlaySoundCommand" CommandParameter="Play"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" FocusManager.IsFocusScope="True">
            <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
            <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
            <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            <Button Command="c:PlaySound.PlaySoundCommand" Content="Play" CommandParameter="What a lovely song!" />
<!-- changed -->
            <Button Command="{Binding SimpleExecution}" Content="StraightForward" CommandParameter="The German way!" />
       </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>

    </DockPanel>
</Window>

LastExample

That’s it for today 🙂

WPF Commands (part 1)

Due to personal time limitations I add a shorter post today. Nonetheless this post is vital for programmers without any WPF experience.

Events are fairly low-level and deprecated in WPF to a certain degree. They are against the idea of MVVM, which in simple terms is the separation of code and user interface. The new technology is task based – known as commands. Commands act like glue between the user interface and the code. You can avoid a lot of repetitive event-handling code. They deal with text captions and enabled/disabled state synchronizations. Let’s have a look at the ICommand interface:

namespace System.Windows.Input {

   public interface ICommand {
      event EventHandler CanExecuteChanged;
      bool CanExecute(object parameter);
      void Execute(object parameter);
   } // interface

} // namespace

The interface ICommand is inherited by RoutedCommand and indirectly by RoutedUICommand. RoutedUICommand has an additional descriptive text property, which RoutedCommand does not have. Besides this they are the same. RoutedUICommand inherits from RoutedCommand and is used for commands that display some text in the UI like menu items or tooltips.

namespace System.Windows.Input {

   public class RoutedUICommand : RoutedCommand {
      public RoutedUICommand();
      public RoutedUICommand(string text, string name, Type ownerType);
      public RoutedUICommand(string text, string name, Type ownerType, InputGestureCollection inputGestures);
      public string Text { get; set; }       // Text that describes this command.
   } // class

} // namespace

RoutedCommand is the only class in WPF that inherits from ICommand. All other classes are derived from RoutedCommand. An important feature of RoutedCommand in WPF is the so-called bubbling behavior. When you have a button in a StackPanel, then events will be executed in that order: Button -> StackPanel -> Window. I will keep it simple here and explain that behavior in another posts.

WPF has prebuild commands like Cut, Copy, Paste, Open and Print. There is no code behind these commands. You have to bind them to your code. Bubbling does play a big role here. You could press Ctrl+C to copy a text. The same command could be part of a TextBox and a window menu. The bubbling can be used to place the same command in two different places. The key input triggers the window command and provides enough information to process it.
Prebuild commands define a standard and generally increase code reusability.

Notice that RoutedCommand has its enhanced versions of CanExecute() and Execute():

namespace System.Windows.Input {

   public class RoutedCommand : RoutedCommand {
      public RoutedCommand();
      public RoutedCommand(string name, Type ownerType);
      public RoutedCommand(string name, Type ownerType, InputGestureCollection inputGestures);
      public InputGestureCollection InputGestures { get; }
      public string Name { get; }
      public Type OwnerType { get; }

      public event EventHandler CanExecuteChanged;
      public bool CanExecute(object parameter, IInputElement target);
      public void Execute(object parameter, IInputElement target);
   } // class

} // namespace

This is confusing. You naturally expect the same definition as in ICommand. The answer must be that the interface ICommand is implemented explicitly. Thus the interface method is hidden and can only be accessed indirectly via an interface variable. See below example:

public interface IMyInterface {
    void hello(object o);
} // interface

public class MyClass : IMyInterface {
  public void hello(object i, string s) { }
  void IMyInterface.hello(object o) {}
} // class

static void Main(string[] args) {
  MyClass x = new MyClass();       
  x.hello("abc", "abc");  // interface not accessible
  IMyInterface c = x;
  c.hello("abc");  // class not accessible
}

There are several groups (static classes) of prebuild commands in WPF.
ApplicationCommands provides classical commands that are in most applications (eg. Cut, Copy, Paste, Save, New, Print).
NavigationCommands provide commands for navigation that you know from browsers (eg. BrowseForward, BrowseBack).
EditingCommands are known from text editors (eg. Delete, MoveToDocumentEnd, MoveRightByWord, DecreaseFontSize).
ComponentCommands are used to move the cursor around (some duplicates are in EditingCommands; eg. MoveDown, MoveFocusBack, ExtendSelectionDown).
MediaCommands are self-explanatory (eg. Play, Pause, Record, BoostBass, ChannelDown).

These classes are static, there can only one instance in your application. They all have default keystrokes. For instance Ctrl+C is predefined for Copy. When you bind them to a command source and add that command source to a window, then the key combination becomes active. You don’t even need a visible control. An additional feature is that key combinations of commands are automatically shown in menus.

We had some theory now. Let’s get practical:

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="200">
    <StackPanel>
        <Button Command="{x:Static ApplicationCommands.New}" CommandParameter="NewProjectX" Content="New" FontSize="20" />
    </StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Input;

namespace DemoApp {

  public partial class MainWindow : Window {

    public MainWindow() {
      InitializeComponent();

      CommandBinding lCommandBinding = new CommandBinding(ApplicationCommands.New);
      lCommandBinding.Executed += Button_Pressed;
      CommandBindings.Add(lCommandBinding); // add the binding object to our main "window" instance
    } //

    private void Button_Pressed(object sender, ExecutedRoutedEventArgs e) {
      MessageBox.Show(sender.ToString() + " did send the message: " + e.Parameter.ToString() + Environment.NewLine + "OriginalSource: " + e.OriginalSource);
    } //

  } // class
} // namespace

Window1

Window2

You don’t have to add the command in your C# code. You can add it directly in XAML. This can be more comfortable. Unfortunately there is a downside as well. The IntelliSense support suffers and I personally believe that it is more error-prone.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="200">
    <Window.CommandBindings>
        <CommandBinding Command="{x:Static ApplicationCommands.New}" Executed="Button_Pressed" />
    </Window.CommandBindings>
    <StackPanel>
        <Button Command="{x:Static ApplicationCommands.New}" CommandParameter="NewProjectX" Content="New" FontSize="20" />
    </StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Input;

namespace DemoApp {

  public partial class MainWindow : Window {

    public MainWindow() {
      InitializeComponent();

      //CommandBinding lCommandBinding = new CommandBinding(ApplicationCommands.New);
      //lCommandBinding.Executed += Button_Pressed;
      //CommandBindings.Add(lCommandBinding); // add the binding object to the window
    } //

    private void Button_Pressed(object sender, ExecutedRoutedEventArgs e) {
      MessageBox.Show(sender.ToString() + " did send the message: " + e.Parameter.ToString() + Environment.NewLine + "OriginalSource: " + e.OriginalSource);
    } //

  } // class
} // namespace

The next example adds a menu. The shortcut Ctrl+N is automatically shown. There is a slight change for the button as well. The object content (text) now binds to itself and uses the text from the command. The advantage is that you hardcode less and become more flexible on multi-language support later on.
You don’t have to change anything in the C# source code.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="200">
    <Window.CommandBindings>
        <CommandBinding Command="{x:Static ApplicationCommands.New}" Executed="Button_Pressed" />
    </Window.CommandBindings>
    <StackPanel>
        <Menu>
            <MenuItem Header="_File">
                <MenuItem Command="{x:Static ApplicationCommands.New}" CommandParameter="NewProject_Y"/>
            </MenuItem>
        </Menu>
        <Separator/>
        <Button Command="{x:Static ApplicationCommands.New}" CommandParameter="NewProject_X" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" FontSize="20" />
    </StackPanel>
</Window>

Window3

Window4

Final note: Do not use the old school WinForms like approach anymore:

<Button Click="Button_Click" CommandParameter="NewProject_C" FontSize="20">Click</Button>
private void Button_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Button clicked"); } 

The next post will follow-up on custom commands.