Home All Groups Group Topic Archive Search About

DataGridView performance

Author
24 Nov 2006 4:05 PM
John Brown
Hi there,

Has anyone had any serious performance problems with this class. A couple of
hundred rows of data with 4 columns (everything loaded on-the-fly with no DB
involved, all simple strings, 90% under 10 characters, the rest as high as
500-600 characters, wrapping turned on) literally takes almost 3 minutes to
load on my 2.4 MHz machine (1 GB RAM with plenty to spare). Wrapping may be
the bottleneck (performance improves when I turn it off) but other than
using virtual mode, can anyone suggest a way to speed things up (or a
reliable 3rd-party control which is really something I wanted to avoid).
Thanks.

Author
24 Nov 2006 4:28 PM
Marc Gravell
Looks pretty quick to me...
Try this: it invents 5000 rows of data using 4 string properties, random
length up to 600 chars; loads almost instantly on similar spec PC, even
including property notification handlers; have you got some example code?

using System;
using System.Windows.Forms;
using System.Collections.Generic;
class MyData
{
    private string fieldA, fieldB, fieldC, fieldD;
    private void OnEvent(EventHandler handler)
    {
        if (handler != null) handler(this, EventArgs.Empty);
    }
    public event EventHandler PropertyAChanged, PropertyBChanged,
PropertyCChanged, PropertyDChanged;
    public string PropertyA
    {
        get { return fieldA; }
        set
        {
            if (fieldA != value)
            {
                fieldA = value;
                OnEvent(PropertyAChanged);
            }
        }
    }
    public string PropertyB
    {
        get { return fieldB; }
        set
        {
            if (fieldB != value)
            {
                fieldB = value;
                OnEvent(PropertyBChanged);
            }
        }
    }
    public string PropertyC
    {
        get { return fieldC; }
        set
        {
            if (fieldC != value)
            {
                fieldC = value;
                OnEvent(PropertyCChanged);
            }
        }
    }
    public string PropertyD
    {
        get { return fieldD; }
        set
        {
            if (fieldD != value)
            {
                fieldD = value;
                OnEvent(PropertyDChanged);
            }
        }
    }
}
static class Program
{
    static readonly Random rand = new Random(123456);
    static string RandomString() {
        int length = rand.Next(600);
        char[] chars = new char[length];
        for (int i = 0; i < length; i++)
        {
            chars[i] = (char) rand.Next(32, 122);
        }
        return new string(chars);
    }
    static void Main()
    {
        const int COUNT = 5000;
        List<MyData> data = new List<MyData>(COUNT);
        for (int i = 0; i < COUNT; i++)
        {
            MyData item = new MyData();
            item.PropertyA = RandomString();
            item.PropertyB = RandomString();
            item.PropertyC = RandomString();
            item.PropertyD = RandomString();
            data.Add(item);
        }
        using(Form f = new Form())
        using (DataGridView dgv = new DataGridView())
        {
            dgv.Dock = DockStyle.Fill;
            dgv.DataSource = data;
            f.Controls.Add(dgv);
            Application.Run(f);
        }
    }
}

Marc
Author
24 Nov 2006 4:29 PM
Marc Gravell
(note still performant if I add dgv.DefaultCellStyle.WrapMode =
DataGridViewTriState.True;)

Marc
Author
24 Nov 2006 4:37 PM
John Brown
> (note still performant if I add dgv.DefaultCellStyle.WrapMode =
> DataGridViewTriState.True;)
>
> Marc

Thanks very much (appreciated). I'll try your sample and let you know ...
Author
24 Nov 2006 4:48 PM
Marc Gravell
As a guess, I would imagine that the problem is that you are adding rows
while it is UI bound, so each insert needs to think about a redraw. Some
controls have a BeginUpdate / EndUpdate pair to help with this, but you
could try disabling layout - it *may*help:

            dgv.SuspendLayout();
            try {
                // your code
            } finally {
                dgv.ResumeLayout();
            }

Alternatively, if you are using a BindingSource, that has a SuspendBinding /
ResumeBinding, or as a last resort you could remove the data-source (from
the grid) completely while editing.

