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.
Related
Is there a way to draw a line (or any shape) on a canvas, and then move that line?
I didn't see a way to do it, except maybe by constantly clearing and redrawing the entire canvas. Is that the only way?
That is the usual way - the canvas is tied to the update cycle of the view. SkiaSharp provides you with all the power, and does nothing.
If you have a complex drawing that takes a few milliseconds, and maybe could have areas cached, you can use temporary bitmaps. There is nothing stopping you from drawing to multiple bitmaps as things change, and then drawing all those bitmaps onto the screen when something needs updating.
I'm working on a college project (simulation) that needs to draw a lot of lines and objects to a custom UserControl. My current approach is just to redraw everything for every tick / update loop using Invalidate(). But it sure needs a lot of time to draw (which is resulting in very low FPS) especially when I need to draw thousands of lines and rectangles.
So how can I only re-draw a specific (group of) objects that move in every update loop and only re-draw the rest (the rarely updated objects) when needed? Or is there other way to optimize the way I draw in this problem?
My idea would be the following:
Draw your Control onto a Bitmap (or other image format) once, and save that Image. Then display that Bitmap on your Control. (Assuming you use a Control that can do that, i.e an ImageBox, not sure what would be best for that).
Whenever you update your graphic, keep track of what sections of your Control may be outdated, then redraw only these sections (drawing only the objects that touch that section), and copy the other sections from your saved image.
Display (and save) the new Image.
I'm making a simple graphic editor in Windows Forms (C#), and I'm using a PictureBox for my canvas. I want to implement the "undo" functionality. I'm drawing using System.Drawing.Graphics. Here is my situation:
If I use picturebox.CreateGraphics(), then I will see the drawing, but it won't actually be made on the image (if afterwards I called pictureBox.Image.Save(...), the saved image would be blank).
If I use Graphics.FromImage(picturebox.Image), then the drawing will be actually made on the image, but I won't see anything.
How can I have both?
And how do I implement the undo functionality after that? I tried using Save() and Restore() on graphics, but it didn't work, maybe I misunderstood what these methods mean.
You should avoid using CreateGraphics since that is a temporary drawing that can get erased by minimizing the form or having another form overlap the graphic area, etc.
To update the PictureBox, just invalidate it after you have an update to the drawing:
pictureBox1.Invalidate();
The Undo-Redo is a different beast. That requires you to keep a list of things to draw and in order to undo something, you remove the item from the list and redraw the whole thing again from the active list.
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.
What is the best approach to render a large number of 2D graphical elements (lines, text, shapes, etc.) in a scrollable view on windows using C#?
You could put a PictureBox (of whatever overall size required) onto a Panel with AutoScroll set to True, and then draw everything you need at once onto the PictureBox using a Graphics object.
However, if the overall size of the drawing surface is extremely large, this approach would not be practical (since it would mean having a huge PictureBox and a correspondingly huge Bitmap, which could consume a large amount of memory). If this were the case, you'd be better off creating your own scrollable user control (horizontal and vertical) and rendering only the visible portion of the overall surface in the control's Paint event.
The first approach would be easier and faster to write, but might consume too much memory. The second approach would require more work on your part, but would minimize memory consumption.
There is a scrollviewcontainer control but not on the toolbox by default. I would do the above approach to a picture box and embed it inside this control. Also, you can use SetStyle to enable double buffering to prevent flicker. Another option is to build a class to handle double buffering (draw to a bitmap object and push out the results using CreateGraphics). There are some good examples out there.