I am working on an interactive WPF graph/tree tool and have nodes and links between them placed in a canvas. The nodes are usercontrols and the links are simply Line shapes, and currently the links go from the centre of a node to another node's centre.
The problem arise when I want the nodes to be slightly transparent and one sees the links behind the nodes.
I figured the most convenient solution would be to apply clipping or opacitymask to the lines, so they are not drawn behind the nodes, but I can't for the life of me figure out how?
Basically I can't figure out a bounding box geometry from the nodes to use as a clipping geometry for the lines. I am also interested in alternative solutions, of course!
It would seem to me like you're overthinking the solution. Why not just change the logic for the links so that the lines begin/end at the correct side of the node instead of starting from the center??? You should only need to do a little more math to accomplish this.
That said, to get the bounding box of a Visual you can use the VisualTreeHelper::GetContentBounnds helper method.
The VisualTreeHelper.GetContentBounds() method seems to return Empty everytime.
An alternative solution to this problem is answered at
Connecting two WPF canvas elements by a line, without using anchors?
that uses bounding boxes to find intersection points to draw the lines from/to.
We worked on something similar and our solution was to put links and nodes on different layers.
So if you want the nodes to appear above the links and the tips of the links to be hidden by the nodes, you just change the z-order of the layers so that the nodes layer is in front of the links-layer.
As layers we used VisualHosts (you find a VisualHost class here) an our node and link objects were DrawingVisuals.
Works fine and you don't need to hassle about finding the borders of your nodes etc.
Related
So there's this tutorial about creating a diagram in WPF.
http://www.codeproject.com/Articles/24681/WPF-Diagram-Designer-Part
I've read it, and still studying it to understand it completely.
At the end of this tutorial, you can basically add shapes, move/rotate/scale them, and since they are created in a vector form, they are keeping their resolutions, there are also connectors that can connect each shape with another.
My goal, since I need to create a simulator which shows how internet protocols are delivered, is to create a divided diagram in which Side A communicates with Side B. it could read an automata and simulate the transitions in the diagram.
I'm thinking of how to deliever this, and since I don't have a lot of knowledge in WPF, I wonder in which way should I implement it.
Should I create 2 different Canvases? or maybe dividing 1 canvas with two sides?
The main issue I'm dealing with, is that when a shape is being dragged to the end margin of the window, then the window allow me to slide it so I can see the rest of the field, this is being done by increasing the size of the Canvas, as seen in the Tutorial Part 1.
However, if my canvas is divided by two, and there's a border in the middle, how can I create two sliders for each of the sides?
I was wondering if you can give me any tips about how approaching this idea, since my knowledge in WPF is still very limited.
Here is my point of view, but it would be very useful if you would provide a more/less final sketch of your app. I recommend using Telerik AppMock but paint will also suffice ;).
From what I have understood you should need 3 canvases.
1-st is canvas on the left.
2-nd is canvas on the right.
3-rd is on top of both canvases.
When you want to drag an element, you must set opacity of the clicked element to be a bit transparent and leave it on its place(1st canvas), add copy of dragged element in to the 3rd canvas. When you do leftmousebuttonup(drop dragged item), you have to check where was it dropped and if it was droppend on the 2nd canvas you add it to this canvas. To position element on the canvas you can use Canvas.SetLeft and accordingly SetRight method.
You can put 1st and 2nd canvases into Grid. Even if Canvases will be bigger if Grid, view will be cut only to the size of the Grid.
Moreover, to allow canvases manipulation, add there (to the Grid) a scrollviewer which will Translate Transform the canvases given to their sizes.
Later, try to use MVVM pattern to fill your Canvases with data.
I would also suggest an ObservableColletion of drawable (you can use FrameworkElement as base class) and draggable objects. Different for every Canvas.
Good luck!
I need to display many markers on a WPF image. The markers can be lines, circles, squares, etc. and there can be several hundreds of them.
Both the image source and the markers data are updated every few seconds. The markers are associated with specific pixels on the image and their size should be absolute in relation to the screen (i.e. when I move the image the markers should move along with it, but if i zoom in, they should take the same space of the screen as before).
Currently, I've implemented this using the AdornerLayer. This solution has several problems but the most significant one is that the UI doesn't fare well under the load even for 120 such markers.
I wanted to ask what would be the best way to go about implementing this? I thought of two solutions:
Inherit from Canvas and make sure it is invalidated not for every
added marker but for a range of markers at once
Create a control that holds an image and change its OnDraw to draw all the markers
I would appreciate some pointers from someone with experience with a similar problem.
Your use case looks quite specialized, so a specialized solution seems in order. I'd try a variant of your second option — extend Image, overriding its OnRender method.
I'm trying to make an application which allows the user to draw shapes to the canvas. Once drawn, I would like for the user to be able to select, move, resize, basically manipulate the shapes in any which way.
I have done something similar in XNA and that was quite easy due to the fact that there was a draw loop. In Silverlight there is no such thing as far as I understand and I am having trouble figuring out how to manage the objects on the canvas. As in what is the best way to manage the canvas' children collection to ensure appropriate response of the UI to what the user does.
Most examples out there are pretty basic and do not go anywhere near this kind of thing. I would be grateful if somebody who has done this before could tell me how they approached the problem.
Thinking about it for a while I think I figured out how it works.
There is a draw loop for the canvas, which is the draw loop of the top level parent container which it lives on.
The difference with XNA I guess is that the collection of items to draw on the canvas doesn't need to be explicitly drawn, since the canvas takes care of drawing its children automatically.
So, what I need is some way to hold on to any object I add to the canvas' children... I can then update the objects drawing properties and the changes will be reflected in the canvas next time it refreshes.
I guess a dictionary of some sort in which to store the items I put in the list might be best...?
Not a finished answer yet, but I guess I understand half of it now.
I'm currently creating a MSPaint-like WPF-application and struggling with the implementation of a snappable grid.
The painting of the grid is no problem with a VisualBrush and a Rectangle but the problem is that these lines are then purely for looks and can't be easily changed (for example highlighted when the snapping to a specific line triggered).
My other idea was to have a 2 Canvas solution where 1 Canvas is used for the elements and one Canvas (who is positioned above the other) contains all the grid lines. However I have the feeling that this would mean quite a performance hit.
Are there any other possible ways to implement this kind of functionality?
Efficiency considerations of a two-panel approach vs DrawingContext
I have good news for you: You are wrong about the significant performance hit. Your two-canvas idea is nearly optimal, even if you use individual objects for the grid lines. This is because WPF uses retained-mode rendering: When you create the canvas, everything on it is serialized into a compact structure at native level. This only changes when you change the grid lines in some way, such as changing the grid spacing. At all other times the performance will be indistinguishable from the very fastest possible managed-code methods.
A slight performance increase could be had by using DrawingContext as Nicholas describes.
A simpler and more efficient solution
Perhaps a better way then drawing individual lines on the grid canvas is to use two tiled visual brushes (one horizontal, one vertical) to draw all unhilighted lines, then use Rectangle(s) added in code-behind to hilight the line(s) you are snapping to.
The main advantage of this technique is that your grid can be effectively infinite, so there is no need to calculate the right number of grid lines to draw and then update this every time the window resizes or the zoom changes. You also only have three UIElements involved, plus one more for each grid line that is currently hilighted. It also seems cleaner to me than tracking collections of grid lines.
The reason you want to use two visual brushes is that drawing is more efficient: The brush drawing the vertical lines is stretched to a huge distance (eg double.MaxValue/2) in the vertical direction so the GPU gets only one drawing call per vertical line, the same for the horizontal. Doing a two-way tiling is much less efficient.
Adorner layer
Since you asked about alternatives, another possibility is to use Adorner and AdornerLayer with any of the solutions above rather than stacking your canvas using eg a Grid or containing Canvas. For a Paint-like application this is nice because the adorner layer can be above your graphic layer(s) yet the adorners can still attach to individual items that are being displayed.
You might consider drawing your grid using the DrawingContext inside of OnRender. Drawing this way does not introduce new UIElements into the visual tree, which helps to keep performance up. In some ways, it is similar to what you are currently doing with the VisualBrush, which also does not create new UI elements per copy.
However, since you will actually be individually drawing each line instead of copying the look of a single line, you'll be able to highlight the grid line(s) that participate in snapping without changing the colors of those that do not.
If you are going to go down this route, make sure to have a look into GuidelineSets for positioning your guide lines (more details here), since you'll probably want to have your guide lines snap to the device's pixels so that they draw sharply.
I'm making a control that involves dragging pieces of a displayed element around. Since part of it is an arc, I have to use a PathFigure so I can use ArcSegments. I'd like to be able to know if the mouse is over a particular segment of the figure, but I don't see an obvious way to do this. Is it impossible or am I missing something?
the root Path object has the normal UI events for Mouse, instead of one Path with lots of Arcs you will need lots of Paths with an arc in each.