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

Reply via email to