Windows 2008 R2Win64Windows 2008Windows VistaWindows 7Windows 2003Win32Visual Studio 2005Windows 2000高级Windows XP.NET 2.0C# 2.0中级Visual StudioWindows.NETC#
简单的三态树状视图





5.00/5 (1投票)
这是“简单的三态树状视图”的替代方案
引言
我遇到了原始代码的太多问题,决定重写大部分代码。
Using the Code
在更改后“刷新”treeview
不再需要(但仍然有效)。 如果使用函数“SetState
”设置其状态,新添加节点的复选框将自动显示。 或者,您可以使用函数“InitializeCBImages
”(对于所有节点)或“InitializeStates
”(对于特定的节点集合)以其初始状态显示checkbox
。
BeforeCheck
和AfterCheck
现在仅对由SetState
函数或鼠标单击修改的节点触发。 其他更改(父级和子级状态)会触发一个新事件:AutoCheck
。
这是类的新代码
public class TriStateCBTreeView : TreeView {
// ~~~ fields ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ImageList _ilStateImages;
bool _bUseTriState;
bool _bCheckBoxesVisible;
bool _bPreventCheckEvent;
// ~~~ constructor ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// <summary>
/// Creates a new instance
/// of this control.
/// </summary>
public TriStateCBTreeView()
: base() {
_ilStateImages = new ImageList(); // first we create
// our state image
CheckBoxState cbsState = CheckBoxState.UncheckedNormal; // list and pre-init
// check state.
for (int i = 0; i <= 2; i++) { // let's iterate each tri-state
Bitmap bmpCheckBox = new Bitmap(16, 16); // creating a new
// checkbox bitmap
Graphics gfxCheckBox = Graphics.FromImage(bmpCheckBox); // and getting
// graphics object from
switch (i) // it...
{
case 0: cbsState = CheckBoxState.UncheckedNormal; break;
case 1: cbsState = CheckBoxState.CheckedNormal; break;
case 2: cbsState = CheckBoxState.MixedNormal; break;
}
CheckBoxRenderer.DrawCheckBox(gfxCheckBox, new Point(2, 2), cbsState); // ...rendering
gfxCheckBox.Save(); // the checkbox and
_ilStateImages.Images.Add(bmpCheckBox); // adding to state image list.
}
_bUseTriState = true;
}
// ~~~ properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// <summary>
/// Gets or sets to display
/// checkboxes in the tree
/// view.
/// </summary>
[Category("Appearance")]
[Description("Sets tree view to display checkboxes or not.")]
[DefaultValue(false)]
public new bool CheckBoxes {
get { return _bCheckBoxesVisible; }
set {
_bCheckBoxesVisible = value;
base.CheckBoxes = _bCheckBoxesVisible;
this.StateImageList = _bCheckBoxesVisible ? _ilStateImages : null;
}
}
[Browsable(false)]
public new ImageList StateImageList {
get { return base.StateImageList; }
set { base.StateImageList = value; }
}
/// <summary>
/// Gets or sets to support
/// tri-state in the checkboxes
/// or not.
/// </summary>
[Category("Appearance")]
[Description("Sets tree view to use tri-state checkboxes or not.")]
[DefaultValue(true)]
public bool CheckBoxesTriState {
get { return _bUseTriState; }
set { _bUseTriState = value; }
}
// ~~~ functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// <summary>
/// Changes nodes state.
/// </summary>
protected void SetParentState(TreeNode tNode) {
TreeNode ParentNode = tNode.Parent;
if (ParentNode != null) {
try {
if (tNode.StateImageIndex == 2) { // if the current node has
// a mixed state
ParentNode.Checked = false; // then its parent is set to
// the same state
ParentNode.StateImageIndex = 2;
return;
}
int CheckedCount = 0;
int UnCheckedCount = 0;
foreach (TreeNode ChildNode in ParentNode.Nodes) { // we count the checked
// and unchecked states
if (ChildNode.StateImageIndex <= 0) // of each node at
// the current level
UnCheckedCount++;
else if (ChildNode.StateImageIndex == 1)
CheckedCount++;
if (ChildNode.StateImageIndex == 2 || // if one node has a
// mixed state or there
(CheckedCount > 0 && UnCheckedCount > 0)) { // are checked and
// unchecked states, then
ParentNode.Checked = false; // the parent node is set to
// a mixed state
ParentNode.StateImageIndex = 2;
return;
}
}
if (UnCheckedCount > 0) {
ParentNode.Checked = false;
ParentNode.StateImageIndex = 0;
}
else if (CheckedCount > 0) {
ParentNode.Checked = true;
ParentNode.StateImageIndex = 1;
}
}
finally {
SetParentState(ParentNode); // the parent node becomes
// the current node
}
}
}
protected void SetChildrenState(TreeNode tNode, bool RootNode) {
if (!RootNode) {
tNode.Checked = (tNode.Parent.StateImageIndex == 1); // the child state
// is inherited
tNode.StateImageIndex = tNode.Parent.StateImageIndex; // from the parent state
}
foreach (TreeNode ChildNode in tNode.Nodes)
SetChildrenState(ChildNode, false);
}
public void SetState(TreeNode tNode, int NewState) {
if (NewState < 0 || NewState > 2)
NewState = 0;
tNode.Checked = (NewState == 1);
if (tNode.Checked == (NewState == 1)) { // we verify if the checked
// state has
tNode.StateImageIndex = NewState; // not been cancelled in a
// BeforeCheck event
_bPreventCheckEvent = true;
SetParentState(tNode);
SetChildrenState(tNode, true);
_bPreventCheckEvent = false;
}
}
/// <summary>
/// Initializes the nodes state.
/// </summary>
public void InitializeStates(TreeNodeCollection tNodes) {
foreach (TreeNode tnCurrent in tNodes) { // set tree state image
if (tnCurrent.StateImageIndex == -1) { // to each child node...
_bPreventCheckEvent = true;
if (tnCurrent.Parent != null) {
tnCurrent.Checked = tnCurrent.Parent.Checked;
tnCurrent.StateImageIndex = tnCurrent.Parent.StateImageIndex;
}
else
tnCurrent.StateImageIndex = tnCurrent.Checked ? 1 : 0;
_bPreventCheckEvent = false;
}
InitializeStates(tnCurrent.Nodes);
}
}
public void InitializeCBImages() {
if (!CheckBoxes) // nothing to do here if
return; // checkboxes are hidden.
base.CheckBoxes = false; // hide normal checkboxes...
InitializeStates(this.Nodes);
}
/// <summary>
/// Refreshes this control.
/// </summary>
public override void Refresh() {
base.Refresh();
InitializeCBImages();
}
// ~~~ events ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected override void OnLayout(LayoutEventArgs levent) {
base.OnLayout(levent);
InitializeCBImages();
}
protected override void OnAfterExpand(TreeViewEventArgs e) {
if (CheckBoxes)
InitializeStates(e.Node.Nodes);
base.OnAfterExpand(e);
}
public delegate void AutoCheckEventHandler(object sender, TreeViewEventArgs e);
public event AutoCheckEventHandler AutoCheck;
protected override void OnBeforeCheck(TreeViewCancelEventArgs e) {
if (_bPreventCheckEvent)
return;
base.OnBeforeCheck(e);
}
protected override void OnAfterCheck(TreeViewEventArgs e) {
if (_bPreventCheckEvent) {
if (AutoCheck != null)
AutoCheck(this, e);
return;
}
base.OnAfterCheck(e);
}
protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e) {
base.OnNodeMouseClick(e);
int iSpacing = ImageList == null ? 0 : 20; // if user clicked area
if (e.X > e.Node.Bounds.Left - iSpacing || // *not* used by the state
e.X < e.Node.Bounds.Left - (iSpacing + 14) || // image we can leave here.
e.Button != MouseButtons.Left) {
return;
}
SetState(e.Node, e.Node.Checked ? 0 : 1);
}
}
历史
- 2012/03/05:首次提交