Skip to main content

C# WPF Tutotial - Getting the Double Click Event [Beginner]



In Win Forms, everything that derived from System.Windows.Forms.Control had the MouseDoubleClick event - and not suprisingly, in WPF, everything derived from System.Windows.Controls.Control also has a MouseDoubleClick event. But there is a key difference - in WinForms, almost everything that gets displayed on the screen is derived from System.Windows.Forms.Control in some way - while in WPF, there are a number of items you can put on the screen that do not actually derive from System.Windows.Controls.Control. So today we are going to take a look at how to get double clicks when you are not derived from System.Windows.Controls.Control.

To figure this out, we are going to write a little app with a TextBlock - and when you double click on the TextBlock, it switches to a TextBox where you can edit the text. When you are done editing the text, you can double click in the TextBox, and it switches back to the TextBlock with the new text that you have entered. You can see screenshots of the two states of this simple app below:

Double Click App Test
Screenshot

OK, so the issue here is that TextBlock does not derive from Control (it derives from FrameworkElement), so it does not have a MouseDoubleClick event to attach to. So what do we do? Well, it is actually really simple - lets take a look at the xaml behind this sample app first:
<Window x:Class="DoubleClickTest.DoubleClickWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DoubleClickTest" Height="100" Width="200" x:Name="MyWindow">
  <Canvas Margin="10">
    <TextBlock Name="MyBlock" MouseDown="MyBlock_MouseDown"
        Text="{Binding ElementName=MyWindow, Path=MyText}"/>
    <TextBox Visibility="Collapsed" Name="MyBox" 
        MouseDoubleClick="MyBox_MouseDoubleClick" >
      <TextBox.Text>
        <Binding Path="MyText" ElementName="MyWindow" 
            UpdateSourceTrigger="PropertyChanged" />
      </TextBox.Text>
    </TextBox>
  </Canvas>
</Window>
 
So as you can see, we just have a TextBlock and a TextBox, one visible and one not. On the TextBox we have attached to the MouseDoubleClick event, and on the TextBlock we have attached to the MouseDown event. So, as you might have suspected, we will be using the MouseDown event to figure out if a double click has occurred. So onto the code behind:
public partial class DoubleClickWindow : Window
{
  public DoubleClickWindow()
  {
    InitializeComponent();
  }

  public string MyText
  {
    get { return (string)GetValue(MyTextProperty); }
    set { SetValue(MyTextProperty, value); }
  }

  public static readonly DependencyProperty MyTextProperty =
      DependencyProperty.Register("MyText", typeof(string), 
        typeof(DoubleClickWindow), new UIPropertyMetadata("This Is Some Text Of Mine"));

  private void MyBlock_MouseDown(object sender, MouseButtonEventArgs e)
  {
    if (e.ClickCount == 2)
    {
      MyBlock.Visibility = Visibility.Collapsed;
      MyBox.Visibility = Visibility.Visible;
    }
  }

  private void MyBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
  {

    MyBox.Visibility = Visibility.Collapsed;
    MyBlock.Visibility = Visibility.Visible;
  }
}
 
So here we have the whole code behind class for DoubleClickWindow. Not much here, just a constructor, the dependency property that the TextBlock and TextBox are bound to, and the two event functions.

And it is one of those event functions that we care about - the MyBlock_MouseDown method. And what do we have here - a ClickCount number in the MouseButtonEventArgs! The ClickCount property holds the number of times the mouse button has been clicked within the system double click time (you know, that slider for double click speed in the mouse control panel). If you want to know if the user has clicked twice, you just have to check and see if the ClickCount is equal to 2 - and that is exactly what we do here. If it is equal to 2, we switch the visibilities on the TextBlock and the TextBox.

The interesting thing about the ClickCount is that you can do something like listen for a triple or even quadruple click. I have no idea why you would want to do such a thing :P - but it is possible. You can also get this information in any click or mouse up event (or any of the corresponding preview events) - any event that gives you the MouseButtonEventArgs as the argument to the event will have the click count information.

Oh, and I suppose we can't forget the last function in the class - MouseDoubleClick, which is hooked to the actual double click event on the TextBox. Of course here we don't have to check if it is a double click (the code wouldn't be executing otherwise) - we just flip the visibilities back. And, just as a side note, if you dive down into the code of Control (where this double click event comes from), you find that all they are doing is triggering the event when the ClickCount of the current mouse down event is equal to 2.

Hope that cleared up any confusion that you may have had about double click events in WPF! I know I was confused for a little while as to why there wasn't a MouseDoubleClick event available everywhere.

Comments

Popular posts from this blog

C# Snippet - Shuffling a Dictionary [Beginner]

Randomizing something can be a daunting task, especially with all the algorithms out there. However, sometimes you just need to shuffle things up, in a simple, yet effective manner. Today we are going to take a quick look at an easy and simple way to randomize a dictionary, which is most likely something that you may be using in a complex application. The tricky thing about ordering dictionaries is that...well they are not ordered to begin with. Typically they are a chaotic collection of key/value pairs. There is no first element or last element, just elements. This is why it is a little tricky to randomize them. Before we get started, we need to build a quick dictionary. For this tutorial, we will be doing an extremely simple string/int dictionary, but rest assured the steps we take can be used for any kind of dictionary you can come up with, no matter what object types you use. Dictionary < String , int > origin = new Dictionary < string , int >();

C# Snippet - The Many Uses Of The Using Keyword [Beginner]

What is the first thing that pops into your mind when you think of the using keyword for C#? Probably those lines that always appear at the top of C# code files - the lines that import types from other namespaces into your code. But while that is the most common use of the using keyword, it is not the only one. Today we are going to take a look at the different uses of the using keyword and what they are useful for. The Using Directive There are two main categories of use for the using keyword - as a "Using Directive" and as a "Using Statement". The lines at the top of a C# file are directives, but that is not the only place they can go. They can also go inside of a namespace block, but they have to be before any other elements declared in the namespace (i.e., you can't add a using statement after a class declaration). Namespace Importing This is by far the most common use of the keyword - it is rare that you see a C# file that does not h

C# WPF Printing Part 2 - Pagination [Intermediate]

About two weeks ago, we had a tutorial here at SOTC on the basics of printing in WPF . It covered the standard stuff, like popping the print dialog, and what you needed to do to print visuals (both created in XAML and on the fly). But really, that's barely scratching the surface - any decent printing system in pretty much any application needs to be able to do a lot more than that. So today, we are going to take one more baby step forward into the world of printing - we are going to take a look at pagination. The main class that we will need to do pagination is the DocumentPaginator . I mentioned this class very briefly in the previous tutorial, but only in the context of the printing methods on PrintDialog , PrintVisual (which we focused on last time) and PrintDocument (which we will be focusing on today). This PrintDocument function takes a DocumentPaginator to print - and this is why we need to create one. Unfortunately, making a DocumentPaginator is not as easy as