views:

657

answers:

2

I'm trying to modify the default graph viewer of the Graph# library because its user interface is awful (just try dragging a node outside of the boundaries, you'll see!)

The basic setup is this: there is a GraphCanvas control (inherited from Panel) which has children of Vertex and Edge control types. What I want to achieve is:

  • GraphCanvas has scroll bars if the contents do not fit in the screen;
  • 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 around. If a vertex is dragged outside the current boundaries of GraphCanvas, the boundaries are increased. The scroll bars should reflect this, however the current viewport should not scroll away while the vertex is being dragged . The same goes if dragging a vertex reduces the boundaries of GraphCanvas - it should stay the same size until the drag operation is finished and resize only then. Automatically scrolling the viewport during a drag operation is awfully confusing and easily introduces dragging errors. See the original implementation if you want to know what I mean.

Although I've got a fair bit of experience with .NET, I'm still a complete beginner in WPF. My current attempt is (in the measure/arrange layout phase) to give each vertext the XY coordinate it desires (even if negative) and implement zooming/scrolling by handling mouse events on the GraphCanvas and modifying the RenderTransform property. Dragging just changes the XY coordinates on the specific vertex (probably triggering the re-layout of the whole thing which would be nice to avoid too). Scrollbars are implemented by placing the GraphCanvas inside a ScrollViewer and implementing IScrollInfo on the GraphCanvas.

Unfortunately there seems to be a problem: I can get mouse events on the GraphCanvas itself only if it has a background at the point. That would be OK, I want a white background anyway, but in the negative coordinates of the GraphCanvas it does not draw the background - and thus does not respond to mouse events.

I'm also wondering if I'm doing the Right Thing by allowing all my child controls (vertices and edges) to go into negative coordinates. How would you implement this?


Added: To clarify about the background problem check out the following screenshot:

What you see here is a simple Windows Forms form with a WPF Host control on it. That has a ScrollViewer in it, and the ScrollViewer has the GraphCanvas in it. The GraphCanvas contains 4 vertices and 6 edges.

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

Note the gray area on the left. That's still a part of the GraphCanvas, but the background brush somehow doesn't exted there. Also, if I left-click there with my mouse (not on a node, but on the gray area), I do NOT get an event. If I left-click on the white area, I get all events just fine.

A: 

Call CaptureMouse on canvas.mouseDown and ReleaseMouseCapture on mouse up. Also, if you set your canvas background to transparent it will still be hit testable

Rob Fonseca-Ensor
If you read my question carefully you'll see why this does not always work (hint: second paragraph from the end).
Vilx-
what mouse gesture are you trying to perform outside the bounds of your canvas?
Rob Fonseca-Ensor
maybe you can provide a screenshot? I did read your paragraph, carefully - it's still not clear
Rob Fonseca-Ensor
I edited the post to clarify.
Vilx-
Blargh, the WPF thingy is having more and more issues! Now it clips edges (but weirdly enough not vertices) that are outside the main area. If I scroll down, the edges are cut mid-way. And I can't find how to override this.
Vilx-
Given the complexity of your question, i don't think i could help without full repro source code :(
Rob Fonseca-Ensor
A: 

you can attach a 'Draggable' behavior to each element...

Reflog