|

Introduction
The TreeView with checkboxes implemented in the .NET Framework (property TreeView.CheckBoxes = True) allows only 2 states (TreeNode.Checked = True or False). The implementation presented here:
-
Allows to use the state image list that is not directly available in the .NET Framework implementation.
-
Allows 3 states (4 including the state none) for a node: checked, unchecked, indeterminate.
-
Implements the logic to set the proper state of parents and children when the user changes the state of a node: it selects all children when the parent is selected, and set the state of the parent(s) to checked, unchecked or indeterminate depending on the number of children selected (all, none, etc.).
I have seen other TriState implementations in the C# section but they use the image list, not the state image list, for checkboxes and therefore doesn't allow to have icons and checkboxes for nodes at the same time.
Using the code
I have derived a TriStateTreeView class from the base TreeView class. This new class needs an additional state image list with icons for the 4 states: none, unchecked, checked, indeterminate (in this order).
The state image list is passed in the constructor:
m_ctlTriStateTreeView = New TriStateTreeView(Me.StateImageList)
A new enum type is provided to specify the state of a node:
Friend Enum CheckBoxState
None = 0
Unchecked = 1
Checked = 2
Indeterminate = 3
End Enum
To add nodes to the treeview, you can use the AddTreeNode helper function of the TriStateTreeView class: objTreeNodeRoot = m_ctlTriStateTreeView.AddTreeNode( _
m_ctlTriStateTreeView.Nodes, "My Computer", _
IMG_COMPUTER, CheckBoxState.None)
To get the state of a node you use the GetTreeNodeState function of the TriStateTreeView class: Friend Function GetTreeNodeState(ByVal objTreeNode As _
TreeNode) As CheckBoxState
To set the state of a node you use the SetTreeNodeState function of the TriStateTreeView class: Friend Sub SetTreeNodeState(ByVal objTreeNode As _
TreeNode, ByVal eCheckBoxState As CheckBoxState)
Points of Interest
The code intercepts the MouseUp and KeyUp events to change the state of a node (when clicking with the mouse or pressing space). Also, the code prevents expanding or collapsing a node double-clicking on the state image.
History
- 27-April-2004: Initial version.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 32 (Total in Forum: 32) (Refresh) | FirstPrevNext |
|
|
 |
