I am currently writing a program where I need to draw some graph's. I need to have a little bit specific layout in these graphs. For example I have three stages of a length in days defined by the user. a start stage of for example 30 days, a mid stage of 40 and an end stage of 20 days. These stages I want to have all a different backgroundcolor in the graph. I do that by drawing pictureboxes and adapting their widths to the stage lengths. Also for every day in the total length I want to draw a vertical line and for the amount of horizontal lines in the graph I take the maximum of y = f(x).
y = f(x) needs to be plotted on the graph. For I use many pictureboxes on the background I cannot use the graphics.DrawLine for it will be drawn behind the pictureboxes. So I decided to make the line with an array of pictureboxes ;) It works fine, but obviously it takes a lot of time to load the program now.
Is there another way to draw this graph using arrays of controls that require less effort from the computer? Or should I completely stop with the arrays?
(I wanted to post my picture here, but I don't have ten reputation yet because I'm a noobie :( )
Later on I will add more lines to this graph, but since I figured that my program is already slowing down I ceased programming those other lines and went to the all-knowing forum!
Any help will be much appreciated!
Greetz,
Arrie
The common form controls aren't really suitable for this purpose. I'd suggest taking a look at using libraries that give you more power and control over visuals and graphics.
#Kári is right:
If you want to stay with .NET only (no 3rd library dependence) you can use GDI. In .NET you can use by including System.Drawing.dll as an reference.
One simple yet correct approach would be:
create a target control (picturebox for example)
implement the OnPaintDraw Event which gives you an Graphics object
that contains many drawing methods. See MSDN for more information:
MSDN -> Graphics
The methods of Graphics will always draw above the control, so make sure your target control is visible an not behind any other control.
If GDI is not enough you can check out other libraries. (See .NET graph library around?)
Related
- Building a CAD program in WPF:
I want to build a CAD program that will have 10000 LINE objects at a time. I'm using LineGeomery class for drawing lines that are added to a Canvas. I have implemented Zoom and Pan and the performance is great so far.
Only one major disappointment:
The Thickness of the lines gets scaled while zooming. I have tried to Bind the Thickness property of the lines to a factor to keep them unchanged, This works but reduces the performance dramatically while zooming. Clearing and drawing new lines with new thickness on MouseWheel is out of the question as well. This one too reduces performance and is not practical in the current method.
- Now what solutions I have?
Stick with the current method and ignore the change in Thickness
Do the whole job in GDI+
Host GDI in WPF
Use WPF Viewport3D (Will the LineThickness be invariant there?)
- Other solutions?
What other paths you would take. I'm new to WPF and programming and I'm eager to learn.
UPDATE:
This is the way I'm doing it right now. I draw 3000 Lines on the Visual Layer using Pen an Brushes. Then on MouseWheel event I redraw all the Lines with the updated Thickness. Also I don't show the rest of the Lines to the user until he zooms so I only create 3000 out of 10000 Lines in each MouseWheel event.
Instead of using Line objects, you could draw your lines by Path objects. Here is an answer https://stackoverflow.com/a/15323221/1305119
Next to hosting a winforms element inside WPF, I would also implement partial rendering on the zooming feature, e.g. when you zoom in everything that is not visible should not be calculated as well!
I am creating a custom control for semiconductor wafermap
Each of those small rectangle need to satisfy following requirements;
1) Tooltip to show the index
2) clickable to include or exclude from the wafermap definition.
no of dies in the wafermap may cross 2 millions in the case of 1400 x 1450 dies.
at certain point i need to show all the dies in a window (most of the clicking will happen in zoomed view).
Currently I am adding each die separately using Rectangle shape and store the coordinate information (index like (10,10)) for the tooltip as an attached property.
I use different style to each die; depending on certain calculation and position of the die.
DieStyle1 = new Style { TargetType = typeof(Rectangle) };
DieStyle1.Setters.Add(new Setter(Shape.FillProperty, Brushes.MediumSlateBlue));
DieStyle1.Setters.Add(new Setter(Shape.StrokeProperty, Brushes.White));
DieStyle1.Setters.Add(new EventSetter(MouseDownEvent, new MouseButtonEventHandler(DieStyle1_MouseDown)));
this approach is slow and use high memory too. so suggest a better way to achieve this in WPF?
In creating a designer for christmas tree lights, I ran into the same problem. Using UIElement or Shapes is way too slow when you get to 100+ items. The best approach to handle a very large number of items entails using double-buffering with your own managed buffer of the image and a structure to handle the clicks. I have posted my project which should give you a good start. It can be obtained at:
http://sourceforge.net/projects/xlightsdesigner/
You are interested in the Controls\ChannelitemsCanvas.cs. It can be modified to suit your needs and uses a quad-tree to store the rectangles so that click events can be quickly determined.
I am doing some work for which I need to develop a control, it should be a simple graph that shows several points and two edges.
My problem is that I need to show up to 16k points, with an update rate of 30 Hz. Has anyone done something similar?, and has any advice?.
For example whether to inherit from FrameworkElement or Control (ItemsControl in this case). If the control inherits from FrameworkElememt it may have a better performance drawing the points in the OnRender method but I would miss the Templating feature that comes from inheriting from Control.
Or does there exist another control that can do this out there?
Thanks in advance for your time.
I ended up using InteropBitmap, it is the fatest bitmap rendering class from WPF.
It allows you to map the image that you want to paint (in memory) and then reder it as a Image. This was perfect as i needed to plot points on the screen.
I got great performance (almost 50Hz for 20k points), i also use PLINQ to update the points in memory.
check this article for more details...
Try and read about ZoomableCanvas. I believe it can solve your problem. You can render all the points as small rectangles/ellipses inside the ZoomableCanvas.
I'm drawing a lot of lines on a long canvas (think stripchart) and have it tuned fairly well for performance, using the low-level geometry classes and freezing them, etc. This improved performance dramatically, but it still takes a few seconds to load a few thousand items into the canvas. I ran a performance analysis on the application, and it looks like a big percentage of the time is taken by each call to canvas.children.add(). I've read that this should be a lightweight call, and since I'm calling it numerous times in one method, it shouldn't be trying to do anything heavy inbetween... Could there possibly be any other reason this might be taking so much time? And any way I might speed it up?
The performance is not terrible, but I fear it could become more of a problem later when I need to deal with larger sets of data.
Just for reference, it looks like it is called 1400 times in this sample, and it taking almost 3 seconds of CPU time on a modern/fast laptop.
The canvas is contained in a hierachy of other controls though, so I'm curious if they might be contributing to this.
Extra note: I'm also not setting a specific height on the canvas, as it is set to fill the grid parent container. Could this be a source of the problems?
Main problem is that Children.Add is always a slow operation, even if you use StreamGeometry objects. I faced the same problem recently and concluded the following:
If you put a bunch of objects into a new canvas and nest it into the main canvas, the performance of the addition operation will be increased dramatically.
So, instead of adding 1400 elements, put 200 elements in 7 canvases and add those 7 canvases to the main canvas.
Since all objects now belong to different canvases, you will need to adjust your app a bit, but this would be a less drastical solution than moving to an alternative solution like DrawingVisual
Just to add about the hierarchy of controls the canvas is within, and the height of the canvas:
the Canvas always takes as much space as its given, and no matter what children u add to it - it NEVER triggers a new Measuer/Arrange passes on its parents. therefor whatever u do inside a canvas could never affect the visual tree it is contained in.
To sum it up - the problem cannot come from there, and the suggestion about the StreamGeomatry is exactly right- this is what causing u the performance issues, and switching to streamgeormatry would solve it.
I would suggest that you draw your shapes directly into an image instead of adding them as children.
Rendering children has a HUGE overhead (as you can see).
There's a similar question with a reference to some helpful articles:
How to draw line of ten thousands of points with WPF within 0.5 second?
I would like to develop a simple point&click game in C# with the default drawing libraries...no openGL/SDL/Tao for this project.
Suffice to say, I am curious as to the best ways to draw clickable images in layers on a form.
Ideally, I would have
1) Environment layer (pathways, doors, etc)
2) Object layer (items)
3) Character layer (enemies)
Ideally, the layers beneath other layers would still be viewable, so I could still see the environment underneath an object (so whatever component I use to draw the object to the form needs to be transparent).
This game is going to be tile based...so I will be generating a 2D array of some sort of component and putting those onto the form. The question is, what component should I use? A friend has recommended to generate panels and drop those onto the form and use the background image property, but is there a better way?
I know that this is not the ideal way to develop...this is more of a prototype for myself. Later on I will probably move it to Tao if I get anywhere, but for now (ie, the next year or so), I would like to keep it extremely simple.
Tiles are simply logical chunks with which to organize your UI. You do not need to necessarily have tiles in the form of Panels to use the "tile" idea. Switching tiles can simply mean that your character has reached the right edge of tile A and you will therefore draw tile B and place the character on the left edge of that tile. So your memory structure should be a 2D array of logical tile objects that contain information about what to draw but not necessarily Panels, though that is an option, i don't recommend it.
Layers: You don't really need to worry about layers. All you have to do is draw in the correct sequence: Environment first, followed by objects and then characters. .Net and probably all frameworks paint back to front, which means that things drawn first may be entirely or partially obscured by objects drawn later. The "layering" happens automatically. If you just draw your objects within their own bounds then you do not need to worry about transparency. E.g. a 20x20 pixel character is drawn within a 20x20 pixel bound.
This is all assuming raw e.Graphics.Draw* and e.Graphics.Fill* calls in the Paint event handler of course. As with anything in software, there are 101 ways...