using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; namespace GeoSigmaViewer { public static class ClassExtensions { /// /// 选中状态:0-未选中, 1-选中,2-部分选中。 /// /// /// public static int GetCheckStatus(this TreeNode node) { return node.StateImageIndex; } public static void SetCheckStatus(this TreeNode node, int status) { node.StateImageIndex=status; } } public partial class TriStateTreeView : TreeView { private const int STATE_UNCHECKED = 0; //unchecked state private const int STATE_CHECKED = 1; //checked state private const int STATE_MIXED = 2; //mixed state (indeterminate) private bool isMouseOnStatus = false; //create a new ThreeStateTreeView public int ID { get; set; } public TriStateTreeView() : base() { System.Security.Cryptography.RNGCryptoServiceProvider csp = new System.Security.Cryptography.RNGCryptoServiceProvider(); byte[] byteCsp = new byte[10]; csp.GetBytes(byteCsp); ID=BitConverter.ToInt32(byteCsp, 0); } protected override void OnBeforeCollapse(TreeViewCancelEventArgs e) { if (isMouseOnStatus) e.Cancel=true; } protected override void OnBeforeExpand(TreeViewCancelEventArgs e) { if (isMouseOnStatus) e.Cancel=true; } /// /// 重新设置所有节点的选中状态 /// public void UpdateView() { this.SetNodesState(this.Nodes); } public void SelectAll() { this.SetNodesState(this.Nodes, STATE_CHECKED); } public void UnselectAll() { this.SetNodesState(this.Nodes, STATE_UNCHECKED); } public void AntiSelect() { this.SetNodesToAntiState(this.Nodes); } //returns a value indicating if all children are checked public static bool IsAllChildrenChecked(TreeNode parent) { return IsAllChildrenSame(parent, STATE_CHECKED); } //returns a value indicating if all children are unchecked public static bool IsAllChildrenUnchecked(TreeNode parent) { return IsAllChildrenSame(parent, STATE_UNCHECKED); } //initialize all nodes state image private void SetNodesState(TreeNodeCollection nodes, int state) { foreach (TreeNode node in nodes) { node.StateImageIndex=state; if (state==STATE_CHECKED) { node.Checked=true; } else { node.Checked=false; } if (node.Nodes.Count!=0) { SetNodesState(node.Nodes, state); } } } private void UpdateStatus(TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { UpdateParent(node); if (node.Nodes.Count!=0) { UpdateStatus(node.Nodes); } } } private void SetNodesState(TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { //if (node.Checked) //{ // node.StateImageIndex=STATE_CHECKED; //} //else //{ // node.StateImageIndex=STATE_UNCHECKED; //} UpdateParent(node); if (node.Nodes.Count!=0) { SetNodesState(node.Nodes); } } } private void SetNodesToAntiState(TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { if (node.GetCheckStatus()==STATE_CHECKED) { node.SetCheckStatus(STATE_UNCHECKED); //node.Checked=true; } else if (node.StateImageIndex==STATE_UNCHECKED) { node.StateImageIndex=STATE_CHECKED; //node.Checked=false; } if (node.Nodes.Count!=0) { SetNodesToAntiState(node.Nodes); } } } //update children state image with the parent value private void UpdateChildren(TreeNode parent) { int state = parent.StateImageIndex; foreach (TreeNode node in parent.Nodes) { node.StateImageIndex=state; if (node.Nodes.Count!=0) { UpdateChildren(node); } } } //update parent state image base on the children state private void UpdateParent(TreeNode child) { TreeNode parent = child.Parent; if (parent==null) { return; } if (child.StateImageIndex==STATE_MIXED) { parent.StateImageIndex=STATE_MIXED; } else if (IsAllChildrenChecked(parent)) { parent.StateImageIndex=STATE_CHECKED; } else if (IsAllChildrenUnchecked(parent)) { parent.StateImageIndex=STATE_UNCHECKED; } else { parent.StateImageIndex=STATE_MIXED; } UpdateParent(parent); } //returns a value indicating if all children are in the same state private static bool IsAllChildrenSame(TreeNode parent, int state) { foreach (TreeNode node in parent.Nodes) { if (node.StateImageIndex!=state) { return false; } if (node.Nodes.Count!=0&&!IsAllChildrenSame(node, state)) { return false; } } return true; } //build the checked, unchecked and indeterminate images private static Image GetStateImage(CheckBoxState state, Size imageSize) { Bitmap bmp = new Bitmap(16, 16); using (Graphics g = Graphics.FromImage(bmp)) { Point pt = new Point((16-imageSize.Width)/2, (16-imageSize.Height)/2); CheckBoxRenderer.DrawCheckBox(g, pt, state); } return bmp; } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); this.StateImageList=new ImageList(); using (Graphics g = base.CreateGraphics()) { Size glyphSize = CheckBoxRenderer.GetGlyphSize(g, CheckBoxState.UncheckedNormal); this.StateImageList.Images.Add(GetStateImage(CheckBoxState.UncheckedNormal, glyphSize)); this.StateImageList.Images.Add(GetStateImage(CheckBoxState.CheckedNormal, glyphSize)); this.StateImageList.Images.Add(GetStateImage(CheckBoxState.MixedNormal, glyphSize)); this.StateImageList.Images.Add(GetStateImage(CheckBoxState.UncheckedDisabled, glyphSize)); this.StateImageList.Images.Add(GetStateImage(CheckBoxState.CheckedDisabled, glyphSize)); this.StateImageList.Images.Add(GetStateImage(CheckBoxState.MixedDisabled, glyphSize)); } } protected override void OnMouseDown(MouseEventArgs e) { MouseEventArgs ee = e as MouseEventArgs; if (ee.Button==MouseButtons.Left) { TreeViewHitTestInfo info = base.HitTest(ee.Location); if (info.Node!=null&&info.Location==TreeViewHitTestLocations.StateImage) { isMouseOnStatus=true; TreeNode node = info.Node; switch (node.StateImageIndex) { case STATE_UNCHECKED: case STATE_MIXED: node.StateImageIndex=STATE_CHECKED; break; case STATE_CHECKED: node.StateImageIndex=STATE_UNCHECKED; break; } UpdateChildren(node); UpdateParent(node); return; } else { isMouseOnStatus=false; } } base.OnMouseDown(e); } protected override void OnClick(EventArgs e) { base.OnClick(e); } protected override void OnMouseDoubleClick(MouseEventArgs e) { base.OnMouseDoubleClick(e); } protected override void OnMouseClick(MouseEventArgs e) { base.OnMouseClick(e); } //check if user press the space key protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); if (e.KeyCode==Keys.Space) { if (base.SelectedNode!=null) { TreeNode node = base.SelectedNode; switch (node.StateImageIndex) { case STATE_UNCHECKED: case STATE_MIXED: node.StateImageIndex=STATE_CHECKED; break; case STATE_CHECKED: node.StateImageIndex=STATE_UNCHECKED; break; } UpdateChildren(node); UpdateParent(node); } } } //swap between enabled and disabled images protected override void OnEnabledChanged(EventArgs e) { base.OnEnabledChanged(e); for (int i = 0; i<3; i++) { Image img = this.StateImageList.Images[0]; this.StateImageList.Images.RemoveAt(0); this.StateImageList.Images.Add(img); } } } }