|
|
I have converted the VB.NET version to a C# version.
While I am at it, I may as well mention a nice little code conversion tool provided by the folks at Telerik that I found on Google's iGoogle home page as a widget. Works like a champ. The only things it did not handle were the API definitions and usage instances (datatypes).
I'd like to post the C# code here but I do not see a way to do so.
Joe
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
It sure looks like a bug to me.
Allow me to provide a more complete description of the anomalous behavior.
When ShowNodeTooltips is set to true, the tooltips do indeed show, but the state icons do not. When ShowNodeTooltips is set to the node tooltips do not show and the state icons also show as expected.
Joe
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
using System; using System.Collections.Generic; using System.Text;
using System.Runtime.InteropServices; using System.Windows.Forms; using System.Drawing; using System.Collections;
namespace Pdb.BIPortal.UserAdmin.Controls.ImageTriStateTreeView {
public enum CheckBoxState { None = 0, Unchecked = 1, Checked = 2, Indeterminate = 3 }
public class ImageTriStateTreeView : System.Windows.Forms.TreeView {
[StructLayout(LayoutKind.Sequential)] private struct TVITEM { public int mask; public IntPtr hItem; public int state; public int stateMask; public int pszText; public int cchTextMax; public int iImage; public int iSelectedImage; public int cChildren; public int lParam; }
[StructLayout(LayoutKind.Sequential)] private struct POINTAPI { public int x; public int y; }
[StructLayout(LayoutKind.Sequential)] private struct TVHITTESTINFO { public POINTAPI pt; public int flags; public IntPtr hItem; }
// Messages private const int TV_FIRST = 4352; private const int TVM_SETIMAGELIST = TV_FIRST + 9; private const int TVM_GETITEM = TV_FIRST + 12; private const int TVM_SETITEM = TV_FIRST + 13; private const int TVM_HITTEST = TV_FIRST + 17;
// TVM_SETIMAGELIST image list kind private const int TVSIL_STATE = 2;
//TVITEM.mask flags private const int TVIF_STATE = 8; private const int TVIF_HANDLE = 16;
//TVITEM.state flags public const int TVIS_STATEIMAGEMASK = 61440;
//TVHITTESTINFO.flags flags public const int TVHT_ONITEMSTATEICON = 64;
// ImageList Images Indexes private const int m_IMG_CHECKBOX_NONE = 0; private const int m_IMG_CHECKBOX_UNCHECKED = 1; private const int m_IMG_CHECKBOX_CHECKED = 2; private const int m_IMG_CHECKBOX_INDETERMINATE = 3; [DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, IntPtr lParam); [DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, ref TVITEM lParam); [DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, ref TVHITTESTINFO lParam);
public ImageTriStateTreeView(ImageList ctlStateImageList) {
int iResult;
// Set the state image list iResult = SendMessage(this.Handle, TVM_SETIMAGELIST, TVSIL_STATE, ctlStateImageList.Handle);
}
private void SetTreeNodeAndChildrenStateRecursively(TreeNode objTreeNode, CheckBoxState eCheckBoxState) { if ((objTreeNode != null)) { SetTreeNodeState(objTreeNode, eCheckBoxState); foreach (TreeNode objChildTreeNode in objTreeNode.Nodes) { SetTreeNodeAndChildrenStateRecursively(objChildTreeNode, eCheckBoxState); } } }
private void SetParentTreeNodeStateRecursively(TreeNode objParentTreeNode) { CheckBoxState eCheckBoxState; bool bAllChildrenChecked = true; bool bAllChildrenUnchecked = true; if ((objParentTreeNode != null)) { if (GetTreeNodeState(objParentTreeNode) != CheckBoxState.None) {
foreach (TreeNode objTreeNode in objParentTreeNode.Nodes) { eCheckBoxState = GetTreeNodeState(objTreeNode); switch (eCheckBoxState) { case CheckBoxState.Checked: bAllChildrenUnchecked = false; break; case CheckBoxState.Indeterminate: bAllChildrenUnchecked = false; bAllChildrenChecked = false; break; case CheckBoxState.Unchecked: bAllChildrenChecked = false; break; } if (bAllChildrenChecked == false & bAllChildrenUnchecked == false) { // This is an optimization break; // TODO: might not be correct. Was : Exit For } } if (bAllChildrenChecked) { SetTreeNodeState(objParentTreeNode, CheckBoxState.Checked); } else if (bAllChildrenUnchecked) { SetTreeNodeState(objParentTreeNode, CheckBoxState.Unchecked); } else { SetTreeNodeState(objParentTreeNode, CheckBoxState.Indeterminate); } // Enter in recursion if ((objParentTreeNode.Parent != null)) { SetParentTreeNodeStateRecursively(objParentTreeNode.Parent); } } } }
internal CheckBoxState GetTreeNodeState(TreeNode objTreeNode) {
CheckBoxState eCheckBoxState = CheckBoxState.None;
TVITEM tTVITEM = new TVITEM(); int iState; int iResult;
tTVITEM.mask = TVIF_HANDLE | TVIF_STATE; tTVITEM.hItem = objTreeNode.Handle; tTVITEM.stateMask = TVIS_STATEIMAGEMASK; tTVITEM.state = 0;
iResult = SendMessage(this.Handle, TVM_GETITEM, 0, ref tTVITEM);
if (iResult != 0) {
iState = tTVITEM.state;
// State image index in bits 12..15 iState = iState / 4095;
switch (iState) {
case m_IMG_CHECKBOX_NONE: eCheckBoxState = CheckBoxState.None; break;
case m_IMG_CHECKBOX_UNCHECKED: eCheckBoxState = CheckBoxState.Unchecked; break;
case m_IMG_CHECKBOX_CHECKED: eCheckBoxState = CheckBoxState.Checked; break;
case m_IMG_CHECKBOX_INDETERMINATE: eCheckBoxState = CheckBoxState.Indeterminate; break;
}
}
return eCheckBoxState;
}
internal void SetTreeNodeState(TreeNode objTreeNode, CheckBoxState eCheckBoxState) {
int iImageIndex=0; TVITEM tTVITEM = new TVITEM(); int iState; int iResult;
if ((objTreeNode != null)) {
switch (eCheckBoxState) {
case CheckBoxState.None: iImageIndex = m_IMG_CHECKBOX_NONE; break;
case CheckBoxState.Unchecked: iImageIndex = m_IMG_CHECKBOX_UNCHECKED; break;
case CheckBoxState.Checked: iImageIndex = m_IMG_CHECKBOX_CHECKED; break;
case CheckBoxState.Indeterminate: iImageIndex = m_IMG_CHECKBOX_INDETERMINATE; break;
}
tTVITEM.mask = TVIF_HANDLE | TVIF_STATE; tTVITEM.hItem = objTreeNode.Handle; tTVITEM.stateMask = TVIS_STATEIMAGEMASK; // State image index in bits 12..15 tTVITEM.state = iImageIndex * 4096;
iResult = SendMessage(this.Handle, TVM_SETITEM, 0, ref tTVITEM);
}
}
public void ToggleTreeNodeState(TreeNode objTreeNode) {
CheckBoxState eCheckBoxState;
eCheckBoxState = GetTreeNodeState(objTreeNode);
this.BeginUpdate();
switch (eCheckBoxState) {
case CheckBoxState.Unchecked:
SetTreeNodeAndChildrenStateRecursively(objTreeNode, CheckBoxState.Checked); SetParentTreeNodeStateRecursively(objTreeNode.Parent); break;
case CheckBoxState.Checked: case CheckBoxState.Indeterminate:
SetTreeNodeAndChildrenStateRecursively(objTreeNode, CheckBoxState.Unchecked); SetParentTreeNodeStateRecursively(objTreeNode.Parent); break;
}
this.EndUpdate();
}
private TreeNode GetTreeNodeHitAtCheckBoxByScreenPosition(int iXScreenPos, int iYScreenPos) {
Point objClientPoint; TreeNode objTreeNode;
objClientPoint = this.PointToClient(new Point(iXScreenPos, iYScreenPos));
objTreeNode = GetTreeNodeHitAtCheckBoxByClientPosition(objClientPoint.X, objClientPoint.Y);
return objTreeNode;
}
private TreeNode GetTreeNodeHitAtCheckBoxByClientPosition(int iXClientPos, int iYClientPos) {
TreeNode objTreeNode = null; int iTreeNodeHandle; TVHITTESTINFO tTVHITTESTINFO = new TVHITTESTINFO();
// Get the hit info tTVHITTESTINFO.pt.x = iXClientPos; tTVHITTESTINFO.pt.y = iYClientPos; iTreeNodeHandle = SendMessage(this.Handle, TVM_HITTEST, 0, ref tTVHITTESTINFO);
// Check if it has clicked on an item if (iTreeNodeHandle != 0) {
// Check if it has clicked on the state image of the item if ((tTVHITTESTINFO.flags & TVHT_ONITEMSTATEICON) != 0) {
objTreeNode = TreeNode.FromHandle(this, new IntPtr(iTreeNodeHandle));
}
}
return objTreeNode;
}
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e) {
TreeNode objTreeNode;
base.OnMouseUp(e);
objTreeNode = GetTreeNodeHitAtCheckBoxByClientPosition(e.X, e.Y); if ((objTreeNode != null)) {
ToggleTreeNodeState(objTreeNode);
}
}
protected override void OnKeyUp(System.Windows.Forms.KeyEventArgs e) {
base.OnKeyUp(e);
if (e.KeyCode == Keys.Space) {
if ((this.SelectedNode != null)) { ToggleTreeNodeState(this.SelectedNode); }
}
}
protected override void OnBeforeExpand(System.Windows.Forms.TreeViewCancelEventArgs e) { // PATCH: if the node is being expanded by a double click at the state image, cancel it if ((GetTreeNodeHitAtCheckBoxByScreenPosition(MousePosition.X, MousePosition.Y) != null)) { e.Cancel = true; }
}
protected override void OnBeforeCollapse(System.Windows.Forms.TreeViewCancelEventArgs e) {
// PATCH: if the node is being collapsed by a double click at the state image, cancel it if ((GetTreeNodeHitAtCheckBoxByScreenPosition(MousePosition.X, MousePosition.Y) != null)) { e.Cancel = true; }
}
public TreeNode AddTreeNode(TreeNodeCollection colNodes, string sNodeText, int iImageIndex, CheckBoxState eCheckBoxState) { TreeNode objTreeNode;
objTreeNode = new TreeNode(sNodeText);
objTreeNode.ImageIndex = iImageIndex; objTreeNode.SelectedImageIndex = iImageIndex;
colNodes.Add(objTreeNode);
this.SetTreeNodeState(objTreeNode, eCheckBoxState);
return objTreeNode;
}
public TreeNode AddTreeNode(TreeNodeCollection colNodes, TreeNode objTreeNode, CheckBoxState eCheckBoxState) { colNodes.Add(objTreeNode); this.SetTreeNodeState(objTreeNode, eCheckBoxState); return objTreeNode; }
/// <summary> /// Return a list of the tag data for all of the checked items in the tree /// </summary> /// <returns></returns> public ArrayList GetCheckedTagData() { ArrayList list = new ArrayList();
foreach (TreeNode node in Nodes) BuildTagDataList(node, list); return list; }
/// <summary> /// Gets all checked nodes as a generic list. /// </summary> /// <typeparam name="T">Generic type</typeparam> /// <returns>Generic list</returns> public List<T> GetCheckedTagData<T>() { List<T> list = new List<T>();
foreach (TreeNode node in Nodes) BuildTagDataList(node, list); return list; }
/// <summary> /// Gets the checked state of a node /// </summary> /// <param name="node">Node</param> /// <returns>The checked state</returns> public ArrayList GetCheckedNodes() { ArrayList list = new ArrayList();
foreach (TreeNode node in Nodes) { BuildNodeDataList(node, list); }
return list; }
/// <summary> /// Build a list of all of the checked nodes in the tree. /// </summary> /// <param name="node"></param> /// <param name="list"></param> private void BuildNodeDataList(TreeNode node, ArrayList list) { if (GetTreeNodeState(node) == CheckBoxState.Checked) list.Add(node);
foreach (TreeNode child in node.Nodes) BuildNodeDataList(child, list); }
/// <summary> /// Build a list of all of the tag data for checked items in the tree. /// </summary> /// <param name="node"></param> /// <param name="list"></param> private void BuildTagDataList(TreeNode node, ArrayList list) { if (GetTreeNodeState(node) == CheckBoxState.Checked && node.Tag != null) list.Add(node.Tag);
foreach (TreeNode child in node.Nodes) BuildTagDataList(child, list); }
/// <summary> /// Build a list of all of the tag data for checked items in the tree. /// </summary> /// <typeparam name="T">The type of the list</typeparam> /// <param name="node">Current node</param> /// <param name="list">List to fill with tags</param> private void BuildTagDataList<T>(TreeNode node, List<T> list) { if (GetTreeNodeState(node) == CheckBoxState.Checked && node.Tag != null) list.Add((T)node.Tag);
foreach (TreeNode child in node.Nodes) BuildTagDataList(child, list); }
}
}
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, thanks for the great, helpful and needed class, but...
I have converted the vbcode into c# with SharpDeveloper. I added the converted classes FormTreeView and TriStateTreeView into a brand new c# windows application solution and replaced MainForm with FormTreeView. A few minor code modifications regarding compiler differences and the c# tree view runs perfectly as the original vb tree view. But...
Now I added the TriStateTreeView class into my project and the CheckBoxes don't show. I'm doing it exactly as in the example in FormTreeView. As far as I can tell I have tried everything. I'm not new to programming but I am new to c# and .NET. Can anyone confirm this behaviour or maybe even have a solution? I would be so very greatful!
Kind Regards
Tom
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi again, I found the couse. Nothing important.
If someone is interested: I populate and expand my node in the nodeMouseDoubleClick event. When I double click the check box the node is populated. It dousn't get expanded because the overridden onBeforeExpand prevents it. But to prevent the node from being populated I added and override for onNodeMouseDoubleClick to do nothing in case of GetTreeNodeHitAtCheckBoxByScreenPosition.
protected override void OnNodeMouseDoubleClick(System.Windows.Forms.TreeNodeMouseClickEventArgs e) { if ((GetTreeNodeHitAtCheckBoxByScreenPosition(MousePosition.X, MousePosition.Y) != null)) { } else base.OnNodeMouseDoubleClick(e); }
Thanks again for that very nice tree view.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi,
I really like this tristate class, but I have found a number of issues that I cannot work around.
1) If you call the form containing the class more than once, the checkboxes disappear. I tried this with the sample application by simply calling the FormTreeView.vb form twice, and it happened there as well.
2) If I set up two or three levels of items and set the items at the lowest levels to be checked. Unfortunately, this does not affect FOLDER level items above them to be partially or fully checked. Is this normal?
Any ideas?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
OK - I've managed to work around point issue above.
You need to set if to unchecked, and then toggle it. This cannot take place within the class definition for some reason, but does work in the form manipulating the control as follows:
m_ctlTriStateTreeView.SetTreeNodeState(tnNode, CheckBoxState.Unchecked) m_ctlTriStateTreeView.ToggleTreeNodeState(tnNode)
Issue 2 still remains, and I can't understand why it should.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
Hi, nice work!!!
I’m newbie, and I have been trying to populate this treeview with my windows route:
C:\ C:\windows C:\documents and settings\[user profile]\..... C:\program files\app 01\xx.txt
Butte I don’t have success….
Is it possible to populate windows route in this treeview, and on close form get the folders / files paths from checked boxes?
Regards
Mpires – mpires@astralpool.pt
-- modified at 18:52 Monday 19th February, 2007
mpires
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
I am using your treeview control after converting it in C#. It worked fine for an year when I used it in .NET 2003. Now I have shifted to .NET 2005 and I have one problem. If I want to get the state of the checkbox, it always returns false even if it is checked. After running it in both 2003 and 2005, I found the difference in the line iResult = SendMessage(this.Handle, TVM_SETITEM, 0, ref tTVITEM); in the method SetTreeNodeState(TreeNode objTreeNode, CheckBoxState eCheckBoxState).
I put a watch on the objTreeNode.Checked expression and in 2003 it turns to "true" after the code excution passes the SendMessage line. In 2005, nothing happens.
Can you help me get rid of this problem ?
Thanks in advance Achintya
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Hi, Again thanks for your code.It really does what I was looking for. I have noticed that you have overriden the beforeExpand Event and collapse event. This was to prevent expansion if doubleClick on the icon. However if you want to load lots of nodes on demand by using the expand even you cant.Any reason why not i should not comment it out?
thanks a lot
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,thanks for your control. I am trying to drag and drop your control from the toolbox to the form but i get an error. It would make life a lot easier.Are you meant to drag and drop the control onto a form?
Thanks A lot vbinfo@devnet247.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
No, it is a class, not a control for the toolbox. Read the article to see the usage. You can transform it into a control if you want.
Carlos J. Quintero
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi there, Tried to transform into a control but having problem with apicall. Basically I am included the stateImageList into the componect and tried moving the call to sendMessage to Public new but i get an error. Any advice ?
thanks a lot
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
Hi,
seems your Exchange server removed files when you mailed the zip to codeproject:
"Antigen for Exchange removed CodeProjectArticle.zip->TriStateTreeview.zip->TriStateTreeView.exe since it was found to match the FILE FILTER= *.exe file filter."
I'd like to try your control .dll, but I haven't installed VB in VS and I don't have the CDs around so I can't compile it myself... Would it be possible for you to post the zip through another server?
Thanks, Jonas
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Jonas,
You are right. I have submitted again the zip file, I don´t know how long it will take to appear. Meantine, you can contact me through my web site www.mztools.com and I will send you the zip file directly.
Best regards,
Carlos Quintero
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks a lot,
that's just what i was looking for.
Just a little remark, when i when replace my standard treeview by your class, i forgot to remove the 'Me.TreeView.CheckBoxes = True attribute. It has for effect that you can't uncheck the checkboxes anymore and other disfonctionnement (the parent checkboxe disapear when you double click on a node)
now it works fine
Jérôme - FRANCE
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
hello everyone:
now i have want to add a treeview control with checkboxes to my web pages, however,there is neither treeview nor checkbox controls in my toolbox. what can i do now ?any thing is appreciated,thanX in advance!!!!!!!!!
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Excellent job and nice bit of coding. Unfortunatly, I needed something like this in C++.
I ended up spending the better part of a day porting this over to Managed C++, and got it to work quit nicely there as well (with the default State images internalized itto the TriStateTreeView class. The user can supply an optional set by setting a "StateImage" property after "new"ing an instance of the control.
I've seen all the ways to "fake it" using the Icon images, but was nice to finally find one that actually got ahold of the actual checkbox image and update it as necessary (which is exactly what I wanted, as I was not really impressed with any of the "fake it" versions).
The big mystery is why the heck did MS not supply something like this as part of the framework in the first place? I've seen some of thier own friggan programs make use of a tri-state type tree, such as the back-up program that came with Windows 2000.
Again, an excellent job on this. I can only imagine what a pain it must've been to figure out all the internal messaging and the like to get ahold of, as well as set, those state images and the states.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Replying to my own message....
After porting this over to Managed C++, I made some improvements.
0 - I overrode the "CheckBoxes" property. This now allows a programmer to "turn on/off" the tri-state check boxes through the property.
0 - I internalized the default check box state images, thus the user does not need to specify an imagelist to the constructor. I did overload the constructor to allow the user to specify a state image list at instantiation.
0 - The default image list is only built "on-demand", that is, it does not bother to setup the image list control until it needs it (i.e., the user set the "CheckBoxes" property to "true" and did not specify a user-defined state image list.
0 - I created a new property "StateImageList" to allow the user to setup a user-specified image list for the check boxes. The user can revert back to the default image list by setting a "0" (effectively "nulling" it out) to this property. The user can also get the current image list that is set. If no user-defined image list is set, it'll return an image list containing the default images.
0 - Lastly, I overloaded the "AddTreeNode" function. I provided versions that only needed to take the node collection and the text. A version that needed only the collection, text, and an image index as well as a couple other variations. I also added an additional argument to the orginal one, to allow the user to specify a seperate "selected image" index.
Some future enhancements that would be nice, if time allows:
First, would be nice to make this a seperate .NET component that could be dragged-n-dropped into the designer, for example. Probably create a "UserControl" from this and make it it's own assembly that would be added into projects that needed this.
Second, would be nice to derive a new "TreeNode" class to allow it's "Checked" property to be overridden. Instead of a boolean value, it would be able to take/return a CheckBoxState enum value. This would be more consistant with how .NET works, since everything seems to be in terms of events, properties, and controls.
Signature? I don't need no stinkin' signature!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question 
|