Do I need to worry about optimal drawing on canvas? - c#

I've to draw a graph on a canvas (bound by a scrollviewer). And there are about 200 or so nodes in memory.
To keep the things simple, I have derived the nodes from a usercontrol which can render itself.
But I've not created the lines between the nodes. I know from MSDN that,
On the surface, the Geometry class and the Shape class are quite similar. Both are used in the rendering of 2D graphics and both have similar concrete classes which derive from them, for example, EllipseGeometry and Ellipse. However, there are important differences between these two sets of classes. For one, the Geometry class lacks some of the functionality of the Shape class, such as the ability to draw itself.
Because there can be lot many more nodes, the system may render things slowly. Hence, to increase performance, I feel the best choice would be Geometry (custom rendering).
My questions:
Should I go with Shape or Geometry to draw the lines?
Should I render only the current viewport area of the scrollviewer to speed up the display (in which case I would have to convert the nodes from controls to geometry objects), or should I just iterate over ALL the nodes and draw lines between them?
Should I render the graph in memory on a bitmap and then flip it? It sounds more like game programming that general application programming! :D
Doesn't WPF automatically takes care of rendering what's in view and what not for better performance?

A few points to ponder...
From your topic I get that you dont want the ability of nodes to redraw themselves as that may make them slower. Instead, you want to decide when and which node to draw. Am I correct?
Well that looks ok to me, however Canvas is never virtualized. I recommend going through the codeplex website and download the WPFToolkit source code. Under DataVisualization namespace you have several charting controls (even ScatterredChart which is similar to yours where lines are not drawn between nodes) and their source code. Observe what they have done. How have they increased performance of their graph tools.
I also came across this artical of how to implement a Scrollable Virtualized Canvas. Probably that can help you to achieve fast rendering of nodes over canvas.
Personally...
1] Geometries are lightweight and I like them.
2] Visual HitTesting can help you understand if an item is under rendered region i.e. within the bounds of the scroll view. Otherwise make it hidden so that it doesn draw itself. "Hidden" and not "Collapsed" because hueristic for scrolling would work fine.
3] I remember my colleague using even the virtualizing stackpanel with horizontal orientation so that it renders nodes and the unit view i.e. the region specific to one point on X axis so that such repeating regions would automatially fit together to produce a monolithic graph.
Wonderful that impelemntation was!
All the best and keep us posted of your progress on this.

Related

WPF FrameworkElement manipulation after OnRender

I create a custom control and draw some objects in OnRender.
Now the question is: Assume I draw 5 rectangles in OnRender. Is there a way to delete eg the 1. rectangle without to retrigger OnRender and redraw rectangles 2-5?
Or in general, is there another way, where you can update or add/remove rendering instructions, instead of rebuilding the drawing in OnRender every time something changes?
# dsdel: Ok, the idea is, that the calculations in OnRender might be very heavy. You can render Text, Geometric shapes. And I ask myself, why shall I create all the Geometry and FormatedText again, if the only thing I want, is to change the position of a line. The Rectangles above just were an example. It is more a general question. Is it really necessary to recalculate all elements in a new call to OnRender instead of just updating what has changed. I mean OnRender does not render anything, it just prepares some object structures that get transfered to DirectX for rendering. So I just want to manipulate the existing object structures instead of creating new once every time a little thing changes.

How to initially place WPF controls on dynamic fullscreen application

Alright, so I'm trying to figure out the best way to accomplish this for my rather unique case. I have a fullscreen WPF application where controls are added to a Grid dynamically and the user is given the option to freely move/resize them. The controls can be individually moved or resized anywhere on the parent Grid but I have prevented them from overlapping via their MouseMove events. They also cannot be moved outside of their container. Since the app will be running on machines with different monitor sizes, I need to take that into consideration when making the original layout. I have an initial layout that I would like to use, but it would seem that I'm out of options:
I first tried using rows and columns just to (initially) place the controls that are added. This method places them correctly but becomes a problem when I need to move or resize the elements because the control is already assigned to a particular row and column. I could try to use this method and then remove any rows/columns after placing the controls, but I don't think that would work well.
I've also considered a Viewbox, but that's not practical in my case for fairly obvious reasons (as it merely resizes the controls to fit the screen). I'd prefer not to use this because I would only need it to standardize my initial layout. That's it. I also don't want to mess up any text that will be displayed on the window.
So yeah, this is more of a "best practice" question because any solution I can think of would not look very professional or elegant. Feel free to ask any questions if you need clarification.
Edit: As an additional note, I'd prefer to stick with a Grid as opposed to a Canvas as my container.
Edit 2: Just to be clear, I would not need the specific (inital) layout after the first launch. When the program exits, the layout (Margins, Width & Heights, etc. for each element) is saved to a file to use for the next launch.
I've developed a number of kiosk/interactive applications using WPF. If you are trying to show the element transitions (while moving), then it might be best to use a parent Canvas and bind the Canvas.Left and Canvas.Top properties. You can mimic the grid alignment, using a Canvas, if you put in place mechanisms (e.g. Manipulation/Mouse events, converters) to make sure that the Canvas attached properties adjust to the row/column offsets.
It is not uncommon at all to use the Viewbox to mitigate display differences (and your use case is not "rather unique"). You set the Viewbox to a target resolution (e.g. 1920x1080) and allow the control to fill the available space. The other alternative would be to dynamically apply a content template based on the application window size/ratio.
After looking at multiple options, I've decided to just use a calculation to (sort of) simulate the behavior of rows/columns. Because my application is fullscreen, I can take my SystemParameters.PrimaryScreenWidth and SystemParameters.PrimaryScreenHeight to orient my layout. Using a combination of universal padding (static values) and ratio-based calculations (dynamic values), I can smoothly set my initial layout.
For instance, I'm dividing the width of my monitor by 6 (rounded up to avoid decimals) and using that (minus half the control's width) as the control's Margin.Left property, centering it on a 'column' of sorts.
Honestly, my initial layout is fairly simple right now, so we'll see if this will suffice going forward. Thanks to everyone who contributed to the question, and sorry if I was unclear on what I was asking.

