internal protected virtual void UnSiteNode(TreeDataGridViewRow node) { if (node.IsSited || node.IsRoot) { // remove child rows first foreach (TreeDataGridViewRow childNode in node.Nodes) { this.UnSiteNode(childNode); childNode.Grid = null; childNode.Owner = null; childNode.Index = -1; } // now remove this row except for the root if (!node.IsRoot) { base.Rows.Remove(node); // Row isn't sited in the grid anymore after remove. Note that we cannot // Use the RowRemoved event since we cannot map from the row index to // the index of the expandable row/node. node.UnSited(); } } }
protected override void OnMouseDown(DataGridViewCellMouseEventArgs e) { if (e.Location.X > InheritedStyle.Padding.Left) { base.OnMouseDown(e); } else { // Expand the node //TODO: Calculate more precise location TreeDataGridViewRow node = OwningNode; if (node != null) { node.Grid._inExpandCollapseMouseCapture = true; if (node.IsExpanded) { node.Collapse(); } else { node.Expand(); } } } }
private void UpdateChildNodes(TreeDataGridViewRow node) { if (node.HasChildren) { foreach (TreeDataGridViewRow childNode in node.Nodes) { childNode.Grid = node.Grid; UpdateChildNodes(childNode); } } }
protected override void OnMouseUp(DataGridViewCellMouseEventArgs e) { base.OnMouseUp(e); TreeDataGridViewRow node = OwningNode; if (node != null) { node.Grid._inExpandCollapseMouseCapture = false; } }
internal protected virtual void RemoveChildNode(TreeDataGridViewRow node) { if ((IsRoot || _isSited) && IsExpanded) { //We only unsite out child node if we are sited and expanded. Grid.UnSiteNode(node); } node.Grid = null; node.Owner = null; node.Index = -1; node._parent = null; }
internal protected virtual void SiteNode(TreeDataGridViewRow node, int index) { if (index < base.Rows.Count) { base.Rows.Insert(index, node); } else { // for the last item. base.Rows.Add(node); } }
/// <summary> /// /// </summary> public TreeDataGridView() { _groups = new DataGridViewGroupCollection(this); // Control when edit occurs because edit mode shouldn't start when expanding/collapsing //this.EditMode = DataGridViewEditMode.EditProgrammatically; RowTemplate = new TreeDataGridViewRow(); // This sample does not support adding or deleting rows by the user. AllowUserToAddRows = false; AllowUserToDeleteRows = false; _root = new TreeDataGridViewRow(this); _root.IsRoot = true; // Ensures that all rows are added unshared by listening to the CollectionChanged event. base.Rows.CollectionChanged += delegate {}; }
internal protected virtual void AddChildNode(TreeDataGridViewRow node) { node._parent = this; node.Grid = Grid; // ensure that all children of this node has their grid set if (Grid != null) { UpdateChildNodes(node); } if ((_isSited || IsRoot) && IsExpanded && !node._isSited) { Grid.SiteNode(node); } }
internal protected virtual void InsertChildNode(int index, TreeDataGridViewRow node) { node._parent = this; node.Grid = Grid; // ensure that all children of this node has their grid set if (Grid != null) { UpdateChildNodes(node); } //TODO: do we need to use index parameter? if ((_isSited || IsRoot) && IsExpanded) { Grid.SiteNode(node); } }
internal protected virtual bool ExpandNode(TreeDataGridViewRow node) { if (!node.IsExpanded || this._virtualNodes) { ExpandingEventArgs exp = new ExpandingEventArgs(node); this.OnNodeExpanding(exp); if (!exp.Cancel) { this.LockVerticalScrollBarUpdate(true); this.SuspendLayout(); _inExpandCollapse = true; node.IsExpanded = true; //TODO Convert this to a InsertRange foreach (TreeDataGridViewRow childNode in node.Nodes) { Debug.Assert(childNode.RowIndex == -1, "Row is already in the grid."); this.SiteNode(childNode); //this.BaseRows.Insert(rowIndex + 1, childRow); //TODO : remove -- just a test. //childNode.Cells[0].Value = "child"; } ExpandedEventArgs exped = new ExpandedEventArgs(node); this.OnNodeExpanded(exped); //TODO: Convert this to a specific NodeCell property _inExpandCollapse = false; this.LockVerticalScrollBarUpdate(false); this.ResumeLayout(true); this.InvalidateCell(node.Cells[0]); } return(!exp.Cancel); } else { // row is already expanded, so we didn't do anything. return(false); } }
//protected override void OnCellDoubleClick(DataGridViewCellEventArgs e) //{ // if (e.RowIndex >= 0) // { // TreeDataGridViewRow row = base.Rows[e.RowIndex] as TreeDataGridViewRow; // if (row != null && row.IsGroupRow) // { // row.Grid._inExpandCollapseMouseCapture = true; // if (row.IsExpanded) // CollapseNode(row); // else // ExpandNode(row); // } // } // base.OnCellClick(e); //} protected override void OnCellClick(DataGridViewCellEventArgs e) { if (e.RowIndex >= 0) { TreeDataGridViewRow row = base.Rows[e.RowIndex] as TreeDataGridViewRow; if (row != null && row.IsGroupRow) { row.Grid._inExpandCollapseMouseCapture = true; if (row.IsExpanded) { CollapseNode(row); } else { ExpandNode(row); } } } base.OnCellClick(e); }
public override object Clone() { TreeDataGridViewRow r = (TreeDataGridViewRow)base.Clone(); if (r == null) { return(null); } r._level = _level; r.Grid = Grid; r._parent = Parent; r._imageIndex = _imageIndex; if (r._imageIndex == -1) { r.Image = Image; } r.IsExpanded = IsExpanded; return(r); }
internal protected virtual bool CollapseNode(TreeDataGridViewRow node) { if (node.IsExpanded) { CollapsingEventArgs exp = new CollapsingEventArgs(node); this.OnNodeCollapsing(exp); if (!exp.Cancel) { this.LockVerticalScrollBarUpdate(true); this.SuspendLayout(); _inExpandCollapse = true; node.IsExpanded = false; foreach (TreeDataGridViewRow childNode in node.Nodes) { Debug.Assert(childNode.RowIndex != -1, "Row is NOT in the grid."); this.UnSiteNode(childNode); } CollapsedEventArgs exped = new CollapsedEventArgs(node); this.OnNodeCollapsed(exped); //TODO: Convert this to a specific NodeCell property _inExpandCollapse = false; this.LockVerticalScrollBarUpdate(false); this.ResumeLayout(true); this.InvalidateCell(node.Cells[0]); } return(!exp.Cancel); } else { // row isn't expanded, so we didn't do anything. return(false); } }
internal protected virtual void SiteNode(TreeDataGridViewRow node) { //TODO: Raise exception if parent node is not the root or is not sited. int rowIndex = -1; TreeDataGridViewRow currentRow; node.Grid = this; if (node.Parent != null && node.Parent.IsRoot == false) { // row is a child Debug.Assert(node.Parent != null && node.Parent.IsExpanded == true); if (node.Index > 0) { currentRow = node.Parent.Nodes[node.Index - 1]; } else { currentRow = node.Parent; } } else { // row is being added to the root if (node.Index > 0) { currentRow = node.Parent.Nodes[node.Index - 1]; } else { currentRow = null; } } if (currentRow != null) { while (currentRow.Level >= node.Level) { if (currentRow.RowIndex < base.Rows.Count - 1) { currentRow = base.Rows[currentRow.RowIndex + 1] as TreeDataGridViewRow; Debug.Assert(currentRow != null); } else { // no more rows, site this node at the end. break; } } if (currentRow == node.Parent) { rowIndex = currentRow.RowIndex + 1; } else if (currentRow.Level < node.Level) { rowIndex = currentRow.RowIndex; } else { rowIndex = currentRow.RowIndex + 1; } } else { rowIndex = 0; } Debug.Assert(rowIndex != -1); this.SiteNode(node, rowIndex); Debug.Assert(node.IsSited); if (node.IsExpanded) { // add all child rows to display foreach (TreeDataGridViewRow childNode in node.Nodes) { //TODO: could use the more efficient SiteRow with index. this.SiteNode(childNode); } } }
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) { TreeDataGridViewRow node = OwningNode; if (node == null) { return; } Image image = node.Image; if (_imageHeight == 0 && image != null) { 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 + GlyphMargin, cellBounds.Y, IndentWidth, cellBounds.Height - 1); int glyphHalf = glyphRect.Width / 2; //TODO: This painting code needs to be rehashed to be cleaner int level = 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 + _glyphWidth, cellBounds.Y + _imageHeightOffset); } else { pp = new Point(glyphRect.X + _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 (node.Grid.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 TreeDataGridViewRow previousNode = node.Parent; int horizontalStop = (glyphRect.X + 4) - IndentWidth; 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 - IndentWidth; } } } } if (node.HasChildren || node.Grid.VirtualNodes) { // Paint node glyphs if (node.IsExpanded) { node.Grid.rOpen.DrawBackground(graphics, new Rectangle(glyphRect.X, glyphRect.Y + (glyphRect.Height / 2) - 4, 10, 10)); } else { node.Grid.rClosed.DrawBackground(graphics, new Rectangle(glyphRect.X, glyphRect.Y + (glyphRect.Height / 2) - 4, 10, 10)); } } }