#682 – Panel Elements Only Fire Mouse Events When Background Is Set

If you create an element derived from Panel, like Canvas, and wire up any of the mouse-related events, you’ll notice that you don’t see your events unless you’ve set the Background property of the Panel.  You will, however, see the routed events when a child element of the canvas originates the event.

In the example below, we don’t see MouseMove event on the Canvas unless we’re moving the mouse over one of the child Buttons.

    <Canvas MouseMove="Canvas_MouseMove">
        <Button Content="Preston Sturges" MouseMove="Button_MouseMove"
                Canvas.Left="10" Canvas.Top="10"/>
        <Button Content="John Ford" MouseMove="Button_MouseMove"
                Canvas.Left="10" Canvas.Bottom="10"/>
        <Button Content="Michael Curtiz" MouseMove="Button_MouseMove"
                Canvas.Right="10" Canvas.Top="10"/>
    </Canvas>

If you do want to see mouse events on a Panel, you need to explicitly set its Background property.  If you don’t want a background color, you can just set the property to Transparent.

    <Canvas MouseMove="Canvas_MouseMove" Background="Transparent">

Advertisements

#670 – Getting the Mouse Position Relative to a Specific Element

When you use the Mouse.GetPosition method or MouseButtonEventsArgs.GetPosition method to get the mouse position, you specify that you want the mouse position relative to a particular element.

If you pass a null value into the GetPosition method, you indicate that you want the mouse position relative to the containing window.    However, you can also pass a reference to a control that implements the IInputElement interface.  Since UIElement implements IInputElement, you can pass in a reference to any user interface element.

In the example below, on mouse movement, we display the coordinates of the mouse position relative to the main window, as well as relative to a Button.

        private void win1_MouseMove_1(object sender, MouseEventArgs e)
        {
            Point p = e.GetPosition(null);
            MousePosText = string.Format("GetPosition(null): X = {0}, Y = {1}", p.X, p.Y);

            p = e.GetPosition(btn1);
            MousePosText2 = string.Format("GetPosition(btn1): X = {0}, Y = {1}", p.X, p.Y);
        }



#664 – MouseEnter and MouseLeave Events

An UIElement will fire a MouseEnter event when its IsMouseOver property becomes true.  It will fire a MouseLeave event when its IsMouseOver property becomes false.

These are both direct events, i.e. they don’t bubble or tunnel, but fire only for the UIElement whose IsMouseOver property is changing.

Suppose that we have a Button contained in a StackPanel that is in a Window.

If we move the mouse into the area of the Window that is not covered by the StackPanel, the MouseEnter for the Window will fire.

If we then move into the StackPanel, we’ll get a MouseEnter for the StackPanel, but we will not get a MouseLeave event for the Window–because the pointer is still located in the Window.

 

Moving over the Button fires its MouseEnter event.

 

Moving out of the Button along its top edge triggers MouseLeave events for the Button, the StackPanel, and the Window.

 

#662 – IsMouseOver Property

Every UIElement object has an IsMouseOver property that indicates whether or not the mouse is currently located over the element.

In the example below, we define a Label whose content is bound to the current state of the IsMouseOver property for a Button.

    <StackPanel Margin="20">
        <Button Name="btn1" Content="Move Mouse Over Me !" HorizontalAlignment="Center" Padding="10,5"/>
        <Label Content="{Binding ElementName=btn1, Path=IsMouseOver}" Foreground="Green"/>
    </StackPanel>


#661 – ButtonBase.Click Event vs. Mouse Click Events

Controls that derive from ButtonBase, like the standard Button, inherit a Click event that fires when user clicks on the button using the left mouse button.

Because ButtonBase inherits from UIElement, a Button will also have access to all of the mouse button events defined for UIElement.

Because the Button does something in response to button presses, it swallows the bubbling events (e.g. MouseLeftButtonDown and MouseDown).  You can still detect these lower level button press events by adding handlers for the tunneling events (e.g. PreviewMouseLeftButtonDown and PreviewMouseDown).  You can also request that your handlers are called even for already-handled events by specifying a handler in code and setting the handledEventsToo parameter to true.

For a left-click on a Button, you’ll normally see click-related events in the following order:

  • UIElement.PreviewMouseLeftButtonDown 
  • UIElement.PreviewMouseDown
  • UIElement.PreviewMouseLeftButtonUp
  • UIElement.PreviewMouseUp
  • ButtonBase.Click

#659 – Detecting a Triple Click

Although not very common in user interfaces, you can use the MouseButtonEventArgs.ClickCount property, available in the PreviewMouseDown or MouseDown events, to detect a triple click.  (You can also detect right vs. left mouse button clicks using the button specific events, e.g. MouseLeftButtonDown and MouseRightButtonDown).

In the example below, double clicking on the Label does nothing.  But a triple click, with either button, toggles the background color of the label.

    <StackPanel Margin="20" >
        <Label Content="Triple-click on me" Margin="20"
               MouseDown="Label_MouseDown" />
    </StackPanel>

In the event handler, we check ClickCount and change the Background of the Label if it’s equal to 3 (a triple click).

        private bool colorToggled = false;

        private void Label_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 3)
            {
                if (!colorToggled)
                {
                    ((Label)sender).Background = Brushes.Blue;
                    colorToggled = true;
                }
                else
                {
                    colorToggled = false;
                    ((Label)sender).Background = null;
                }
            }
        }


#653 – MouseMove Events

Most controls in WPF inherit a series of mouse input events from the UIElement class.  This includes the PreviewMouseMove (tunneling) and MouseMove (bubbling) events.

The MouseMove events indicate that the user is moving the mouse across the element in question.  As the user moves the mouse, the event fires for the control that the mouse is over.

Because these events propagate, however, the events will also tunnel down to the control that the mouse is over and then bubble back up the logical tree.

For example, if we have a TextBox inside a StackPanel that is inside a Window and we move the mouse around within the TextBox, we’ll see the following events fired:

  • PreviewMouseMove on Window
  • PreviewMouseMove on StackPanel
  • PreviewMouseMove on TextBox
  • MouseMove on TextBox
  • MouseMove on StackPanel
  • Mousemove on Window