LinesVisual3D not visible behind opaque objects

I have a problem that all of my LinesVisual3D are not visible, when placed after an object with semi-transparent material (lowered alpha channel). All other 3D objects are visible when placed behind, but the lines are not. What is more, when the lines partially intersect with the object, only the part that is not intersecting is visible.
Is it possible to make these lines visible?
I believe this might be an effect of how WPF 3D handles opacity. I've had similar issues with other Visual3Ds.
Have a look at Transparency in WPF 3D.
Basically you have to add opaque and transparent objects in the correct order. Try adding the opaque objects last. I.e. add the LinesVisual3D you're having issues with, then add the things with lower opacity.
Disclamer: I have not tried your scenario with specifically LinesVisual3D, so it might be that there is a bug in Helix regarding that specific visual.

Ideas on how to zoom on a Chart control in WPF

summarizing I have implemented a chart control as a simple Canvas with a Polyline on it. The next thing I need is to be able to zoom the chart.
I would like to know how would you that (just the idea, no details needed). What I would like to do is to create somehow a bigger Canvas and paint the line bigger and just show a part of the Canvas to the user, and the he drags the Chart it will move the Canvas. Something like in the following picture. Do you think this is possible?
Kael Rowan from Microsoft Research built a ZoomableCanvas class that may do exactly what you want. You can also see all the posts he wrote about it. You can even try a running XBAP example if your browser supports it.
We use the RenderTransform for this, create your zoom and pan matrix( or transform ) and apply that to your canvas. The nice thing is, that you can still have elements that can display behind or on top of the canvas with the identity transform or with another. For example for a grid or screen space elements like a minimap, which should always be visible. You might also want to look into this old question, which is somehow related.

WPF snapping controls

my current free-time project, in order to dive into WPF MVVM, is a "digital" copy of an old puzzle I used to play a lot in my childhood. It basically is a simple puzzle where one has to fill a given space with different kind of pieces so the whole space is filled. But with the extra twist of being in hexagonal space.
Just to illustrate, this is what it currently looks like in WPF:
http://img190.imageshack.us/img190/2553/atomgridmolecule.png
So basically there is a number of predefined pieces(like the orange one above) which can be "plugged" into the given grid(the gray stuff above).
So the result might look something like this:
http://img30.imageshack.us/img30/2553/atomgridmolecule.png
I want the user(probably only me^^) to be able to drag and drop the pieces into the grid. I want the dragging to look natural meaning having the correct offset while dragging depending on where the user clicked the piece.
Both grid and molecule are the same control, a custom hexagonal panel control derived from the WPF Panel class.
The problem is on how to do the "plugging in" and especially the "unplugging".
I have two ideas on how I might tackle this:
Just color the cells in the grid and hiding the original piece
Pro:
Zero cost perfect alignment of the cells
Cons:
Recreating the piece at the right spot with the correct mouse offset if dragging out, seems impossibly? hard to do
Snapping the piece to the grid and show it on top
Pro:
Dragging out is a simple dragging operation, just as dragging in
Disadvantage:
Somehow have to align the piece with the underlying grid, some kind of snapping
So which approach should I take? Even more important how can I even implement this in WPF? Especially using a clean MVVM way.
Thanks so much for your help! Any input is highly appreciated!
EDIT:
Thanks Aran, I thought so too.
But how do I actually implement this now?
How can I actually get the coordinates?
All the orange circles are linked, so how can I "move" or better "plug" them in as one piece?
Im inclined to go with the second idea. a simple snapping would just be to test if the centre point of the circle you are dragging is within some tolerance factor of a circle on the grid and if so snap them.

Categories