using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
namespace Vanara.Windows.Forms
{
///
/// A combo box that displays the items of an type. If the Enum type has a , then the
/// drop-down will be checked list of the values.
///
///
public class EnumComboBox : CustomComboBox
{
private readonly List items = new List();
private readonly Timer timer = new Timer { Interval = 150 };
private CheckedListBox checkListBox;
private Type type = null;
/// Initializes a new instance of the class.
public EnumComboBox() : base()
{
base.DropDownStyle = ComboBoxStyle.DropDownList;
timer.Tick += Timer_Tick;
}
/// Gets or sets the data source for this .
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new object DataSource { get => base.DataSource; set => base.DataSource = value; }
/// Gets or sets the property to display for this .
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string DisplayMember { get => base.DisplayMember; set => base.DisplayMember = value; }
/// Gets or sets a value specifying the style of the combo box.
///
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new ComboBoxStyle DropDownStyle { get => base.DropDownStyle; set => base.DropDownStyle = value; }
/// Gets or sets the Enum type that is used to populate the values of the combo box.
/// The enum type string.
/// EnumTypeString must be an enumerated type.
[DefaultValue(""), Category("Behavior"), Description("The Enum type that is used to populate the values of the combo box.")]
public string EnumTypeString
{
get => type?.FullName ?? "";
set
{
type = FindType(value, true);
if (type is null || !type.IsEnum)
throw new ArgumentException("EnumTypeString must be an enumerated type.");
items.Clear();
foreach (var item in Enum.GetValues(type))
items.Add(new ECBItem(item));
if (type.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0)
{
if (checkListBox == null)
{
checkListBox = new CheckedListBox()
{
BorderStyle = BorderStyle.None,
CheckOnClick = true,
FormattingEnabled = true,
Location = new System.Drawing.Point(17, 35),
MultiColumn = false,
Name = "checkedListBox1",
Size = new System.Drawing.Size(187, 105),
TabIndex = 0
};
checkListBox.ItemCheck += CheckListBox_ItemCheck;
}
checkListBox.Items.Clear();
checkListBox.Items.AddRange(items.ToArray());
DropDownControl = checkListBox;
}
else
{
DropDownControl = null;
DisplayMember = "Text";
ValueMember = "Value";
DataSource = items;
}
}
}
///
/// Gets or sets the value of the member property specified by the property.
///
public new object SelectedValue
{
get
{
var ret = 0L;
if (!HasFlags)
{
ret = Convert.ToInt64(items[SelectedIndex].Value);
}
else
{
for (var i = 0; i < checkListBox.CheckedItems.Count; i++)
{
var o = checkListBox.CheckedItems[i] as ECBItem;
if (o != null && o.Value is IConvertible)
try { ret |= Convert.ToInt64(o.Value); } catch { }
}
}
return Convert.ChangeType(ret, GetEnumUnderlyingType(type));
}
set
{
if (!HasFlags)
SelectedIndex = items.FindIndex(i => i.Value == value);
else
{
var lval = Convert.ToInt64(value);
checkListBox.BeginUpdate();
for (var i = 0; i < checkListBox.Items.Count; i++)
{
long? val = null;
var o = checkListBox.Items[i] as ECBItem;
if (o != null && o.Value is IConvertible)
try { val = Convert.ToInt64(o.Value); } catch { }
checkListBox.SetItemCheckState(i, (val.HasValue && (val.Value & lval) == val.Value) ? CheckState.Checked : CheckState.Unchecked);
}
checkListBox.EndUpdate();
}
}
}
/// Gets or sets the property to use as the actual value for the items in the .
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string ValueMember { get => base.ValueMember; set => base.ValueMember = value; }
/// Gets an object representing the collection of the items contained in this .
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new ObjectCollection Items => base.Items;
private bool HasFlags => DropDownControl != null;
/// Gets the selected value.
/// The type of the value to retrieve.
/// The selected value cast to .
public T GetSelectedValue() => SelectedValue == null ? default : (T)SelectedValue;
private static Type GetEnumUnderlyingType(Type eType)
{
if (!eType.IsEnum)
throw new ArgumentException("Must be an Enum type.", nameof(eType));
var fields = eType.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (fields == null || fields.Length != 1)
throw new ArgumentException("Invalid Enum type.", nameof(eType));
return fields[0].FieldType;
}
private void CheckListBox_ItemCheck(object sender, ItemCheckEventArgs e) => timer.Enabled = true;
private Type FindType(string name, bool ignoreCase) => AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetType(name, false, ignoreCase)).Where(t => t != null).FirstOrDefault();
private string GetFlagText()
{
var items = new string[checkListBox.CheckedItems.Count];
for (var i = 0; i < checkListBox.CheckedItems.Count; i++)
items[i] = checkListBox.CheckedItems[i].ToString();
return string.Join(", ", items);
}
private void Timer_Tick(object sender, EventArgs e)
{
timer.Enabled = false;
if (HasFlags)
Text = GetFlagText();
}
[Serializable]
private class ECBItem
{
public ECBItem(object value)
{
Value = value;
Text = value.ToString();
// TODO: Alternatively get text from resource or translation service.
}
public string Text { get; set; }
public object Value { get; set; }
public override string ToString() => Text;
}
}
}