Search code examples
wpfxaml

PreviewMouseMove event doesn't work when you have clicked on anothor button


 <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Button Grid.Column="0" Background="Red"></Button>
        <Grid Grid.Column="1" Name="BlueGrid" Background="Blue" PreviewMouseMove="Grid_PreviewMouseMove"></Grid>
    </Grid>
 private void Grid_PreviewMouseMove(object sender, MouseEventArgs e)
 {
      var pos = Mouse.GetPosition(BlueGrid);
 }

So there are to grid in this window. I want to get the mouse position every single time your mouse is on the blue grid. It's working fine but it only has one problem. When you click on the button(Red button) and you hold it and you enter the grid the event doesn't work any more.

I tried other events like MouseMove,MouseEnter and DragEnter but none of them works. Is there anything I can do to get the mouse position of the grid no matter what?


Solution

  • The explanation is that when you click on a ButtonBase the control clinches the mouse capture. This means all mouse input events are all using the ButtonBase as source even when the mouse input events are triggered outside the element's bounds.

    The solution is to listen for the routed mouse input events on a common parent container and control the mouse capture using CaptureMode.SubTree.
    You can identify the event source of interest by accessing the RoutedEventArgs.Source property:

    <Grid PreviewMouseMove="Grid_PreviewMouseMove">
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
    
      <Button Grid.Column="0"
              Background="Red" />
      <Grid x:Name="BlueGrid" 
            Grid.Column="1"
            Background="Blue" />
    </Grid>
    
    private void Grid_PreviewMouseMove(object sender, MouseEventArgs e)
    {
      // Capture mouse for the complete sub tree instead for a single element.
      // In this case this includes the Button and the Grid.
      // Because messing with the mouse capture could potentially break 
      // the ButtonBase.Click event and ButtonBase.Command handling 
      // you may have to fallback to use the UIElement.PreviewMouseLeftButtonUp event 
      // to execute the Button.
      _ = Mouse.Capture(this, CaptureMode.SubTree);
    
      // Filter the event source to handle BlueGrid mouse move events
      if (e.Source is Grid grid 
        && grid.Name.Equals("BlueGrid", StringComparison.OrdinalIgnoreCase))
      {
        // TODO::Handle mouse move over BlueGrid
      }
    
      // Relasae mouse capture
      _ = Mouse.Capture(null);
    }