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);
}
}
}
}