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.
Related
my task is to draw a flexible number of digital signal realtime-data in SciChart.
Due to the nature of this signals they are between 0..1. I want to have them stacked as in the SciChart example found at https://www.scichart.com/example/wpf-chart-example-vertically-stacked-yaxis/.
But with a dynamic grid template inside the YAxesPanelTemplate. What ever I try, there are no YAxes drawn.
I'm using a GridExtension which is very close to the one found here:
https://rachel53461.wordpress.com/2011/09/17/wpf-grids-rowcolumn-count-properties/
refernced from this answer
https://rachel53461.wordpress.com/2011/09/17/wpf-grids-rowcolumn-count-properties/
Any help is highly appreciated
Cheers
Martin
my solution might not be ideal, but it is almost working for me.
Since I’m developing the code for a customer, I’m not allowed to post code by NDA, but I can give my theoretical approach.
specify the number of YAxes in VM
use this to build the grid inside ItemPanelTemplate and bind with DynamicResource (see example in link below)
to do so, use class from this blog and adopt as needed. I build
a specialized class for my use-case
bind to the SizeChangedEvent of RenderSurface Iterate the axes from
YAxes,calculate height per axis and set it.
inside the same loop don’t forget to set the row by using
Grid.SetRow(axis, rowIndex)
This approach is from my point of view not the most performing, but the only I was able to discover from the SciChart docs.
The last task which I’m facing, is to get the height of the chart portion of the RenderSurface, as the height given in SizeChanged is of the full height including YAxis and other stuff drawn.
Maybe someone from SciChart (#Dr. ABT - just maybe) can help out on this last task?
Hope this helps someone else too.
Cheers
Martin
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?)
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'm working on a c# wpf app in which I want to do something with audio. the irrklang audio library provides me with a pcm decoded 16 bit byte array.
I want to create a timeline control which shows the waveform along the timeline with an overlaying rectangle which the user can drag and click/drag the left and right side to increase or decrease the selection.
It is used to the trim the audio track. I would like the selected min and max to be databindable, the minimum and maximum value of the total track to be bindable.
To clarify here is an image mockup:
I'm not asking for a complete control but tips and suggestions on how to tackle this are more than welcome. Perhaps solutions like this already exist but so far I haven't been able to find it.
I think I need to tackle: the control (zooming, panning and changing the selection) and drawing the waveform in the control
Thanks in advance,
I think you should check out this codeplex project
http://wpfsvl.codeplex.com/
Refer to Audio WaveForm Drawing Using WPF.
Something based upon WaveFileTrimmerControl.xaml would be useful, it uses related controls PolygonWaveFormControl.xaml & RangeSelectionControl.xaml (links are to the XAML but refer to the CS also). In any case it'd be a good starting point for building a control that exactly meets what you want.
You could override the render method and use primitives which will give possibly better performance; but like anything related to performance I'd try the above approach first which is almost certainly good enough.
I need more precision then integer based locations when puttng controls on a form.
It seems control.location only supports Point.
Is there a work around for this?
Point p = new Point(100, 200);
this.Location = p;// this works of course
PointF pF = new PointF(100.04f, 200.08f);
this.Location = pF;// this does not work of course because Location expects a Point not PointF
Is there some setting on the base form, or base control I can set to have more location precision?
You could use Windows Presentation Foundation (WPF) together with XAML (both work nicely within Visual Studio), which allows subpixel positioning of controls.
However, assuming that you are using Windows Forms and not WPF, why would you ever need to put a control on a non-integer (subpixel) location?
Although GDI+ is capable of floating point coordinate systems, Win32 (upon which Winforms is based) is not. I second the reccomendation to move to WPF which has a ubiquitous floating point coordinate system based on device independent virtual pixels.
No, control rendering in WinForms is all fundamentally pixel-based. There is a way you could achieve sub-pixel positioning (without using WPF), but it would be work on your part, and I'm really not sure why you would need this anyway.
The gist of the approach is to create a user control with a hidden instance of the control you're trying place funkily (sub-pixelly, maybe). You wire up all the user control's events so that they pass through to the hidden control, and after each event is passed you call the hidden control's DrawToBitmap method to get a snapshot of the control. You then use Graphics.DrawImage to copy the snapshot to the surface of the user control. DrawImage is not restricted to pixels, so you can offset the drawing by less than a pixel to achieve the precise positioning you're looking for.
Warning: please do not actually do this, as there is no reason for it when you can just use WPF. This would be a lot of work, since "passing the control's events through" is not as simple matter as it sounds. There's also a problem with rendering the focus correctly in this manner, as the invisible control cannot be given the focus (I'm not even going to tell you what the grisly hack solution is to that problem).
Update: It's worth revisiting that decision about WPF - it is ideal for what you're doing and would make your life much simpler. I have been generally underwhelmed by WPF, because I think that while it's very powerful it is essentially overpowered for the uses to which it is most often put (namely, boring-ass business apps). In your case, though, it provides a granularity that you actually require in your app.
If you're stuck in WinForms, however, your best approach is to write your own UserControl versions of the text-editing controls that your application requires. At its core, a TextBox is just a square that you draw a border around and some text on. The .Net Graphics methods for this (DrawRectangle and DrawString) can have the drawing coordinates specified in floating point.
There are tons of StackOverflow questions about owner-drawn user controls and GDI+ graphics.
1 point is 1 pixel and therefore the maximum resolution required.
This is the reason why 0,0 maps to the left corner, and 1024 maps to the right, in a resolution of 1024x768