views:

63

answers:

3

I'm creating a dashboard application that shows hundreds of "items" on a FlowLayoutPanel.

Each "item" is a UserControl that is made up of 12 or labels.

My app queries a database and then creates an "item" instance for each record, populating ethe labels and textboxes with data before adding it to the FlowLayoutPanel.

After adding about 560 items to the panel, I noticed that the USER Objects count in my Task Manager had gone up to about 7300, which was much much larger than any other app on my machine.

I did a quick spot of mental arithmetic (OK, I might have used calc.exe) and figured that 560 * 13 (12 labels plus the UserControl itself) is 7280. So that suddenly gave away where all the objects were coming from...

Knowing that there is a 10,000 USER object limit before windows throws in the towel, I'm trying to figure better ways of drawing these items onto the FlowLayoutPanel.

My ideas so far are as follows:

1) User-draw the "item", using graphics.DrawText and DrawImage in place of many of the labels. I'm hoping that this will mean 1 item = 1 USER Object, not 13.

2) Have 1 instance of the "item", then for each record, populate the instance and use the Control.DrawToBitmap() method to grab an image and then use that in the FlowLayoutPanel (or similar)

So... Does anyone have any other suggestions ???

P.S. It's a zoomable interface, so I have already ruled out "Paging" as there is a requirement to see all items at once :(

Thanks everyone.

A: 

Your idea #2 is the one I would recommend. This is exactly how list and grid controls intended to display thousands of records are able to perform in-place editing. You start with just one control, and move it around to wherever you need it.

If you need to display several instances at the same time then it's a little bit harder - as you mention, you would most likely have to use DrawToBitmap and display the "ghost image" of the control.

Alternatively, I assume that there's some scrolling going on here (nobody can actually look at 7280 UI objects at once, right?), so the other thing you could do is dynamically create only the instances which are actually going to be on the screen at the same time. You'd have to calculate the visible area and compare that against the list of controls to be displayed, and just display placeholders if the UI is zoomed out too much to actually make out any details. I imagine that scrolling/zooming would become a pretty CPU-intensive operation if you did this, though; better to just not create them at all.

Aaronaught
+1  A: 

At a minimum, I would start with your idea #1. This will indeed reduce the number of windows your application is gobbling up by a factor of 13.

Regarding your idea #2, that won't really help you at all if you then put the Bitmap into a PictureBox (or whatever) and thus have a large number of PictureBox controls on your form (this could even be worse, since Bitmaps sometimes are composed of a more limited resource than general RAM, which is an entirely different problem from consuming too many windows). This would only be a good idea if you were taking the resulting Bitmaps and copying them onto a single larger control (and then Disposing the Bitmaps).

If you take this latter approach, then there's really no need to utilize the intermediate step of rendering to a control, getting a Bitmap copy of the control and then drawing that Bitmap onto a final control. It would make more sense to take the code/logic that you use to render the control, and instead render directly to the final (multi-element) control.

MusiGenesis
As opposed to creating hundreds of bitmaps or picture boxes, I think the approach would be to either draw every control directly to the image of a single `PictureBox`, or have a single "sprite" bitmap and draw all of the controls to that. Although if they're really *just* labels then I suppose it's easier to use a `TextRenderer` and bypass the controls entirely - it's hard to tell exactly what needs to be drawn here.
Aaronaught
I'd steer him away from `TextRenderer`, as it's pretty slow (relative to `Graphics.DrawString`), but otherwise I agree that his best approach is to just render each database row directly to a single control (and preferably only render the visible rows).
MusiGenesis
A: 

I've implemented #1 with good results.

13x less user objects, and it also feels faster and more responsive.

Thanks for the suggestions - I'm surprised that this isn't a more common problem !

Andy Blackman