Again, I could probably help more with a code snippet *that is runnable and
demonstrates the problem*.
(Jon puts it very well: http://www.yoda.arachsys.com/csharp/complete.html)

Marc
Author
24 Nov 2006 5:12 PM
John Brown
Show quote
"Marc Gravell" <marc.grav***@gmail.com> wrote in message
news:uOGcch%23DHHA.3596@TK2MSFTNGP03.phx.gbl...
> As a guess, I would imagine that the problem is that you are adding rows
> while it is UI bound, so each insert needs to think about a redraw. Some
> controls have a BeginUpdate / EndUpdate pair to help with this, but you
> could try disabling layout - it *may*help:
>
>            dgv.SuspendLayout();
>            try {
>                // your code
>            } finally {
>                dgv.ResumeLayout();
>            }
>
> Alternatively, if you are using a BindingSource, that has a SuspendBinding
> / ResumeBinding, or as a last resort you could remove the data-source
> (from the grid) completely while editing.
>
> Again, I could probably help more with a code snippet *that is runnable
> and demonstrates the problem*.
> (Jon puts it very well: http://www.yoda.arachsys.com/csharp/complete.html)

Already investigated "SuspendLayout()" with no success. It's starting to
look like there's little I can do other than relying on virtual mode. I also
found this (where MSFT provides some possible remedies but basicallly
acknowledges the "lower performance" and perhaps a "fast painting mod" for a
future release).

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=117093
Author
24 Nov 2006 4:56 PM
John Brown
"John Brown" <no_spam@_nospam.com> wrote in message
news:ONyTKb%23DHHA.3600@TK2MSFTNGP06.phx.gbl...
>> (note still performant if I add dgv.DefaultCellStyle.WrapMode =
>> DataGridViewTriState.True;)
>>
>> Marc
>
> Thanks very much (appreciated). I'll try your sample and let you know ...

Ok, it does load almost instantly now. Painting is still painfully
(unacceptably) slow however (navigating as well). I did find the original
problem though. Try setting "AutoSizeColumnsMode" to
"DataGridViewAutoSizeColumnsMode.AllCells" Now it takes forever to load.
Have you used the older "DataGrid" class. I understand it's much faster but
without all the bells and whistles. Do you have any opinion on it. Thanks.
Author
24 Nov 2006 5:17 PM
Marc Gravell
Interestingly, it appears to take about 3-4 times as long if it does this in
the inital load. I'm guessing due to resizing fonts etc requiring a re-draw.

Try the following, which loads the data when you first drag the mouse over
the grid - it loads in about 5 seconds on my poor-mans laptop (1.8, 512) -
so should be better for you. Obviously you might want to put this in a small
timer or something rather than rely on user intervention (I'm guessing that
using Load would still cause the redraws; haven't tested though)

Main difference is where the data gets initialised (although the important
bit really is when the bindings get set against the dgv, or in this case,
reset):

    static void Main()
    {
        const int COUNT = 5000;
        bool loaded = false;
        BindingList<MyData> data = new BindingList<MyData>();
        using(Form f = new Form())
        using (DataGridView dgv = new DataGridView())
        {
            dgv.MouseEnter += delegate
            {
                if (loaded) return;
                data.RaiseListChangedEvents = false;
                try
                {
                    data.Clear();
                    for (int i = 0; i < COUNT; i++)
                    {
                        MyData item = new MyData();
                        item.PropertyA = RandomString();
                        item.PropertyB = RandomString();
                        item.PropertyC = RandomString();
                        item.PropertyD = RandomString();
                        data.Add(item);
                    }
                }
                finally
                {
                    data.RaiseListChangedEvents = true;
                    data.ResetBindings();
                    loaded = true;
                }
            };
            dgv.AutoSizeColumnsMode =
DataGridViewAutoSizeColumnsMode.AllCells;
            dgv.DataSource = data;
            dgv.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
            dgv.Dock = DockStyle.Fill;
            f.Controls.Add(dgv);
            Application.Run(f);
        }
    }
Author
24 Nov 2006 5:37 PM
John Brown
Show quote
"Marc Gravell" <marc.grav***@gmail.com> wrote in message
news:%23EKvwx%23DHHA.3188@TK2MSFTNGP06.phx.gbl...
> Interestingly, it appears to take about 3-4 times as long if it does this
> in the inital load. I'm guessing due to resizing fonts etc requiring a
> re-draw.
>
> Try the following, which loads the data when you first drag the mouse over
> the grid - it loads in about 5 seconds on my poor-mans laptop (1.8, 512) -
> so should be better for you. Obviously you might want to put this in a
> small timer or something rather than rely on user intervention (I'm
> guessing that using Load would still cause the redraws; haven't tested
> though)
>
> Main difference is where the data gets initialised (although the important
> bit really is when the bindings get set against the dgv, or in this case,
> reset):

It still took several minutes to render itself but that's better than
before. Something's obviously wrong however given that it returns in 5
seconds on your laptop. What I'll have to do is look at your code in greater
detail (BindingList, etc.) and combined with other possible remedies at
MSFT's site (cited in my other post), maybe I can handle painting/drawing on
a page-by-page basis (without turning to virtual mode). With any luck I can
improve things after some experimentation. If worse comes to worse however,
do you have any experience with the "DataGrid" or some other 3rd-party
control. I don't need anything flashy but functional control is important
(the grid's look should be clean and modern - not outdated - but my needs
are mostly utilitarian). Thanks for all your help (truly appreciated)
Author
24 Nov 2006 10:46 PM
Marc Gravell
You're welcome... and if you find what is causing the poor performance,
please let us know.
Alternatively, if you can reproduce it in a standalone example (even if
you can't explain it), then please feel free to post it - I know I
would be interested in having a look, and I'm sure it would pique a few
others too...

Marc
Author
6 Dec 2006 2:18 PM
Coen van Dongen
Dear all,

we are experiencing same 'slow' grid response over here. Problem seems to be related to shared rows becoming unshared (cause by accessing the rows collection with a 'standard' indexer instead of the SharedRows prop/method), first time collection of a row from the collection takes approx 20ms per row on a 3Ghz+ machine. Do the math.. we're working with 150 rows * 20 ms = about 3 seconds just getting stuff from the collection.

Second pass, when rows are already unshared, the getting is done within the ms (used ms precision timing, so don't know exact speed).

If anyone knows how to disable sharing of rows in the datagrid(without using virtualmode), please post.

Could be related...
---
Posted via DotNetSlackers.com

AddThis Social Bookmark Button