WPF creates a list of controls that can be scrolled with the mouse, but still remain functional

I have a list of controls that I show through the WrapPanel, and it is horizontally oriented.

I applied the Click and Drag scrolling method to make the user scroll with the mouse by clicking and dragging.

Same:

<Canvas x:Name="ParentCanvas" PreviewMouseDown="Canvas_MouseDown" MouseMove="Canvas_MouseMove"> <WrapPanel> <WrapPanel.RenderTransform> <TranslateTransform /> </WrapPanel.RenderTransform> <!-- controls are all in here ... --> </WrapPanel> </Canvas> 

Then in the code behind:

  private Point _mousePosition; private Point _lastMousePosition; private void Canvas_MouseDown(object sender, MouseButtonEventArgs e) { _lastMousePosition = e.GetPosition(ParentCanvas); e.Handled = true; } private void Canvas_MouseMove(object sender, MouseEventArgs e) { _mousePosition = e.GetPosition(ParentCanvas); var delta = _mousePosition - _lastMousePosition; if(e.LeftButton == MouseButtonState.Pressed && delta.X != 0) { var transform = ((TranslateTransform)_wrapPanel.RenderTransform).Clone(); transform.X += delta.X; _wrapPanel.RenderTransform = transform; _lastMousePosition = _mousePosition; } } 

It all works great.

But I want to make it so that when users click on the drag and drop, the elements in the WrapPanel dont respond (i.e. the user only views), but when the user clicks (as in a full click), then they respond to the click.

As the iphone works, when you click and drag directly into the application, it does not open the application, but scrolls the screen, but when you click the application, it starts ...

Hope this makes sense.

Cheers, Mark

+4
source share
2 answers

I believe that you will need to grab the mouse. The problem is that you will be struggling with controls (such as Button) that will also try to capture the mouse.

In your MouseDown event (perhaps in fact PreviewMouseDown) you can use e.MouseDevice.Capture (_wrapPanel, CaptureMode.Element). This should direct all mouse input to _wrapPanel, and not to any subtree elements.

In your MouseUp event, you need to free the capture by calling e.Mousedevice.Capture (null). If the scrolling did not take place, you want to send a "click" to the control, which would usually receive a click, which I'm not quite sure about. Perhaps you can use Peer automation classes to do this?

The trick is that some controls will not work properly if you remove mouse events from them. Consider a slider, for example. How would a slider ever be used inside a panel that works like this?

+3
source

Another, and, in my opinion, better solution:

  • Add a PreviewMouseDown handler to which you set Handled = true and write down the parameters, including the position, and set the maybeClick flag (if the recursion flag is not set) and sets the timer.

  • Add a MouseMove handler that clears the maybeClick flag if the mouse moves more than epsilon away from the position recorded for PreviewMouseDown .

  • Add a PreviewMouseUp handler that checks the maybeClick flag - if true, it sets the recursion flag, makes InputManager.ProcessInput to re-raise the original PreviewMouseDown , and then clears the recursion flag.

  • In the timer, do the same as for PreviewMouseUp so that the click is delayed only for a moment.

The net effect is to delay the PreviewMouseDown event until you have time to check whether the mouse is moved or not.

Some points regarding this solution:

  • Setting Handled=true to PreviewMouseDownEvent also stops MouseDownEvent .
  • A recursive call is ignored in the PreviewMouseDown handler because the recursion flag is set
0
source

Source: https://habr.com/ru/post/1303756/


All Articles