Speeding up DataGridView RowCount assignment
-
In code below Line m_Grid.RowCount = 1000000; takes 8 seconds. How to speed it up ? Andrus.
using System;
using System.Windows.Forms;
using System.Collections.Generic;class test
{
[STAThreadAttribute()]
public static void Main()
{
Application.Run(new VirtualModeForm());
}
}class VirtualModeForm : Form
{
private List<DataObject> m_Data = new List<DataObject>();
private List<bool> m_Visited = new List<bool>();
DataGridView m_Grid = new DataGridView();
public VirtualModeForm()
{
Controls.Add(m_Grid);
m_Grid.CellValueNeeded += OnCellValueNeeded;
InitData();
InitGrid();
}private void InitData() { for (int i = 0; i < 1000001 + 1; i++) { m\_Visited.Add(false); DataObject obj = new DataObject(); obj.Id = i; obj.Val = 2 \* i; m\_Data.Add(obj); } } private void InitGrid() { m\_Grid.Dock = DockStyle.Fill; m\_Grid.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCellsExceptHeader); m\_Grid.VirtualMode = true; m\_Grid.ReadOnly = true; m\_Grid.ColumnCount = 108; // this line causes 8 seconds delay. how to fix. m\_Grid.RowCount = 1000000; } private void OnCellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { m\_Visited\[e.RowIndex\] = true; if (e.ColumnIndex == 0) { e.Value = m\_Data\[e.RowIndex\].Id; } else if (e.ColumnIndex == 1) { e.Value = m\_Data\[e.RowIndex\].Val; } else if (e.ColumnIndex == 2) { Random rand = new Random(); e.Value = rand.Next(); } }
}
public class DataObject
{
private int m_Id;
private int m_Val;public int Val { get { return m\_Val; } set { m\_Val = value; } } public int Id { get { return m\_Id; } set { m\_Id = value; } } public int Id1 { get; set; } public int Id2 { get; set; } public int Id3 { get; set; } public int Id4 { get; set; } public int Id5 { get; set; } public int Id6 { get; set; } public int Id7 { get; set; } public int Id8 { get; set; } public int Id9 { get; set; } public int Id10 { get; set; } public int Id11 { get; set; } public int Id12 { get; set;
If you're already using virtual mode, why set the row count so high. Try a smaller value like 100. When additional rows are needed, CellValueNeeded should provide them from a store like datatable, array etc.
The need to optimize rises from a bad design. My articles[^]
-
If you're already using virtual mode, why set the row count so high. Try a smaller value like 100. When additional rows are needed, CellValueNeeded should provide them from a store like datatable, array etc.
The need to optimize rises from a bad design. My articles[^]
Fake Rowcount causes the following issues: 1. It is not possible to see more rows: you can navigate only between first 100 rows. No way to go to row number 101. 2. Buttor in vertical scrollbar does not show real position in table. For real rowcount, button indicates visually real position: in the start, in middle or in end of table. So it is impossible to use fake rowcount.
Andrus
-
In code below Line m_Grid.RowCount = 1000000; takes 8 seconds. How to speed it up ? Andrus.
using System;
using System.Windows.Forms;
using System.Collections.Generic;class test
{
[STAThreadAttribute()]
public static void Main()
{
Application.Run(new VirtualModeForm());
}
}class VirtualModeForm : Form
{
private List<DataObject> m_Data = new List<DataObject>();
private List<bool> m_Visited = new List<bool>();
DataGridView m_Grid = new DataGridView();
public VirtualModeForm()
{
Controls.Add(m_Grid);
m_Grid.CellValueNeeded += OnCellValueNeeded;
InitData();
InitGrid();
}private void InitData() { for (int i = 0; i < 1000001 + 1; i++) { m\_Visited.Add(false); DataObject obj = new DataObject(); obj.Id = i; obj.Val = 2 \* i; m\_Data.Add(obj); } } private void InitGrid() { m\_Grid.Dock = DockStyle.Fill; m\_Grid.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCellsExceptHeader); m\_Grid.VirtualMode = true; m\_Grid.ReadOnly = true; m\_Grid.ColumnCount = 108; // this line causes 8 seconds delay. how to fix. m\_Grid.RowCount = 1000000; } private void OnCellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { m\_Visited\[e.RowIndex\] = true; if (e.ColumnIndex == 0) { e.Value = m\_Data\[e.RowIndex\].Id; } else if (e.ColumnIndex == 1) { e.Value = m\_Data\[e.RowIndex\].Val; } else if (e.ColumnIndex == 2) { Random rand = new Random(); e.Value = rand.Next(); } }
}
public class DataObject
{
private int m_Id;
private int m_Val;public int Val { get { return m\_Val; } set { m\_Val = value; } } public int Id { get { return m\_Id; } set { m\_Id = value; } } public int Id1 { get; set; } public int Id2 { get; set; } public int Id3 { get; set; } public int Id4 { get; set; } public int Id5 { get; set; } public int Id6 { get; set; } public int Id7 { get; set; } public int Id8 { get; set; } public int Id9 { get; set; } public int Id10 { get; set; } public int Id11 { get; set; } public int Id12 { get; set;
Hi, do some research on DataGridView.VirtualMode, that is the official way to handle insane amounts of data in a reasonable time. I haven't used it myself yet, so I won't be able to explain from experience. :)
Luc Pattyn [Forum Guidelines] [My Articles]
Fixturized forever. :confused:
-
Fake Rowcount causes the following issues: 1. It is not possible to see more rows: you can navigate only between first 100 rows. No way to go to row number 101. 2. Buttor in vertical scrollbar does not show real position in table. For real rowcount, button indicates visually real position: in the start, in middle or in end of table. So it is impossible to use fake rowcount.
Andrus
Sorry, wrote that in a hurry. Rowcount is the actual amount which is used to define scroll size. If you have wired CellValueNeeded correctly, it should work fine. Have you checked that CellValueNeeded is actually used and is it called (several times) when you set the rowcount. Another thing is that you have automatic sizes for columns. That may slow this quite a lot. Try commenting it out and test if any change.
The need to optimize rises from a bad design. My articles[^]
-
Hi, do some research on DataGridView.VirtualMode, that is the official way to handle insane amounts of data in a reasonable time. I haven't used it myself yet, so I won't be able to explain from experience. :)
Luc Pattyn [Forum Guidelines] [My Articles]
Fixturized forever. :confused:
-
Lyc, as you see from my sample it already uses VirtualMode. The issue is that increasing number of rows decreases RowCount setting speed. This should not happen.
Andrus
Hi, I suggest you study some examples, and observe your code as to what exactly is going on. As in: how many ValueNeeded events do fire, and how many items are visible at one time. If there is a mismatch, then that is the problem. The basic concept is the DGV should only fire ValueNeeded for items that have to be drawn. BTW are you sure you want over 100 columns? and all those get/set properties? it does not look right. Also I don't like the two lists of properties, the only data you should need is a list of items. Avoid redundancy! :)
Luc Pattyn [Forum Guidelines] [My Articles]
Fixturized forever. :confused:
-
Sorry, wrote that in a hurry. Rowcount is the actual amount which is used to define scroll size. If you have wired CellValueNeeded correctly, it should work fine. Have you checked that CellValueNeeded is actually used and is it called (several times) when you set the rowcount. Another thing is that you have automatic sizes for columns. That may slow this quite a lot. Try commenting it out and test if any change.
The need to optimize rises from a bad design. My articles[^]
Mika, thank you for reply. Tried tried the following: 1. OnCellValueNeeded is not called: F11 steps to next line after 8 sec delay. Debug output window shows a lot of messagers "skipping over non-user code". Delay seems to occur after those messages are output. 2. I removed m_Grid.AutoResizeColumns line and tried with DataGridViewAutoSizeColumnsMode.None Delay still occurs. I'm wondering why number or rows affects to this delay. VirtualMode must be designed to avoid this. Is it possible to use other control to create editable virtual grid ? I looked SourceGrid in http://www.devage.com/[^] but it last update was a year ago so it seems not maintained. Those grids are used frequently in my application in UI. Data for visibla part of a grid grid is retrieved from database for 4 seconds due to virtualization. It is not reasonable to force user to wait 8 seconds for a grid to render. Any idea how to fix this ?
Andrus
-
Hi, I suggest you study some examples, and observe your code as to what exactly is going on. As in: how many ValueNeeded events do fire, and how many items are visible at one time. If there is a mismatch, then that is the problem. The basic concept is the DGV should only fire ValueNeeded for items that have to be drawn. BTW are you sure you want over 100 columns? and all those get/set properties? it does not look right. Also I don't like the two lists of properties, the only data you should need is a list of items. Avoid redundancy! :)
Luc Pattyn [Forum Guidelines] [My Articles]
Fixturized forever. :confused:
Luc, Thank you. MSDN has DataGridView_Samples.zip which contains two VirtualMode grid samples and a doc file covering VirtualMode a bit. Part of samples from this file are also duplicated in MSDN doc code samples. MSDN forums contains also some few messages about VirtualMode. There is also a Chris Cells book. The sample code presented here is modified sample from this book. My code is based on this information. I have looked first 100 pages returned from google search. I havent found any other information about DataGridView VirtualMode. Pressing F11 in RowCount moves to next line after delay. So OnCellValueNeeded method not any other lines in my code are not called. In real application I have wide Product tables which can contain 100 columns. They appear fine in wide LCD screen. Reducing number of columns to 50 causes also long delay. I'm sorry for a bad sample. Below is minimal code to reproduce 8 sec delay issue.
using System;
using System.Windows.Forms;class Test
{
public static void Main()
{
Application.Run(new VirtualModeForm());
}
}class VirtualModeForm : Form
{
DataGridView grid = new DataGridView();
public VirtualModeForm()
{
Controls.Add(grid);
grid.VirtualMode = true;
grid.ColumnCount = 108;
// this line causes 8 seconds delay.
grid.RowCount = 1000000;
}
}Andrus
-
Luc, Thank you. MSDN has DataGridView_Samples.zip which contains two VirtualMode grid samples and a doc file covering VirtualMode a bit. Part of samples from this file are also duplicated in MSDN doc code samples. MSDN forums contains also some few messages about VirtualMode. There is also a Chris Cells book. The sample code presented here is modified sample from this book. My code is based on this information. I have looked first 100 pages returned from google search. I havent found any other information about DataGridView VirtualMode. Pressing F11 in RowCount moves to next line after delay. So OnCellValueNeeded method not any other lines in my code are not called. In real application I have wide Product tables which can contain 100 columns. They appear fine in wide LCD screen. Reducing number of columns to 50 causes also long delay. I'm sorry for a bad sample. Below is minimal code to reproduce 8 sec delay issue.
using System;
using System.Windows.Forms;class Test
{
public static void Main()
{
Application.Run(new VirtualModeForm());
}
}class VirtualModeForm : Form
{
DataGridView grid = new DataGridView();
public VirtualModeForm()
{
Controls.Add(grid);
grid.VirtualMode = true;
grid.ColumnCount = 108;
// this line causes 8 seconds delay.
grid.RowCount = 1000000;
}
}Andrus
Hi Andrus, I did a little experiment with your code. Observations: - time elapsed is proportional to number of rows; - time elapsed heavily depends (not proportional) on number of columns - setting RowCount first is a lot faster. Conclusions: 1) the DGV seems to create objects for all the cells right from the start, and creating 108 million objects is bound to take a couple of seconds. 2) for unknown reasons RowCount-first is faster BTW: you should not add the grid to Controls before it has been set up. :)
Luc Pattyn [Forum Guidelines] [My Articles]
Fixturized forever. :confused:
-
Hi Andrus, I did a little experiment with your code. Observations: - time elapsed is proportional to number of rows; - time elapsed heavily depends (not proportional) on number of columns - setting RowCount first is a lot faster. Conclusions: 1) the DGV seems to create objects for all the cells right from the start, and creating 108 million objects is bound to take a couple of seconds. 2) for unknown reasons RowCount-first is faster BTW: you should not add the grid to Controls before it has been set up. :)
Luc Pattyn [Forum Guidelines] [My Articles]
Fixturized forever. :confused:
Luc, 2) for unknown reasons RowCount-first is faster Thank you very much. You are genious. I tried this in my applicaton and this eliminates RowCount delay. Now there is only 3 sec delay which is caused by reading first two pages to cache like in MSDN sample. There is also SELECT COUNT(*) FROM mytable command but this seems not to cause any delay. the DGV seems to create objects for all the cells right from the start, and creating 108 million objects is bound to take a couple 108 millions of objects should take visible in Task Manager amout of memory. Task Manager memory (working set) does not show significat memory consumption. So I think that 108 million of objects are not created. Maybe this is related to sililar issue which posted here and in MS product feedback and which does not have any solution: Steps to reproduce: 1. Run code below 2. Double click in grid header in separation line between columns 1 ja 2 Observed: CPU usage goes to 100% for a long time.
using System; using System.Windows.Forms; using System.Collections.Generic; class test { [STAThreadAttribute()] public static void Main() { Application.Run(new VirtualModeForm()); } } class VirtualModeForm : Form { private List<DataObject> m_Data = new List<DataObject>(); private List<bool> m_Visited = new List<bool>(); DataGridView m_Grid = new DataGridView(); public VirtualModeForm() { Controls.Add(m_Grid); m_Grid.CellValueNeeded += OnCellValueNeeded; InitData(); InitGrid(); } private void InitData() { for (int i = 0; i < 1000001 + 1; i++) { m_Visited.Add(false); DataObject obj = new DataObject(); obj.Id = i; obj.Val = 2 * i; m_Data.Add(obj); } } private void InitGrid() { m_Grid.Dock = DockStyle.Fill; m_Grid.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCellsExceptHeader); m_Grid.VirtualMode = true; m_Grid.ReadOnly = true; m_Grid.ColumnCount = 3; m_Grid.Rows.Add(); m_Grid.Rows.AddCopies(0, 1000000); } private void OnCellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { m_Visited[e.RowIndex] = true; if (e.ColumnIndex == 0) { e.Value = m_Data[e.RowIndex].Id; } else if (e.ColumnIndex == 1) { e.Value = m_Data[e.RowIndex].Val; } else if (e.ColumnIndex == 2) { Random rand = new Random(); e.Value = rand.Next(); } } } public class DataObject { private int m_Id; private int m_Val; public int Val { get { return m_Val; } set { m_Val = value; } } public int Id { get { return m_