protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { if (!paddingok) { PrepareDraw(); cellStyle.Padding = Style.Padding; } DataGridViewRow xrow = this.DataGridView.Rows[rowIndex]; if (!(xrow is TreeGridRow)) { return; } TreeGridRow node = (TreeGridRow)xrow; if (node == null) { return; } Image image = node.Image; if (this._imageHeight == 0 && image != null) { this.UpdateStyle(); } // paint the cell normally base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); // TODO: Indent width needs to take image size into account Rectangle glyphRect = new Rectangle(cellBounds.X + this.GlyphMargin, cellBounds.Y, INDENT_WIDTH, cellBounds.Height - 1); int glyphHalf = glyphRect.Width / 2; //TODO: This painting code needs to be rehashed to be cleaner int level = this.Level; //TODO: Rehash this to take different Imagelayouts into account. This will speed up drawing // for images of the same size (ImageLayout.None) if (image != null) { Point pp; if (_imageHeight > cellBounds.Height) { pp = new Point(glyphRect.X + this.glyphWidth, cellBounds.Y + _imageHeightOffset); } else { pp = new Point(glyphRect.X + this.glyphWidth, (cellBounds.Height / 2 - _imageHeight / 2) + cellBounds.Y); } // Graphics container to push/pop changes. This enables us to set clipping when painting // the cell's image -- keeps it from bleeding outsize of cells. System.Drawing.Drawing2D.GraphicsContainer gc = graphics.BeginContainer(); { graphics.SetClip(cellBounds); graphics.DrawImageUnscaled(image, pp); } graphics.EndContainer(gc); } // Paint tree lines if (((TreeGridAdvanced)(DataGridView)).ShowLines) { using (Pen linePen = new Pen(SystemBrushes.ControlDark, 1.0f)) { linePen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; bool isLastSibling = node.IsLastSibling; bool isFirstSibling = node.IsFirstSibling; if (node.Level == 1) { // the Root nodes display their lines differently if (isFirstSibling && isLastSibling) { // only node, both first and last. Just draw horizontal line graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2); } else if (isLastSibling) { // last sibling doesn't draw the line extended below. Paint horizontal then vertical graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2); graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2); } else if (isFirstSibling) { // first sibling doesn't draw the line extended above. Paint horizontal then vertical graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2); graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.X + 4, cellBounds.Bottom); } else { // normal drawing draws extended from top to bottom. Paint horizontal then vertical graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2); graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Bottom); } } else { if (isLastSibling) { // last sibling doesn't draw the line extended below. Paint horizontal then vertical graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2); graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2); } else { // normal drawing draws extended from top to bottom. Paint horizontal then vertical graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2); graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Bottom); } // paint lines of previous levels to the root TreeGridRow previousNode = node.Parent; int horizontalStop = (glyphRect.X + 4) - INDENT_WIDTH; if (previousNode != null) { while (!previousNode.IsRoot) { if (previousNode.HasChildren && !previousNode.IsLastSibling) { // paint vertical line graphics.DrawLine(linePen, horizontalStop, cellBounds.Top, horizontalStop, cellBounds.Bottom); } previousNode = previousNode.Parent; horizontalStop = horizontalStop - INDENT_WIDTH; if (previousNode == null) { break; } } } } } } if (node.HasChildren) { TreeGridAdvanced _grid = (TreeGridAdvanced)DataGridView; // Paint node glyphs if (node.Node.Expanded) { if (_grid.themesenabled) { try { if (_grid.rOpen == null) { _grid.rOpen = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Opened); _grid.treeboxwidth = System.Convert.ToInt32(WinFormsGraphics.DPIScale * 10); } _grid.rOpen.DrawBackground(graphics, new Rectangle(glyphRect.X, glyphRect.Y + (glyphRect.Height / 2) - 4, _grid.treeboxwidth, _grid.treeboxwidth)); /* * Pen npen = Pens.Black; * int recwidth = 8; * int margin = 2; * int leftmargin = -recwidth / 2 - 2; * int topmargin = 0; * Rectangle nrect = new Rectangle(leftmargin + glyphRect.X + glyphRect.Width / 2 - recwidth / 2, * topmargin + glyphRect.Y + glyphRect.Height / 2 - recwidth / 2, * recwidth, * recwidth); * graphics.DrawLine(npen, new Point(nrect.X + margin, nrect.Top + recwidth / 2), * new Point(nrect.X + recwidth - margin, nrect.Top + recwidth / 2));*/ } catch { _grid.themesenabled = false; } } if (!_grid.themesenabled) { Pen npen = Pens.Black; int recwidth = 8; int margin = 2; int leftmargin = -recwidth / 2 - 2; int topmargin = 0; Rectangle nrect = new Rectangle(leftmargin + glyphRect.X + glyphRect.Width / 2 - recwidth / 2, topmargin + glyphRect.Y + glyphRect.Height / 2 - recwidth / 2, recwidth, recwidth); using (Brush nbrush = new SolidBrush(cellStyle.BackColor)) { graphics.FillRectangle(nbrush, nrect); graphics.DrawRectangle(npen, nrect); graphics.DrawLine(npen, new Point(nrect.X + margin, nrect.Top + recwidth / 2), new Point(nrect.X + recwidth - margin, nrect.Top + recwidth / 2)); } } } else { if (_grid.themesenabled) { try { if (_grid.rClosed == null) { _grid.rClosed = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Closed); _grid.treeboxwidth = System.Convert.ToInt32(WinFormsGraphics.DPIScale * 10); } // node._grid.rClosed = new VisualStyleRenderer("Explorer::TreeView",2,1); _grid.rClosed.DrawBackground(graphics, new Rectangle(glyphRect.X, glyphRect.Y + (glyphRect.Height / 2) - 4, _grid.treeboxwidth, _grid.treeboxwidth)); } catch { _grid.themesenabled = false; } } if (!_grid.themesenabled) { Pen npen = Pens.Black; int recwidth = 8; int margin = 2; int leftmargin = -recwidth / 2 - 2; int topmargin = 0; using (Brush nbrush = new SolidBrush(cellStyle.BackColor)) { Rectangle nrect = new Rectangle(leftmargin + glyphRect.X + glyphRect.Width / 2 - recwidth / 2, topmargin + glyphRect.Y + glyphRect.Height / 2 - recwidth / 2, recwidth, recwidth); graphics.FillRectangle(nbrush, nrect); graphics.DrawRectangle(npen, nrect); graphics.DrawLine(npen, new Point(nrect.X + margin, nrect.Top + recwidth / 2), new Point(nrect.X + recwidth - margin, nrect.Top + recwidth / 2)); graphics.DrawLine(npen, new Point(nrect.X + recwidth / 2, nrect.Top + margin), new Point(nrect.X + recwidth / 2, nrect.Top + recwidth - margin)); } } } } }
// Performance bottleneck internal protected virtual void UpdateStyle() { if (this.RowIndex < 0) { return; } if (paddingok) { return; } int level = this.Level; Size preferredSize; // This line consumes lot of memory Graphics g = ((TreeGridAdvanced)DataGridView).GetGraphics(); // Graphics g = ((TreeGridView)this.DataGridView).GetGraphics(); preferredSize = this.GetPreferredSize(g, this.InheritedStyle, this.RowIndex, new Size(0, 0)); //preferredSize = new Size(20, 21); Image image = ((TreeGridRow)DataGridView.Rows[RowIndex]).Image; if (image != null) { // calculate image size _imageWidth = image.Width + 2; _imageHeight = image.Height + 2; } else { _imageWidth = glyphWidth; _imageHeight = 0; } Padding p = new Padding(); // TODO: Make this cleaner if (preferredSize.Height < _imageHeight) { int leftpad = p.Left + (level * INDENT_WIDTH) + _imageWidth + INDENT_MARGIN; // Performance bottleneck changing padding takes lot of time TreeGridAdvanced _grid = (TreeGridAdvanced)this.DataGridView; if (_grid.paddings_list.IndexOfKey(leftpad) >= 0) { this.Style = _grid.paddings_list.Values[leftpad]; } else { Padding npad = new Padding(leftpad, p.Top + (_imageHeight / 2), p.Right, p.Bottom + (_imageHeight / 2)); this.Style.Padding = npad; _grid.paddings_list.Add(leftpad, this.Style); } _imageHeightOffset = 2;// (_imageHeight - preferredSize.Height) / 2; } else { int leftpad = p.Left + (level * INDENT_WIDTH) + _imageWidth + INDENT_MARGIN; Padding oldpad = this.Style.Padding; // if ((oldpad.Left != npad.Left) || (oldpad.Top != npad.Top) || (oldpad.Right != npad.Right) || (oldpad.Bottom != npad.Bottom)) if (oldpad.Left != leftpad) { // Performance bottleneck changing padding takes lot of time TreeGridAdvanced _grid = (TreeGridAdvanced)this.DataGridView; if (_grid.paddings_list.IndexOfKey(leftpad) >= 0) { this.Style = _grid.paddings_list[leftpad]; } else { Padding npad = new Padding(leftpad, p.Top, p.Right, p.Bottom); this.Style.Padding = npad; _grid.paddings_list.Add(leftpad, this.Style); } } } calculatedLeftPadding = ((level - 1) * glyphWidth) + _imageWidth + INDENT_MARGIN; paddingok = true; }