views:

81

answers:

4

I have a folder with a large amount of files inside of it. I want to be able to render each of my files as a button. And when I click on the button something will happen.

 private void Form1_Load(object sender, EventArgs e)
    {
        int x = 10; 
        int y = 10;

        /// Process the list of files found in the directory.
        string[] fileEntries = Directory.GetFiles(@"c:\lotsofDocs");
        foreach (string fileName in fileEntries)
        {
            // do something with fileName
            Button newbotton = new Button();
            newbotton.AutoSize = true;
            newbotton.Text = fileName;
            panel1.Controls.Add(newbotton);
            newbotton.Location = new Point(x, y);
            x += 150;
            if (x == 760)
            {
                y += 50;
                x = 10;
            }
        }

As you can see there's nothing crazy in the code. I have a panel on a form and I've set auto scroll on the panel to true and auto size to false. This causes the form to maintain size and the buttons (some of them anyway) to get rendered off the form and I can scroll down to them.

All good so far.

If I have 100 or 200 file everything is ok, if I have 1932 files it takes about 10 seconds to render all the buttons.

I've read the follow question Super slow C# custom control and I understand that the approach I'm using might not be the best to use here.

And now the question at last: how does windows explorer handle this? If I open this folder in Windows explorer it opens instantly. What type of control is windows explorer using? Or is it doing it in a completly different way to me.

Thanks

+3  A: 

Very long lists of controls are usually implemented via virtualised controls. That means that if only 20 buttons fit on the screen it only creates 20 buttons or so. When you scroll around it reuses the same 20 buttons with new data in them.

Controls can be very slow to create and manage in large numbers as they are usually added to a simple lists or hierarchy (and are quite complex individually).

Better off managing a smaller set of buttons yourself to show a very long list of data. More work obviously, but the end result is lightening fast compared to the "simple way".

If you don't want to DIY, try a third party control. As an example the Telerik virtualised Tree, List and Grid controls can display a million records with no slowdown. Take a look at their Winforms grid here

Enough already
A: 

Can you allocate all the buttons at once? What I mean is, create an array of buttons after you read the file names (so you know how many buttons to create), then simply set their properties in the loop. I don't know how much that will speed things up, but it's worth a try. You might also see if there's an override on the panel's Add method that takes an array or list of controls and add them all at once, too.

TMN
I tried using the addRange method but surprisingly it turned out to be slower :(
AidanO
+2  A: 

You should look at the ListView. It provides the same basic set of functionality as the file area in Windows Explorer with comparable performance.

Make sure to call BeginUpdate before adding your items and EndUpdate when you are done for the best performance. Adding your items with Items.AddRange is also good for performance.

Albin Sunnanbo
A: 

One trick that often helps improving slow contruction / change operations is to hide the controls and / or the parent container involved. In your case, that would mean hiding panel1 before creating the controls, and showing it again afterwards. Might not help a bit in your case, but it's worth a try.

However, you will have fundamental problems creating so many controls in Win32 or WinForms. While the Window System now can handle these, it's not the thing tries to be good at.

It is also not the best user interface for that. 2000 Buttons in a 5 x 400 matrix? Holy effin' cow. I don't want to use that. What do you do if a file name does not fit 150 pixels? What do you do on displays where "150" means ".15 mm"?

Alternatives
Why not a list control? That at least has page up / page down, and type ahead to find items starting with the text I enter. Throw in a "quick filter" edit control on top of it, where where entering some text filters out any files that don't contain it, and you have a standard interface that can be used efficiently. If you expect many items, you can put the LitView control into virtual mode. While this loses some built-in features (e.g. autosizing columns), it works with insane numbers of items thrown at it.

You could also render the buttons as HTML links, and show it inside a browser control. That's not necessarily faster, but HTML renders progressively, I can use the list while you are still feeding items.

peterchen
I tried setting the panel visable status to false, and while it was quicker to add the buttons, it took almost all the time I'd saved to make the panel visable again.
AidanO
ah... would have been nice. So you probably went for a list view?
peterchen