In my graphic calculator, I am using canvas as a plane on which graphs of functions are rendered. I have noticed that whenever I input complex functions (I use bezier curves for that, so the more complex the function -> the more points I need to render for the graph to be smooth-looking) it gets quite laggy and overally doesn't perform well.
Which of these solutions are the least computationally costly / thus are the best approach?
1. (My current solution) Using huge Canvas inside a ScrollViewer that limits the view area
Cons I have found:
The whole canvas is rendered, even the non-visible part
Starts to lag when there is more than 50K elements on the canvas
2. Using just Canvas that is not so big, and management of panning / zooming through TransformMatrix
Cons I think there might be (solution not tried):
Won't it be even more laggy when it will have to redraw and recalculate everything dynammically?
3. Some other solutions?
Any help will be greatly appreciated.
If you can avoid it, you really don't want to be using discrete visuals to represent things like charts/graphs; they are very heavy, and are constantly participating in input handling and layout. I would recommend using WPF's drawing/geometry APIs directly. I would suggest implementing a custom control which performs its own rendering (see OnRender). I would also suggest implementing IScrollInfo so you can manage your own scrolling: you will always know the viewport size and position, which gives you the option of invalidating your geometry when scrolling, and then rebuilding only the parts of the graph that are actually in view. That should reduce the overhead significantly.
Related
I am making a project that draw Numbers in multicolored random dots. If you type in a 1,000,000 the scree will slowly paint with 1M dots that look like the number. I'm migrating to WPF and wanted known if there is an easy wat to pain on top of a text block as that will save a lot of hit testing for me.
Adorners are designed to do exactly that. They allow you to render controls, drawings, or anything you like on a separate layer that is always on top of other controls.
As my first WPF project, I am attempting to build an application to play a card game similar to Magic the Gathering. It is not clear to me how to lay out the main play area. You can see some examples that are similar to what I am attempting by looking at example 1 or example 2. The chat/info areas on the right would be separate user controls.
The cards must maintain their aspect ratios, and each play area would start with 10 columns and two rows of cards. As more cards are played, the number of columns and/or rows may change. Each player area may have a different number of columns and/or rows. Cards may overlap, and may be placed sideways (tapped). Cards in all areas should be the same size (although they may be cropped in some areas). Cards do not need to lie exactly on the grid (they do not necessarily snap-to-grid).
When the user hovers the mouse over a card, it should expand to a significantly larger size using an animation. A card in one player area may overflow into the other player's area when expanded (but only as long as the mouse hovers).
Given these requirements, I am tempted to use one large user control derived from Canvas with image objects for each card (along with other shapes to delineate the areas). This implies that I will be doing a lot of work during the OnRenderSizeChanged event to position the child items within the canvas (manual layout).
Using a grid does not seem feasible to me, due to the free-form placement and overlap.
Decomposing the play area into smaller user controls would leverage the WPF layout capabilities, but it seems like decomposition would prevent the cards from expanding into adjacent user controls during the mouse-over, so that doesn't seem feasible either.
Is there a better alternative to one large canvas-based control? It seems wrong to be doing manual layout in WPF, but I cannot see an alternative.
This sounds like a great scenario for Composite Application ala Prism. It provides solid framework for implementing regions, modules, sending message between modules etc... From looking at your screen captures, developing a shell with different regions and dropping modules into them would probably greatly benefit your layout. As for the cards themselves, perhaps they could be modules as well?
Check out:
http://msdn.microsoft.com/en-us/library/ff649780.aspx
Particualy good examples come with the download package including a stock market like application and event aggregator example.
You said:
Decomposing the play area into smaller user controls would leverage the WPF layout capabilities, but it seems like decomposition would prevent the cards from expanding into adjacent user controls during the mouse-over, so that doesn't seem feasible either.
But this is not correct. Decomposition is absolutely the right approach to take, and this would not prevent the cards from expanding into adjacent user controls. The reason being that you can use a RenderTransform rather than a LayoutTransform. See this example, by Charles Petzold, or this article, to visualize the difference. Because a RenderTransform is applied after the layout has already occurred, your cards would be able to expand outside their bounds.
Given that decomposition is the right approach, I would arrange your various card collections into a Grid, with each collection being an ItemsControl. The ItemsControl should bind its ItemsSource property to some collection, and then you can provide a custom ItemTemplate that would display the image and any other information. I would be hesitant to use a Canvas, as this would restrict you to hard-coding the positions for the cards (which is a very WinForms-like solution for a problem that can be far more elegantly solved). Take advantage of WPF's fantastic layout engine and use nested grids and items controls to create a dynamic layout. This will ensure that your game board looks good at any resolution and when stretched to various sizes.
I recommend you take a look at this guys project . In java I know but if I was to go the route of building a card game. That would be what I would go off of.
A lot of canvases inside of a grid could help you here, the canvas will allow the content to render outside of its bounds, as long as you turn ClipToBounds to false, and you will be given much more control over exact placement of the cards than with other schemes. You will also get the powerful functionality of a grid control, allowing you to add and remove columns and rows as needed (though you will also have to dynamically add and remove canvasses, though this isn't too difficult.
If you're worried about the contents of your "Card" moving around when the box is rescaled, surround it in a viewbox. It will manage all your scaling for you, and ensures your card uses as much real estate as it can get. Alternatively you could use a RenderTransform, but a lot of these might slow your program down (Experts: does the viewbox operate using RenderTransforms? If so this point is moot)
To ensure the cards maintain their aspect ratios make sure each Image's Stretch attribute is set to "Uniform", making them all keep the same size could be done by designating a master card, and binding heights and widths of all subsequent cards to this original card, though that is a little messy and doesn't allow the cards to expand. Another solution is to set a single size for each card manually, animating this when you want to expand or shrink.
I want to do basic WPF graphics, i.e. rectangles, lines, circles and text.
When should I use Drawing and when should I use a DrawingVisual?
I have some code that uses Drawing and I render those to a DrawingImage and display that in an image control. Is this the right way? I could not see how to add text to a drawing. I had trouble positioning it too. Should I be rendering to a Canvas?
I have some code that uses DrawingVisual and writes to a DrawingContext. That is like WinForms. Is this the recommended way?
Do you have any high level advice on which APIs to use for basic graphics and labels? Will they options work on Silver Light and Desktop?
You mention in your comment that you're actually implementing scatter plots or similar graphs. Typically in WPF this is created by templating the existing controls, like a listview. It sounds counterintuitive, but this is far easier and more powerful than drawing your own.
This article by Charles Petzhold shows a scatter plot implemented in this way and goes into great detail about how to make it performant to 10,000+ data points.
You'll most likely want to just render to a Canvas. If you add "shapes" to a canvas, WPF will handle all of the drawing for you.
For details, see Shapes and Basic Drawing in WPF.
How can I speed up the scrolling of UserControls in a WinForms app.?
My main form has trouble scrolling quickly on slow machines--painting for each of the small scroll increments is CPU intensive.
My form has roughly fifty UserControls (with multiple fields) positioned one below the other.
I’ve tried intercepting OnScroll and UserPaint in order to eliminate some of the unnecessary re-paints for very small scroll events, but the underlying Paint gets called anyway.
How can I streamline scrolling on slower machines?
The tried-and-true method is to use an offscreen bitmap which is updated only when the data represented by your control actually changes; then, all OnPaint needs to do is render that bitmap to the screen.
If your paint process is intensive, and since you have so many controls, you'll find this makes a massive difference to the performance of your application.
Note that using the DoubleBuffering control property won't help in your case--it does tell WinForms to render to an offscreen bitmap before rendering to the screen, but that still happens at every paint cycle since WinForms doesn't keep track of when the representation has changed.
So, you'd have to roll your own. It's not that difficult. Here's what looks like a reasonably good article on the subject.
You can also increase the size of the scroll step. For example
panel1.VerticalScroll.SmallChange = 100;
Will cause the panel to scroll it's content 100 units vertically per click of the scrollbar button. So you take bigger steps each time, that might make the experience feel better at least. And you can do the same for the horizontal scroll bar of course.
I have used tabs to eliminate scrolling.
I am working on an application that uses several large canvas controls (several thousand pixels across), layered on top of each other. The canvas controls themselves are completely invisible, but each contains a number of controls, mainly images.
My question is, is there a recommended maximum size for a canvas, or is it purely a memory issue? And also, are we better off setting the Canvas size to (0, 0) and making use of the fact that we can happily render controls outside of the bounds of the canvas?
Thanks,
G
Watch out: the maximum size of a Silverlight canvas is 32767 points. This is because the size of UIElements is not stored as floats as it is in WPF, but in 32 bit quantities of which 16 bits form the integer of size and 16 bits form the floating part of it. So make sure your canvas is not bigger than that and not going to be.
The solution which you would need to make it larger is to do the scrolling yourself and position the objects yourself. In effect you're recreating the canvas. This is called Virtualizing in WPF terms.
The memory consumption won't be bigger depending on the canvas size but depend only on the number of controls and the cumulative memory size of those controls. However, if you're going to have a lot of WPF objects, the layout phase does take considerable time with more (say, more than 1000) objects. If that's going to be a problem you need to code it yourself again and have a cache of unused WPF objects of the same type lying around (since WPF object creation is also quite slow).
From my understanding of the innards of Canvas, it should need no additional memory for being bigger.
The first thing that comes to my mind on having a non-zero sized Canvas is that it allows one to put items on it relatively to any of the four corners, which helps when e.g. resizing the container.