What is the best way to implement a panel with draggable / scalable children?

I'm trying to change the default graph viewer for the Graph # library because its user interface is terrible (just try dragging the node outside the bounds, you'll see!)

The basic setup is as follows: there is a GraphCanvas control (inherited from Panel), which has descendants of the Vertex and Edge control types. What I want to achieve:

  • GraphCanvas has scroll bars if the content does not fit on the screen;
  • The GraphCanvas can also be scrolled by "dragging" it (just click on an empty space and drag);
  • GraphCanvas can be zoomed in and out (via CTRL + mouse wheel);
  • Vertices can be dragged. If the vertex is dragged outside the current bounds of the GraphCanvas, the bounds are enlarged. The scrollbars should reflect this, however the current viewport should not scroll while dragging the vertex. The same happens if dragging the vertex reduces the bounds of the GraphCanvas - it must stay at the same size until the drag operation is complete, and only resize it then. The automatic scrolling of the viewport during a drag-and-drop operation is terribly confusing and easily introduces drag-and-drop errors. Check out the original implementation if you want to know what I mean.

Although I have quite a bit of experience with .NET, I am still a beginner at WPF. My current attempt (in the measure / arrange phase) to give each text the desired XY coordinate (even if it is negative) and to implement zoom / scrolling by handling mouse events in the GraphCanvas and changing the RenderTransform property. Dragging simply changes the XY coordinates at a particular vertex (possibly causing the entire object to change structure, which would also be nice to avoid). Scrollbars are implemented by placing a GraphCanvas inside a ScrollViewer and implementing IScrollInfo in a GraphCanvas.

Unfortunately, there seems to be a problem: I can only receive mouse events on the GraphCanvas itself if it has a background at that point. That would be nice, I still want a white background, but in negative coordinates of the GraphCanvas, it doesn't paint the background - and therefore doesn't respond to mouse events.

I am also wondering if I am doing the right thing by allowing all of my child controls (vertices and edges) to go to negative coordinates. How would you implement this?


Added: To clarify the background issue, see the following screenshot:
(source: valts.21.lv )

Here you see a simple Windows Form with a WPF Host control. It has a ScrollViewer and the ScrollViewer has a GraphCanvas. The GraphCanvas contains 4 vertices and 6 edges.

The GraphCanvas stretches to fill the ScrollViewer. But since some of the vertices are at negative coordinates, a RenderTransform is applied to it, which simply shifts everything to the right (TranslateTransform). It also has a white background brush.

Note the gray area on the left. This is still part of the GraphCanvas, but the background brush somehow doesn't exist there. Also, if I left-click there (not on the node, but in the gray area), I will NOT receive the event. If I left click on the white area, I get all events just fine.

+2


source to share


2 answers


Call CaptureMouse on canvas.mouseDown and ReleaseMouseCapture on mouse. Also, if you set the canvas background to transparent

, it will still be available for testing.



0


source


You can attach a Draggable behavior to each element.



0


source







All Articles