using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Forms; namespace Microsoft.Win32.TaskScheduler { /// /// A check list in a drop down combo box. /// [System.Drawing.ToolboxBitmap(typeof(Microsoft.Win32.TaskScheduler.TaskEditDialog), "Control")] public partial class DropDownCheckTree : CustomComboBox { private List checkedItems = new List(); private System.Windows.Forms.TreeView checkedTreeView; private bool updatingChecks; private Dictionary values = new Dictionary(); /// /// Initializes a new instance of the class. /// public DropDownCheckTree() { this.checkedTreeView = new System.Windows.Forms.TreeView() { BorderStyle = System.Windows.Forms.BorderStyle.None, CheckBoxes = true, Name = "checkedTreeView", ShowLines = true, ShowPlusMinus = true, Tag = this, Visible = false }; this.checkedTreeView.AfterCheck += checkedTreeView_ItemCheck; base.DropDownControl = this.checkedTreeView; base.DropSize = new System.Drawing.Size(base.DropDownWidth, 400); } private delegate void NodeAction(TreeNode node, bool childrenChecked); /// /// Occurs when the property changes. /// [Category("Action"), Description("Occurs when the SelectedItems property changes.")] public event EventHandler SelectedItemsChanged; /// /// Gets or sets the text used on the Check All Items item that, when clicked, will check all the other items. /// /// The text. [DefaultValue((string)null), Category("Appearance"), Localizable(true)] public string CheckAllText { get; set; } /// /// Gets the checked items. /// /// The checked items. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public List CheckedItems { get { return this.checkedItems; } } /// /// Gets or sets a value indicating whether formatting is applied to the property of the . /// /// /// true if formatting of the property is enabled; otherwise, false. The default is false. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new bool FormattingEnabled { get { return base.FormattingEnabled; } set { base.FormattingEnabled = value; } } /// /// Gets the list of all check list items. /// /// The items. [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Category("Data")] public new TreeNodeCollection Items { get { return this.checkedTreeView.Nodes; } } /// /// Gets or sets a value indicating whether the items in the combo box are sorted. /// /// true if the combo box is sorted; otherwise, false. The default is false. /// /// An attempt was made to sort a that is attached to a data source. /// /// /// /// /// /// /// public new bool Sorted { get { return this.checkedTreeView.Sorted; } set { this.checkedTreeView.Sorted = value; } } /// /// Checks the matching items. /// /// The match. /// if set to true keep existing checked items. public void CheckItems(Predicate match, bool keepExisting = false) { ForEachChildNode(this.checkedTreeView.Nodes, n => { if (match == null || match(n.Name)) n.Checked = true; else if (!keepExisting) n.Checked = false; }); UpdateText(); } /// /// Checks the item in the tree whose value matches the one specified by . /// /// The value to match. /// if set to true check the matching item, else uncheck it. public void CheckValue(string value, bool check = true) { TreeNode node; if (value != null && value is string) if (values.TryGetValue((string)value, out node)) node.Checked = check; UpdateText(); } /// /// Unchecks all items in the tree. /// public void UncheckAllItems() { updatingChecks = true; for (int i = checkedItems.Count - 1; i >= 0; i--) checkedItems[i].Checked = false; checkedItems.Clear(); updatingChecks = false; UpdateText(); } /// /// Updates the text associated with each item of the check list. /// public void UpdateText() { if (this.checkedItems.Count == 0) { this.Text = string.Empty; } else { if (this.checkedItems.Count == this.checkedTreeView.GetNodeCount(true) && this.CheckAllText != null) this.Text = this.CheckAllText; else { var selNodes = this.checkedItems.FindAll(n => !string.IsNullOrEmpty(n.Name)).ConvertAll(t => (string)t.Name); selNodes.Sort(); this.Text = string.Join(", ", selNodes.ToArray()); } } } internal static TreeNode AddValue(TreeNodeCollection nodeColl, string text, string key) { TreeNode child = nodeColl.Add(key, text); if (key != null) { if (child.TreeView != null && child.TreeView.Parent != null && child.TreeView.Tag is DropDownCheckTree) ((DropDownCheckTree)child.TreeView.Tag).values.Add(key, child); } return child; } /// /// Raises the event. /// /// An that contains the event data. protected override void OnDropDownClosed(EventArgs e) { base.OnDropDownClosed(e); UpdateText(); } /// /// Raises the event. /// protected virtual void OnSelectedItemsChanged() { EventHandler h = this.SelectedItemsChanged; if (h != null) h(this, EventArgs.Empty); } private bool AreChildrenChecked(TreeNode treeNode, NodeAction nodeAction = null) { bool foundCheck = false; foreach (TreeNode n in treeNode.Nodes) { if (n.Checked || AreChildrenChecked(n)) { foundCheck = true; break; } } if (nodeAction != null) nodeAction(treeNode, foundCheck); return foundCheck; } private void checkedTreeView_ItemCheck(object sender, TreeViewEventArgs e) { // Update checked items list if (e.Node.Checked) this.checkedItems.Add(e.Node); else this.checkedItems.Remove(e.Node); // Update parent and children checks appropriately if (!updatingChecks) { updatingChecks = true; SetCheckOnChildren(e.Node); TreeNode n = e.Node; while (n.Parent != null) { n.Parent.Checked = e.Node.Checked ? true : AreChildrenChecked(n.Parent); n = n.Parent; } OnSelectedItemsChanged(); updatingChecks = false; } } private void ForEachChildNode(TreeNodeCollection pNodes, Action action, bool allChildren = true) { foreach (TreeNode node in pNodes) { action(node); if (allChildren) ForEachChildNode(node.Nodes, action, allChildren); } } private void SetCheckOnChildren(TreeNode treeNode) { bool pChecked = treeNode.Checked; ForEachChildNode(treeNode.Nodes, n => { n.Checked = pChecked; }); } } }