The initial layout of the datagrid (CalcGridAreas in particular) ends up recursively calling itself (on one test it was being invoked 5 or 6 times.) You can see this happening with a large datagrid by watching the vertical scrollbar's slider change size as it lays out. This patch calculates the layout/positioning of everything in a single pass, which speeds things up quite a bit. Chris
Index: System.Windows.Forms/ChangeLog =================================================================== --- System.Windows.Forms/ChangeLog (revision 60602) +++ System.Windows.Forms/ChangeLog (working copy) @@ -1,3 +1,11 @@ +2006-05-11 Chris Toshok <[EMAIL PROTECTED]> + + * DataGridDrawingLogic.cs: make CalcGridAreas non-reentrant. + Figure out the positioning/layout in a single pass instead of + multiple recursive invocations. Speeds up the initial display of + the data grid. Also, make many things private that were + originally public but unused outside this class. + 2006-05-11 Atsushi Enomoto <[EMAIL PROTECTED]> * TextBoxBase.cs : implement CTRL+A (select all). Fixed bug #78368. Index: System.Windows.Forms/DataGridDrawingLogic.cs =================================================================== --- System.Windows.Forms/DataGridDrawingLogic.cs (revision 60602) +++ System.Windows.Forms/DataGridDrawingLogic.cs (working copy) @@ -71,7 +71,7 @@ } // Gets a column from a pixel - public int FromPixelToColumn (int pixel) + private int FromPixelToColumn (int pixel) { int width = 0; int cnt = grid.CurrentTableStyle.GridColumnStyles.Count; @@ -129,51 +129,106 @@ } } + bool in_calc_grid_areas; public void CalcGridAreas () { if (grid.IsHandleCreated == false) // Delay calculations until the handle is created return; + /* make sure we don't happen to end up in this method again */ + if (in_calc_grid_areas) + return; + + in_calc_grid_areas = true; + /* Order is important. E.g. row headers max. height depends on caption */ grid.horz_pixeloffset = 0; CalcCaption (); CalcParentRows (); - CalcRowsHeaders (); + CalcRowsHeaders (grid.visiblerow_count); CalcColumnsHeader (); CalcCellsArea (); - UpdateVisibleRowCount (); // need it to be able to calcultate the need of horz scrollbar - if (SetUpVerticalScrollBar ()) { // We need a Vertical ScrollBar - + bool needHoriz = false; + bool needVert = false; + + /* figure out which scrollbars we need, and what the visible areas are */ + int visible_row_count; + int visible_cells_width = cells_area.Width; + int visible_cells_height = cells_area.Height; + int width_of_all_columns = CalcAllColumnsWidth (); + int allrows = grid.RowsCount; + if (grid.ShowEditRow && grid.RowsCount > 0) + allrows++; + + /* use a loop to iteratively calculate whether + * we need horiz/vert scrollbars. */ + for (int i = 0; i < 2; i ++) { + if (needVert) + visible_cells_width = cells_area.Width - grid.vert_scrollbar.Width; + if (needHoriz) + visible_cells_height = cells_area.Height - grid.horiz_scrollbar.Height; + visible_row_count = GetVisibleRowCount (visible_cells_height); + + needHoriz = (width_of_all_columns > visible_cells_width); + needVert = (visible_row_count != allrows); + } + + int horiz_scrollbar_width = grid.ClientRectangle.Width; + int horiz_scrollbar_maximum = 0; + int vert_scrollbar_height = 0; + int vert_scrollbar_maximum = 0; + + if (needVert) + SetUpVerticalScrollBar (out vert_scrollbar_height, out vert_scrollbar_maximum); + + if (needHoriz) + SetUpHorizontalScrollBar (out horiz_scrollbar_maximum); + + cells_area.Width = visible_cells_width; + cells_area.Height = visible_cells_height; + + if (needVert && needHoriz) { if (grid.ShowParentRowsVisible) { parent_rows.Width -= grid.vert_scrollbar.Width; } - if (grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0) { + if (!ShowingColumnHeaders) { if (columnshdrs_area.X + columnshdrs_area.Width > grid.vert_scrollbar.Location.X) { columnshdrs_area.Width -= grid.vert_scrollbar.Width; } } - if (cells_area.X + cells_area.Width >= grid.vert_scrollbar.Location.X) { - cells_area.Width -= grid.vert_scrollbar.Width; - } + horiz_scrollbar_width -= grid.vert_scrollbar.Width; + vert_scrollbar_height -= grid.horiz_scrollbar.Height; } - if (SetUpHorizontalScrollBar ()) { // We need a Horizontal ScrollBar - cells_area.Height -= grid.horiz_scrollbar.Height; - + if (needVert) { if (rowshdrs_area.Y + rowshdrs_area.Height > grid.ClientRectangle.Y + grid.ClientRectangle.Height) { rowshdrs_area.Height -= grid.horiz_scrollbar.Height; rowshdrs_maxheight -= grid.horiz_scrollbar.Height; } + + grid.vert_scrollbar.Height = vert_scrollbar_height; + grid.vert_scrollbar.Maximum = vert_scrollbar_maximum; + grid.Controls.Add (grid.vert_scrollbar); + grid.vert_scrollbar.Visible = true; } + else { + grid.Controls.Remove (grid.vert_scrollbar); + grid.vert_scrollbar.Visible = false; + } - // Reajust scrollbars to avoid overlapping at the corners - if (grid.vert_scrollbar.Visible && grid.horiz_scrollbar.Visible) { - grid.horiz_scrollbar.Width -= grid.vert_scrollbar.Width; - grid.vert_scrollbar.Height -= grid.horiz_scrollbar.Height; + if (needHoriz) { + grid.horiz_scrollbar.Width = horiz_scrollbar_width; + grid.horiz_scrollbar.Maximum = horiz_scrollbar_maximum; + grid.Controls.Add (grid.horiz_scrollbar); + grid.horiz_scrollbar.Visible = true; } + else { + grid.Controls.Remove (grid.horiz_scrollbar); + grid.horiz_scrollbar.Visible = false; + } UpdateVisibleColumn (); UpdateVisibleRowCount (); @@ -183,9 +238,11 @@ //Console.WriteLine ("DataGridDrawing.CalcGridAreas rowshdrs_area:{0}", rowshdrs_area); //Console.WriteLine ("DataGridDrawing.CalcGridAreas columnshdrs_area:{0}", columnshdrs_area); //Console.WriteLine ("DataGridDrawing.CalcGridAreas cells:{0}", cells_area); + + in_calc_grid_areas = false; } - public void CalcCaption () + private void CalcCaption () { if (grid.caption_visible == false) { caption_area = Rectangle.Empty; @@ -200,7 +257,7 @@ //Console.WriteLine ("DataGridDrawing.CalcCaption {0}", caption_area); } - public void CalcCellsArea () + private void CalcCellsArea () { if (grid.caption_visible) { cells_area.Y = caption_area.Y + caption_area.Height; @@ -212,7 +269,7 @@ cells_area.Y += parent_rows.Height; } - if (!(grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0)) { + if (ShowingColumnHeaders) { cells_area.Y += columnshdrs_area.Height; } @@ -223,11 +280,11 @@ //Console.WriteLine ("DataGridDrawing.CalcCellsArea {0}", cells_area); } - public void CalcColumnsHeader () + private void CalcColumnsHeader () { int width_all_cols, max_width_cols; - if (grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0) { + if (!ShowingColumnHeaders) { columnshdrs_area = Rectangle.Empty; return; } @@ -267,7 +324,7 @@ //Console.WriteLine ("DataGridDrawing.CalcColumnsHeader {0}", columnshdrs_area); } - public void CalcParentRows () + private void CalcParentRows () { if (grid.ShowParentRowsVisible == false) { parent_rows = Rectangle.Empty; @@ -288,7 +345,7 @@ //Console.WriteLine ("DataGridDrawing.CalcParentRows {0}", parent_rows); } - public void CalcRowsHeaders () + private void CalcRowsHeaders (int visiblerow_count) { if (grid.CurrentTableStyle.CurrentRowHeadersVisible == false) { rowshdrs_area = Rectangle.Empty; @@ -305,19 +362,49 @@ rowshdrs_area.Y += parent_rows.Height; } - if (!(grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0)) { // first block is painted by ColumnHeader + if (ShowingColumnHeaders) { // first block is painted by ColumnHeader rowshdrs_area.Y += ColumnsHeaderHeight; } rowshdrs_area.X = grid.ClientRectangle.X; rowshdrs_area.Width = grid.RowHeaderWidth; - rowshdrs_area.Height = grid.visiblerow_count * grid.RowHeight; + rowshdrs_area.Height = visiblerow_count * grid.RowHeight; rowshdrs_maxheight = grid.ClientRectangle.Height + grid.ClientRectangle.Y - rowshdrs_area.Y; //Console.WriteLine ("DataGridDrawing.CalcRowsHeaders {0} {1}", rowshdrs_area, // rowshdrs_maxheight); } + private int GetVisibleRowCount (int visibleHeight) + { + int rv; + int total_rows = grid.RowsCount; + + if (grid.ShowEditRow && grid.RowsCount > 0) { + total_rows++; + } + + int rows_height = (total_rows - grid.first_visiblerow) * grid.RowHeight; + int max_rows = visibleHeight / grid.RowHeight; + + if (max_rows > total_rows) { + max_rows = total_rows; + } + + if (rows_height > cells_area.Height) { + rv = max_rows; + } else { + rv = total_rows; + } + + CalcRowsHeaders (rv); // Height depends on num of visible rows + + if (rv + grid.first_visiblerow > total_rows) + rv = total_rows - grid.first_visiblerow; + + return rv; + } + public void UpdateVisibleColumn () { if (grid.CurrentTableStyle.GridColumnStyles.Count == 0) { @@ -341,30 +428,20 @@ public void UpdateVisibleRowCount () { int max_height = cells_area.Height; + int max_rows = max_height / grid.RowHeight; + int total_rows = grid.RowsCount; if (grid.ShowEditRow && grid.RowsCount > 0) { total_rows++; } - int rows_height = (total_rows - grid.first_visiblerow) * grid.RowHeight; - int max_rows = max_height / grid.RowHeight; - if (max_rows > total_rows) { max_rows = total_rows; } - if (rows_height > cells_area.Height) { - grid.visiblerow_count = max_rows; - } else { - grid.visiblerow_count = total_rows; - } + grid.visiblerow_count = GetVisibleRowCount (max_height); - CalcRowsHeaders (); // Height depends on num of visible rows - - if (grid.visiblerow_count + grid.first_visiblerow > total_rows) - grid.visiblerow_count = total_rows - grid.first_visiblerow; - if (grid.visiblerow_count < max_rows) { grid.visiblerow_count = max_rows; grid.first_visiblerow = total_rows - max_rows; @@ -468,8 +545,11 @@ Rectangle rect_row = new Rectangle (); + int row_width = CalcAllColumnsWidth (); + if (row_width > cells_area.Width) + row_width = cells_area.Width; rect_row.X = cells_area.X; - rect_row.Width = cells_area.Width; + rect_row.Width = row_width; rect_row.Height = grid.RowHeight; rect_row.Y = cells_area.Y + ((row - grid.FirstVisibleRow) * grid.RowHeight); grid.Invalidate (rect_row); @@ -504,47 +584,25 @@ rect_col.Height = cells_area.Height; grid.Invalidate (rect_col); } - - // Return true if the scrollbar is needed - public bool SetUpHorizontalScrollBar () + + void SetUpHorizontalScrollBar (out int maximum) { - int width_all = CalcAllColumnsWidth (); + maximum = CalcAllColumnsWidth (); - if (width_all <= cells_area.Width) { - grid.horiz_scrollbar.Visible = false; - grid.Controls.Remove (grid.horiz_scrollbar); - return false; - } - grid.horiz_scrollbar.Location = new Point (grid.ClientRectangle.X, grid.ClientRectangle.Y + grid.ClientRectangle.Height - grid.horiz_scrollbar.Height); grid.horiz_scrollbar.Size = new Size (grid.ClientRectangle.Width, grid.horiz_scrollbar.Height); - grid.horiz_scrollbar.Maximum = width_all;// - cells_area.Width; grid.horiz_scrollbar.LargeChange = cells_area.Width; - grid.Controls.Add (grid.horiz_scrollbar); - grid.horiz_scrollbar.Visible = true; - return true; } - // Return true if the scrollbar is needed - public bool SetUpVerticalScrollBar () + + void SetUpVerticalScrollBar (out int height, out int maximum) { - int y, height; - int allrows = grid.RowsCount; - - if (grid.ShowEditRow && grid.RowsCount > 0) { - allrows++; - } + int y; - if (grid.visiblerow_count == allrows) { - grid.vert_scrollbar.Visible = false; - grid.Controls.Remove (grid.vert_scrollbar); - return false; - } - if (grid.caption_visible) { y = grid.ClientRectangle.Y + caption_area.Height; height = grid.ClientRectangle.Height - caption_area.Height; @@ -559,17 +617,13 @@ grid.vert_scrollbar.Size = new Size (grid.vert_scrollbar.Width, height); - grid.vert_scrollbar.Maximum = grid.RowsCount; + maximum = grid.RowsCount; if (grid.ShowEditRow && grid.RowsCount > 0) { - grid.vert_scrollbar.Maximum++; + maximum++; } grid.vert_scrollbar.LargeChange = VLargeChange; - - grid.Controls.Add (grid.vert_scrollbar); - grid.vert_scrollbar.Visible = true; - return true; } #endregion // Public Instance Methods @@ -594,7 +648,11 @@ } } - public int ColumnsHeaderHeight { + bool ShowingColumnHeaders { + get { return grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0; } + } + + int ColumnsHeaderHeight { get { return grid.CurrentTableStyle.HeaderFont.Height + 6; }
_______________________________________________ Mono-winforms-list maillist - Mono-winforms-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-winforms-list