Click here to Skip to main content
15,913,685 members
Articles / Programming Languages / C# 4.0
Tip/Trick

Mouse Tracking and Binding

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
18 Jun 2013MIT2 min read 8.1K   146   3  
Mouse tracking and mouse binding.

Introduction

Have you ever wanted to bind something to the mouse's x and y coordinates? Ever get frustrated by the times WPF consumes mouse events? Then the MouseTracker class will probably be helpful!

Background

Tying directly into the Windows API allows us to bypass the .NET Framework. However, this also introduces a few issues you will have to consider before doing so. There is a note in the MouseTracker.cs file!

The three big down sides about WPF's mouse implementation are: that you cannot make global mouse handlers, you must attach mouse handlers to IInputElement objects, and that there is no mouse DependencyObject that can be used for binding. That being said there's still a way to achieve almost any objective with the mouse implementation provided by Microsoft. Easily being able to make a popup follow the mouse seems to be one of the biggest problems people face with this, myself included. Although, getting this to work right is very helpful for aesthetics in drag 'n' drop scenarios.

Using the code

In the MouseTracker class I did not implement all mouse events possible by the Windows API. You can always add more if you want, just look at the mouse values in WINUSER.H. You can Google where to get a copy. When you have it, look for the value WM_MOUSEMOVE in the file. The values that immediately follow are the mouse events possible.

Here is a basic implementation of the MouseTracker...

C#
MT = new MouseTracker();
MT.MouseLeftButtonDown += MT_MouseLeftButtonDown;
MT.MouseLeftButtonUp += MT_MouseLeftButtonUp;
MT.MouseRightButtonDown += MT_MouseRightButtonDown;
MT.MouseRightButtonUp += MT_MouseRightButtonUp;
MT.MouseXChanged += MT_MouseXChanged;
MT.MouseYChanged += MT_MouseYChanged;

private void MT_MouseLeftButtonDown(object sender, EventArgs e)
{
    // do something
}

private void MT_MouseLeftButtonUp(object sender, EventArgs e)
{
    // do something
}

private void MT_MouseRightButtonDown(object sender, EventArgs e)
{
    // do something
}

private void MT_MouseRightButtonUp(object sender, EventArgs e)
{
    // do something
}

private void MT_MouseXChanged(object sender, EventArgs e)
{
    // do something
}

private void MT_MouseYChanged(object sender, EventArgs e)
{
    // do something
}

As you can see it is similar to what you are used to. Let's look at the part I like. Binding a popup's location to the mouse for a drag 'n' drop setup. Let's say you want to "rip" out a TreeViewItem from a TreeView and display it in a popup so it can be dropped into another TreeView. Or maybe, have the TreeViewItems' content display in a Window on LeftMouseButtonUp (...tabs to windows...hmmmm). Here is a slimmed down version of that, minus drag 'n' drop...and the other TreeView. :)

XML
<TreeView Name="treeView" MouseLeave="treeView_MouseLeave">
    <TreeViewItem Header="One" />
    <TreeViewItem Header="Two">
        <TreeViewItem Header="Two-One" />
    </TreeViewItem>
    <TreeViewItem Header="Three" />
    <TreeViewItem Header="Four" />
    <TreeViewItem Header="Five">
        <TreeViewItem Header="Five-One" />
    </TreeViewItem>
</TreeView>
C#
private MouseTracker MT { get; set; }
private Popup DragDisplay { get; set; }

public MainWindow()
{
    InitializeComponent();

    MT = new MouseTracker();
    MT.MouseLeftButtonUp += MT_MouseLeftButtonUp;            
}

private void MT_MouseLeftButtonUp(object sender, EventArgs e)
{
    if (DragDisplay != null)
    {
        DragDisplay.IsOpen = false;
        DragDisplay = null;
    }
}

private void treeView_MouseLeave(object sender, MouseEventArgs e)
{
    if (treeView.SelectedItem != null && e.LeftButton == MouseButtonState.Pressed)
    {
        DragDisplay = new Popup();
        DragDisplay.AllowsTransparency = true;
        DragDisplay.Placement = PlacementMode.Absolute;
        DragDisplay.StaysOpen = true;

        Border border = new Border()
        {
            Background = Brushes.LightGray,
            BorderBrush = Brushes.Gray,
            BorderThickness = new Thickness(1),
            Child = new ContentPresenter() 
                    { 
                        Content = treeView.SelectedItem.ToString(),
                        Margin = new Thickness(5, 10, 5, 10)
                    }
        };

        DragDisplay.Child = border;

        Binding leftBinding = new Binding("MouseX");
        leftBinding.Mode = BindingMode.OneWay;
        leftBinding.Source = MT;

        Binding topBinding = new Binding("MouseY");
        topBinding.Mode = BindingMode.OneWay;
        topBinding.Source = MT;

        DragDisplay.SetBinding(Popup.HorizontalOffsetProperty, leftBinding);
        DragDisplay.SetBinding(Popup.VerticalOffsetProperty, topBinding);

        DragDisplay.IsOpen = true;
    }
}

Run your main window and "rip" out TreeViewItems and see their ToString representation. Download the source and demo project for the MouseTracker DependencyObject and a better example.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Architect SL-X
United States United States
Developed various languages over the years. Found C# and fell in love with it. Been doing it ever since. Love WPF or ASP.Net MVC with the Razor view engine as front-end technologies. As a developer I want to make development easier for all developers. I like designing and providing tools for other programmers to use.

Comments and Discussions

 
-- There are no messages in this forum --