using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Windows.Forms; using System.Reflection; using System.ComponentModel; using System.Drawing.Design; namespace Aga.Controls.Tree.NodeControls { public class NodeComboBox : BaseTextControl { #region Properties private int _editorWidth = 100; [DefaultValue(100)] public int EditorWidth { get { return _editorWidth; } set { _editorWidth = value; } } private int _editorHeight = 100; [DefaultValue(100)] public int EditorHeight { get { return _editorHeight; } set { _editorHeight = value; } } private List _dropDownItems; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] [Editor(typeof(StringCollectionEditor), typeof(UITypeEditor)), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public List DropDownItems { get { return _dropDownItems; } } #endregion public event EventHandler CreatingEditor; public NodeComboBox() { _dropDownItems = new List(); } protected override Size CalculateEditorSize(EditorContext context) { if (Parent.UseColumns) { if (context.Editor is CheckedListBox) return new Size(context.Bounds.Size.Width, EditorHeight); else return context.Bounds.Size; } else { if (context.Editor is CheckedListBox) return new Size(EditorWidth, EditorHeight); else return new Size(EditorWidth, context.Bounds.Height); } } protected override Control CreateEditor(TreeNodeAdv node) { Control c; object value = GetValue(node); if (IsCheckedListBoxRequired(node)) c = CreateCheckedListBox(node); else c = CreateCombo(node); OnCreatingEditor(new EditEventArgs(node, c)); return c; } protected override void DisposeEditor(Control editor) { } protected virtual void OnCreatingEditor(EditEventArgs args) { if (CreatingEditor != null) CreatingEditor(this, args); } protected virtual bool IsCheckedListBoxRequired(TreeNodeAdv node) { object value = GetValue(node); if (value != null) { Type t = value.GetType(); object[] arr = t.GetCustomAttributes(typeof(FlagsAttribute), false); return (t.IsEnum && arr.Length == 1); } return false; } private Control CreateCombo(TreeNodeAdv node) { ComboBox comboBox = new ComboBox(); if (DropDownItems != null) comboBox.Items.AddRange(DropDownItems.ToArray()); comboBox.SelectedItem = GetValue(node); comboBox.DropDownStyle = ComboBoxStyle.DropDownList; comboBox.DropDownClosed += new EventHandler(EditorDropDownClosed); SetEditControlProperties(comboBox, node); return comboBox; } private Control CreateCheckedListBox(TreeNodeAdv node) { CheckedListBox listBox = new CheckedListBox(); listBox.CheckOnClick = true; object value = GetValue(node); Type enumType = GetEnumType(node); foreach (object obj in Enum.GetValues(enumType)) { object[] attributes = enumType.GetField(obj.ToString()).GetCustomAttributes(typeof(BrowsableAttribute), false); if (attributes.Length == 0 || ((BrowsableAttribute)attributes[0]).Browsable) listBox.Items.Add(obj, IsContain(value, obj)); } SetEditControlProperties(listBox, node); if (CreatingEditor != null) CreatingEditor(this, new EditEventArgs(node, listBox)); return listBox; } protected virtual Type GetEnumType(TreeNodeAdv node) { object value = GetValue(node); return value.GetType(); } private bool IsContain(object value, object enumElement) { if (value == null || enumElement == null) return false; if (value.GetType().IsEnum) { int i1 = (int)value; int i2 = (int)enumElement; return (i1 & i2) == i2; } else { var arr = value as object[]; foreach (object obj in arr) if ((int)obj == (int)enumElement) return true; return false; } } protected override string FormatLabel(object obj) { var arr = obj as object[]; if (arr != null) { StringBuilder sb = new StringBuilder(); foreach (object t in arr) { if (sb.Length > 0) sb.Append(", "); sb.Append(t); } return sb.ToString(); } else return base.FormatLabel(obj); } void EditorDropDownClosed(object sender, EventArgs e) { EndEdit(true); } public override void UpdateEditor(Control control) { if (control is ComboBox) (control as ComboBox).DroppedDown = true; } protected override void DoApplyChanges(TreeNodeAdv node, Control editor) { var combo = editor as ComboBox; if (combo != null) { if (combo.DropDownStyle == ComboBoxStyle.DropDown) SetValue(node, combo.Text); else SetValue(node, combo.SelectedItem); } else { var listBox = editor as CheckedListBox; Type type = GetEnumType(node); if (IsFlags(type)) { int res = 0; foreach (object obj in listBox.CheckedItems) res |= (int)obj; object val = Enum.ToObject(type, res); SetValue(node, val); } else { List list = new List(); foreach (object obj in listBox.CheckedItems) list.Add(obj); SetValue(node, list.ToArray()); } } } private bool IsFlags(Type type) { object[] atr = type.GetCustomAttributes(typeof(FlagsAttribute), false); return atr.Length == 1; } public override void MouseUp(TreeNodeAdvMouseEventArgs args) { if (args.Node != null && args.Node.IsSelected) //Workaround of specific ComboBox control behavior base.MouseUp(args); } } }