C# redraw only foreground - c#

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.

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.

SkiaSharp - how to move objects on canvas

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.

WPF Dynamic Cursor

I am creating a vector graphic editor in WPF. I am rendering the artwork using a D3DImage that has been customised using SharpDX so that I use it with Direct2D. When an item is selected, resize handles appear around the selected item. I want the cursor to change when the user hovers over these resize handles, but they are rendered in Direct2D and are not WPF elements. How do I accomplish this?
Well, if you’re doing your own rendering to D3DImage, you gotta do your own hit testing.
If your geometry’s relatively simple (boxes, circles, polylines, not too many of them), you can hit test these handles shapes in mouse move event handler. Either manually, or by using e.g. FillContainsPoint D2D APIs.
Or, if you aren’t doing something very color-sensitive like a desktop publishing, you can encode resize handles in the color of your shapes. Use a couple of least significant bits of the blue channel (human eyes are least sensitive to blue), read the color under the mouse, change cursor accordingly to the blue color value.
Or, you can switch to DXGI_FORMAT_R16G16B16A16_UNORM for your render target (looks like D2D supports that format), this way you can add much more per-pixel data to your image without any visible artifacts (use lower bytes of each of the 3 color channels). This however complicates rendering, you’ll need to do one more pass to convert the texture into A8R8G8B8 for the WPF.
P.S. I wonder why don’t you use WPF elements instead? 2D vector graphics there is rather advanced. You can easily create/manipulate/fill/outline these shapes programmatically (just place then on a canvas), this way WPF will handle all these hit tests, and rendering, and more.

How to draw on a picturebox and save it in Winforms C#?

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.

How to display images on top of each other using C# (Forms or WPF)?

I need to display images on top of each other. This can either be a composite\layered image or separate images. This will typically be a larger image with smaller images on top. With the composite\layered approach the smaller images would each need to be a separate (and accessible) layer. With the separate images approach the smaller images are on top with a transparent background. With either approach the smaller images must be accessible i.e. can be moved (dragged) or deleted. The app needs to display these images together (as if it was one image) and keep track of the coordinates (position) of the smaller images.
The current (proof-of-concept) solution has a PictureBox control that displays the large image and a treeview. Nodes are dragged from the treeview to the picture box and rendered using the graphics DrawString or DrawImage methods – these draw the smaller images. The problem is that once the smaller image is drawn I cannot get back to it as a separate graphics object. The picture box “sees” it as part of the current image.
I need to do this in C# (WinForms or WPF). And the image type must be a common and open format i.e. not proprietary. Preferably no 3rd party controls.
Any suggestions\guidance?
WPF would be the technology of my choice for this project.
Drag & Drop way nicer, without flickering, better concept
Rendering directly on HW, way smoother for image manipulation
General idea of the implementation:
MVVM pattern
ViewModel holding your layer information
ItemsControl bound to the collection of Small overlay Images holding a DataTemplate which visualizes the images thour custom UserControl based on a Thumb (for drag & drop functionality) displayes the small images on top.
Easy to add functionality to drag, edit, hide each small image seperately.
The problem is that once the smaller image is drawn I cannot get back
to it as a separate graphics object. The picture box “sees” it as part
of the current image.
That behaviour is perfectly normal. GDI drawing does not work with objects. To do what you are asking, you need to track any event that can cause a change in the final image and when such an event occur, you need to draw the whole image from the begining, including the first image (assigning the background image, I guess).
May be create picture box per image. The transparent background will give the effect of single image.

Categories