diff --git a/WatchList.WinForms/Control/CheckComboBox/CheckBoxComboBox.cs b/WatchList.WinForms/Control/CheckComboBox/CheckBoxComboBox.cs index 787a32d..21f8c5d 100644 --- a/WatchList.WinForms/Control/CheckComboBox/CheckBoxComboBox.cs +++ b/WatchList.WinForms/Control/CheckComboBox/CheckBoxComboBox.cs @@ -1,5 +1,5 @@ using System.ComponentModel; -using System.Reflection; +using WatchList.WinForms.Control.CheckComboBox.Component; namespace TestTask.Controls.CheckComboBox { @@ -354,459 +354,6 @@ private void CheckBoxProperties_Changed(object sender, EventArgs e) #endregion } - /// - /// This ListControl that pops up to the User. It contains the CheckBoxComboBoxItems. - /// The items are docked DockStyle.Top in this control. - /// - [ToolboxItem(false)] - public class CheckBoxComboBoxListControl : ScrollableControl - { - #region CONSTRUCTOR - - public CheckBoxComboBoxListControl(CheckBoxComboBox owner) - : base() - { - DoubleBuffered = true; - - _checkBoxComboBox = owner; - _items = new CheckBoxComboBoxItemList(_checkBoxComboBox); - BackColor = SystemColors.Window; - // AutoScaleMode = AutoScaleMode.Inherit; - AutoScroll = true; - ResizeRedraw = true; - // if you don't set this, a Resize operation causes an error in the base class. - MinimumSize = new Size(1, 1); - MaximumSize = new Size(500, 500); - } - - #endregion - - #region PRIVATE PROPERTIES - - /// - /// Simply a reference to the CheckBoxComboBox. - /// - private CheckBoxComboBox _checkBoxComboBox; - - /// - /// A Typed list of ComboBoxCheckBoxItems. - /// - private CheckBoxComboBoxItemList _items; - - #endregion - - public CheckBoxComboBoxItemList Items { get => _items; } - - #region RESIZE OVERRIDE REQUIRED BY THE POPUP CONTROL - - /// - /// Prescribed by the Popup control to enable Resize operations. - /// - /// - protected override void WndProc(ref Message m) - { - if ((Parent.Parent as Popup).ProcessResizing(ref m)) - { - return; - } - - base.WndProc(ref m); - } - - #endregion - - #region PROTECTED MEMBERS - - [Obsolete] - protected override void OnVisibleChanged(EventArgs e) - { - // Synchronises the CheckBox list with the items in the ComboBox. - SynchroniseControlsWithComboBoxItems(); - base.OnVisibleChanged(e); - } - - /// - /// Maintains the controls displayed in the list by keeping them in sync with the actual - /// items in the combobox. (e.g. removing and adding as well as ordering) - /// - [Obsolete] - public void SynchroniseControlsWithComboBoxItems() - { - SuspendLayout(); - - if (_checkBoxComboBox._mustAddHiddenItem && _checkBoxComboBox.DataSource == null) - { - _checkBoxComboBox.Items.Insert(0, _checkBoxComboBox.GetCSVText(false)); // INVISIBLE ITEM - _checkBoxComboBox.SelectedIndex = 0; - _checkBoxComboBox._mustAddHiddenItem = false; - } - - Controls.Clear(); - - #region Disposes all items that are no longer in the combo box list - - for (int Index = _items.Count - 1; Index >= 0; Index--) - { - CheckBoxComboBoxItem item = _items[Index]; - if (!_checkBoxComboBox.Items.Contains(item.ComboBoxItem)) - { - _items.Remove(item); - item.Dispose(); - } - } - #endregion - - #region Recreate the list in the same order of the combo box items - - bool HasHiddenItem = _checkBoxComboBox.DropDownStyle == ComboBoxStyle.DropDownList - && _checkBoxComboBox.DataSource == null - && !DesignMode; - - CheckBoxComboBoxItemList NewList = new CheckBoxComboBoxItemList(_checkBoxComboBox); - - for (var index0 = 0; index0 <= _checkBoxComboBox.Items.Count - 1; index0++) - { - var obj = _checkBoxComboBox.Items[index0]; - CheckBoxComboBoxItem? item = null; - - // The hidden item could match any other item when only - // one other item was selected. - if (index0 == 0 && HasHiddenItem && _items.Count > 0) - { - item = _items[0]; - } - else - { - int startIndex = HasHiddenItem - ? 1 // Skip the hidden item, it could match - : 0; - for (int index1 = startIndex; index1 <= _items.Count - 1; index1++) - { - if (_items[index1].ComboBoxItem == obj) - { - item = _items[index1]; - break; - } - } - } - - if (item == null) - { - item = new CheckBoxComboBoxItem(_checkBoxComboBox, obj); - item.ApplyProperties(_checkBoxComboBox.CheckBoxProperties); - } - - NewList.Add(item); - item.Dock = DockStyle.Top; - } - - _items.Clear(); - _items.AddRange(NewList); - - #endregion - #region Add the items to the controls in reversed order to maintain correct docking order - - if (NewList.Count > 0) - { - // This reverse helps to maintain correct docking order. - NewList.Reverse(); - // If you get an error here that "Cannot convert to the desired - // type, it probably means the controls are not binding correctly. - // The Checked property is binded to the ValueMember property. - // It must be a bool for example. - Controls.AddRange(NewList.ToArray()); - } - - #endregion - - // Keep the first item invisible - if (_checkBoxComboBox.DropDownStyle == ComboBoxStyle.DropDownList - && _checkBoxComboBox.DataSource == null - && !DesignMode) - { - _checkBoxComboBox.CheckBoxItems[0].Visible = false; - } - - ResumeLayout(); - } - - #endregion - } - - /// - /// The CheckBox items displayed in the Popup of the ComboBox. - /// - [ToolboxItem(false)] - public class CheckBoxComboBoxItem : CheckBox - { - #region CONSTRUCTOR - - /// A reference to the CheckBoxComboBox. - /// A reference to the item in the ComboBox.Items that this object is extending. - public CheckBoxComboBoxItem(CheckBoxComboBox owner, object comboBoxItem) - : base() - { - DoubleBuffered = true; - _checkBoxComboBox = owner; - _comboBoxItem = comboBoxItem; - - if (_checkBoxComboBox.DataSource != null) - { - AddBindings(); - } - else - { - Text = comboBoxItem.ToString(); - } - } - #endregion - - #region PRIVATE PROPERTIES - - /// - /// A reference to the CheckBoxComboBox. - /// - private readonly CheckBoxComboBox _checkBoxComboBox; - - /// - /// A reference to the Item in ComboBox.Items that this object is extending. - /// - private object _comboBoxItem; - - #endregion - - #region PUBLIC PROPERTIES - - /// - /// A reference to the Item in ComboBox.Items that this object is extending. - /// - public object ComboBoxItem - { - get => _comboBoxItem; - internal set => _comboBoxItem = value; - } - - #endregion - - #region BINDING HELPER - - /// - /// When using Data Binding operations via the DataSource property of the ComboBox. This - /// adds the required Bindings for the CheckBoxes. - /// - public void AddBindings() - { - // Note, the text uses "DisplayMemberSingleItem", not "DisplayMember" (unless its not assigned) - DataBindings.Add("Text", _comboBoxItem, _checkBoxComboBox.DisplayMemberSingleItem); - - // The ValueMember must be a bool type property usable by the CheckBox.Checked. - DataBindings.Add("Checked", _comboBoxItem, _checkBoxComboBox.ValueMember, false, - // This helps to maintain proper selection state in the Binded object, - // even when the controls are added and removed. - DataSourceUpdateMode.OnPropertyChanged, false, null, null); - - // Helps to maintain the Checked status of this - // checkbox before the control is visible - if (_comboBoxItem is INotifyPropertyChanged) - { - ((INotifyPropertyChanged)_comboBoxItem).PropertyChanged += new PropertyChangedEventHandler(CheckBoxComboBoxItem_PropertyChanged); - } - } - - #endregion - - #region PROTECTED MEMBERS - - protected override void OnCheckedChanged(EventArgs e) - { - // Found that when this event is raised, the bool value of the binded item is not yet updated. - if (_checkBoxComboBox.DataSource != null) - { - PropertyInfo pI = ComboBoxItem.GetType().GetProperty(_checkBoxComboBox.ValueMember); - pI.SetValue(ComboBoxItem, Checked, null); - } - - base.OnCheckedChanged(e); - // Forces a refresh of the Text displayed in the main TextBox of the ComboBox, - // since that Text will most probably represent a concatenation of selected values. - // Also see DisplayMemberSingleItem on the CheckBoxComboBox for more information. - if (_checkBoxComboBox.DataSource != null) - { - string oldDisplayMember = _checkBoxComboBox.DisplayMember; - _checkBoxComboBox.DisplayMember = null; - _checkBoxComboBox.DisplayMember = oldDisplayMember; - } - } - - #endregion - - #region HELPER MEMBERS - - internal void ApplyProperties(CheckBoxProperties properties) - { - Appearance = properties.Appearance; - AutoCheck = properties.AutoCheck; - AutoEllipsis = properties.AutoEllipsis; - AutoSize = properties.AutoSize; - CheckAlign = properties.CheckAlign; - FlatAppearance.BorderColor = properties.FlatAppearanceBorderColor; - FlatAppearance.BorderSize = properties.FlatAppearanceBorderSize; - FlatAppearance.CheckedBackColor = properties.FlatAppearanceCheckedBackColor; - FlatAppearance.MouseDownBackColor = properties.FlatAppearanceMouseDownBackColor; - FlatAppearance.MouseOverBackColor = properties.FlatAppearanceMouseOverBackColor; - FlatStyle = properties.FlatStyle; - ForeColor = properties.ForeColor; - RightToLeft = properties.RightToLeft; - TextAlign = properties.TextAlign; - ThreeState = properties.ThreeState; - } - - #endregion - - #region EVENT HANDLERS - ComboBoxItem (DataSource) - - /// - /// Added this handler because the control doesn't seem - /// to initialize correctly until shown for the first - /// time, which also means the summary text value - /// of the combo is out of sync initially. - /// - private void CheckBoxComboBoxItem_PropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == _checkBoxComboBox.ValueMember) - { - Checked = (bool)_comboBoxItem - .GetType() - .GetProperty(_checkBoxComboBox.ValueMember) - .GetValue(_comboBoxItem, null); - } - } - - #endregion - } - - /// - /// A Typed List of the CheckBox items. - /// Simply a wrapper for the CheckBoxComboBox.Items. A list of CheckBoxComboBoxItem objects. - /// This List is automatically synchronised with the Items of the ComboBox and extended to - /// handle the additional boolean value. That said, do not Add or Remove using this List, - /// it will be lost or regenerated from the ComboBox.Items. - /// - [ToolboxItem(false)] - public class CheckBoxComboBoxItemList : List - { - #region CONSTRUCTORS - - public CheckBoxComboBoxItemList(CheckBoxComboBox checkBoxComboBox) - { - _CheckBoxComboBox = checkBoxComboBox; - } - - #endregion - - #region PRIVATE FIELDS - - private CheckBoxComboBox _CheckBoxComboBox; - - #endregion - - #region EVENTS, This could be moved to the list control if needed - - public event EventHandler CheckBoxCheckedChanged; - - protected void OnCheckBoxCheckedChanged(object sender, EventArgs e) => CheckBoxCheckedChanged?.Invoke(sender, e); - - private void item_CheckedChanged(object sender, EventArgs e) => OnCheckBoxCheckedChanged(sender, e); - - #endregion - - #region LIST MEMBERS & OBSOLETE INDICATORS - - [Obsolete("Do not add items to this list directly. Use the ComboBox items instead.", false)] - public new void Add(CheckBoxComboBoxItem item) - { - item.CheckedChanged += new EventHandler(item_CheckedChanged); - base.Add(item); - } - - public new void AddRange(IEnumerable collection) - { - foreach (CheckBoxComboBoxItem item in collection) - { - item.CheckedChanged += new EventHandler(item_CheckedChanged); - } - - base.AddRange(collection); - } - - public new void Clear() - { - foreach (CheckBoxComboBoxItem item in this) - { - item.CheckedChanged -= item_CheckedChanged; - } - - base.Clear(); - } - - [Obsolete("Do not remove items from this list directly. Use the ComboBox items instead.", false)] - public new bool Remove(CheckBoxComboBoxItem item) - { - item.CheckedChanged -= item_CheckedChanged; - return base.Remove(item); - } - - #endregion - - #region DEFAULT PROPERTIES - - /// - /// Returns the item with the specified displayName or Text. - /// - public CheckBoxComboBoxItem this[string displayName] - { - get - { - // An invisible item exists in this scenario to help with the Text displayed in the TextBox of the Combo - // 1 Ubiklou : 2008-04-28 : Ignore first item. - // (http://www.codeproject.com/KB/combobox/extending_combobox.aspx?fid=476622&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2526813&fr=1#xx2526813xx) - var startIndex = _CheckBoxComboBox.DropDownStyle - == ComboBoxStyle.DropDownList - && _CheckBoxComboBox.DataSource - == null ? 1 : 0; - - for (var Index = startIndex; Index <= Count - 1; Index++) - { - CheckBoxComboBoxItem Item = this[Index]; - - string? text; - - if (string.IsNullOrEmpty(Item.Text) - && Item.DataBindings != null - && Item.DataBindings["Text"] != null) - { - PropertyInfo propertyInfo = Item.ComboBoxItem.GetType() - .GetProperty(Item.DataBindings["Text"].BindingMemberInfo.BindingMember); - text = propertyInfo.GetValue(Item.ComboBoxItem, null) as string; - } - else - { - text = Item.Text; - } - - if (text.CompareTo(displayName) == 0) - { - return Item; - } - } - - throw new ArgumentOutOfRangeException(string.Format("\"{0}\" does not exist in this combo box.", displayName)); - } - } - - #endregion - } - [TypeConverter(typeof(ExpandableObjectConverter))] public class CheckBoxProperties { diff --git a/WatchList.WinForms/Control/CheckComboBox/CheckBoxCMBListControlContainer.cs b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxCMBListControlContainer.cs similarity index 93% rename from WatchList.WinForms/Control/CheckComboBox/CheckBoxCMBListControlContainer.cs rename to WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxCMBListControlContainer.cs index 1d0b9c5..c5d465f 100644 --- a/WatchList.WinForms/Control/CheckComboBox/CheckBoxCMBListControlContainer.cs +++ b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxCMBListControlContainer.cs @@ -1,6 +1,7 @@ using System.ComponentModel; +using TestTask.Controls.CheckComboBox; -namespace TestTask.Controls.CheckComboBox +namespace WatchList.WinForms.Control.CheckComboBox.Component { /// /// A container control for the ListControl to ensure the ScrollBar on the ListControl does not diff --git a/WatchList.WinForms/Control/CheckComboBox/CheckBoxCMBListControlContainer.resx b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxCMBListControlContainer.resx similarity index 100% rename from WatchList.WinForms/Control/CheckComboBox/CheckBoxCMBListControlContainer.resx rename to WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxCMBListControlContainer.resx diff --git a/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxItem.cs b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxItem.cs new file mode 100644 index 0000000..529439f --- /dev/null +++ b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxItem.cs @@ -0,0 +1,158 @@ +using System.ComponentModel; +using System.Reflection; +using TestTask.Controls.CheckComboBox; + +namespace WatchList.WinForms.Control.CheckComboBox.Component +{ + /// + /// The CheckBox items displayed in the Popup of the ComboBox. + /// + [ToolboxItem(false)] + public class CheckBoxComboBoxItem : CheckBox + { + #region CONSTRUCTOR + + /// A reference to the CheckBoxComboBox. + /// A reference to the item in the ComboBox.Items that this object is extending. + public CheckBoxComboBoxItem(CheckBoxComboBox owner, object comboBoxItem) + : base() + { + DoubleBuffered = true; + _checkBoxComboBox = owner; + _comboBoxItem = comboBoxItem; + + if (_checkBoxComboBox.DataSource != null) + { + AddBindings(); + } + else + { + Text = comboBoxItem.ToString(); + } + } + #endregion + + #region PRIVATE PROPERTIES + + /// + /// A reference to the CheckBoxComboBox. + /// + private readonly CheckBoxComboBox _checkBoxComboBox; + + /// + /// A reference to the Item in ComboBox.Items that this object is extending. + /// + private object _comboBoxItem; + + #endregion + + #region PUBLIC PROPERTIES + + /// + /// A reference to the Item in ComboBox.Items that this object is extending. + /// + public object ComboBoxItem + { + get => _comboBoxItem; + internal set => _comboBoxItem = value; + } + + #endregion + + #region BINDING HELPER + + /// + /// When using Data Binding operations via the DataSource property of the ComboBox. This + /// adds the required Bindings for the CheckBoxes. + /// + public void AddBindings() + { + // Note, the text uses "DisplayMemberSingleItem", not "DisplayMember" (unless its not assigned) + DataBindings.Add("Text", _comboBoxItem, _checkBoxComboBox.DisplayMemberSingleItem); + + // The ValueMember must be a bool type property usable by the CheckBox.Checked. + DataBindings.Add("Checked", _comboBoxItem, _checkBoxComboBox.ValueMember, false, + // This helps to maintain proper selection state in the Binded object, + // even when the controls are added and removed. + DataSourceUpdateMode.OnPropertyChanged, false, null, null); + + // Helps to maintain the Checked status of this + // checkbox before the control is visible + if (_comboBoxItem is INotifyPropertyChanged) + { + ((INotifyPropertyChanged)_comboBoxItem).PropertyChanged += new PropertyChangedEventHandler(CheckBoxComboBoxItem_PropertyChanged); + } + } + + #endregion + + #region PROTECTED MEMBERS + + protected override void OnCheckedChanged(EventArgs e) + { + // Found that when this event is raised, the bool value of the binded item is not yet updated. + if (_checkBoxComboBox.DataSource != null) + { + var pI = ComboBoxItem.GetType().GetProperty(_checkBoxComboBox.ValueMember); + pI.SetValue(ComboBoxItem, Checked, null); + } + + base.OnCheckedChanged(e); + // Forces a refresh of the Text displayed in the main TextBox of the ComboBox, + // since that Text will most probably represent a concatenation of selected values. + // Also see DisplayMemberSingleItem on the CheckBoxComboBox for more information. + if (_checkBoxComboBox.DataSource != null) + { + var oldDisplayMember = _checkBoxComboBox.DisplayMember; + _checkBoxComboBox.DisplayMember = null; + _checkBoxComboBox.DisplayMember = oldDisplayMember; + } + } + + #endregion + + #region HELPER MEMBERS + + internal void ApplyProperties(CheckBoxProperties properties) + { + Appearance = properties.Appearance; + AutoCheck = properties.AutoCheck; + AutoEllipsis = properties.AutoEllipsis; + AutoSize = properties.AutoSize; + CheckAlign = properties.CheckAlign; + FlatAppearance.BorderColor = properties.FlatAppearanceBorderColor; + FlatAppearance.BorderSize = properties.FlatAppearanceBorderSize; + FlatAppearance.CheckedBackColor = properties.FlatAppearanceCheckedBackColor; + FlatAppearance.MouseDownBackColor = properties.FlatAppearanceMouseDownBackColor; + FlatAppearance.MouseOverBackColor = properties.FlatAppearanceMouseOverBackColor; + FlatStyle = properties.FlatStyle; + ForeColor = properties.ForeColor; + RightToLeft = properties.RightToLeft; + TextAlign = properties.TextAlign; + ThreeState = properties.ThreeState; + } + + #endregion + + #region EVENT HANDLERS - ComboBoxItem (DataSource) + + /// + /// Added this handler because the control doesn't seem + /// to initialize correctly until shown for the first + /// time, which also means the summary text value + /// of the combo is out of sync initially. + /// + private void CheckBoxComboBoxItem_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == _checkBoxComboBox.ValueMember) + { + Checked = (bool)_comboBoxItem + .GetType() + .GetProperty(_checkBoxComboBox.ValueMember) + .GetValue(_comboBoxItem, null); + } + } + + #endregion + } +} diff --git a/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxItemList.cs b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxItemList.cs new file mode 100644 index 0000000..29ad5b8 --- /dev/null +++ b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxItemList.cs @@ -0,0 +1,128 @@ +using System.ComponentModel; +using System.Reflection; +using TestTask.Controls.CheckComboBox; + +namespace WatchList.WinForms.Control.CheckComboBox.Component +{ + /// + /// A Typed List of the CheckBox items. + /// Simply a wrapper for the CheckBoxComboBox.Items. A list of CheckBoxComboBoxItem objects. + /// This List is automatically synchronised with the Items of the ComboBox and extended to + /// handle the additional boolean value. That said, do not Add or Remove using this List, + /// it will be lost or regenerated from the ComboBox.Items. + /// + [ToolboxItem(false)] + public class CheckBoxComboBoxItemList : List + { + #region CONSTRUCTORS + + public CheckBoxComboBoxItemList(CheckBoxComboBox checkBoxComboBox) + { + _CheckBoxComboBox = checkBoxComboBox; + } + + #endregion + + #region PRIVATE FIELDS + + private CheckBoxComboBox _CheckBoxComboBox; + + #endregion + + #region EVENTS, This could be moved to the list control if needed + + public event EventHandler CheckBoxCheckedChanged; + + protected void OnCheckBoxCheckedChanged(object sender, EventArgs e) => CheckBoxCheckedChanged?.Invoke(sender, e); + + private void item_CheckedChanged(object sender, EventArgs e) => OnCheckBoxCheckedChanged(sender, e); + + #endregion + + #region LIST MEMBERS & OBSOLETE INDICATORS + + [Obsolete("Do not add items to this list directly. Use the ComboBox items instead.", false)] + public new void Add(CheckBoxComboBoxItem item) + { + item.CheckedChanged += new EventHandler(item_CheckedChanged); + base.Add(item); + } + + public new void AddRange(IEnumerable collection) + { + foreach (var item in collection) + { + item.CheckedChanged += new EventHandler(item_CheckedChanged); + } + + base.AddRange(collection); + } + + public new void Clear() + { + foreach (var item in this) + { + item.CheckedChanged -= item_CheckedChanged; + } + + base.Clear(); + } + + [Obsolete("Do not remove items from this list directly. Use the ComboBox items instead.", false)] + public new bool Remove(CheckBoxComboBoxItem item) + { + item.CheckedChanged -= item_CheckedChanged; + return base.Remove(item); + } + + #endregion + + #region DEFAULT PROPERTIES + + /// + /// Returns the item with the specified displayName or Text. + /// + public CheckBoxComboBoxItem this[string displayName] + { + get + { + // An invisible item exists in this scenario to help with the Text displayed in the TextBox of the Combo + // 1 Ubiklou : 2008-04-28 : Ignore first item. + // (http://www.codeproject.com/KB/combobox/extending_combobox.aspx?fid=476622&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2526813&fr=1#xx2526813xx) + var startIndex = _CheckBoxComboBox.DropDownStyle + == ComboBoxStyle.DropDownList + && _CheckBoxComboBox.DataSource + == null ? 1 : 0; + + for (var Index = startIndex; Index <= Count - 1; Index++) + { + var Item = this[Index]; + + string? text; + + if (string.IsNullOrEmpty(Item.Text) + && Item.DataBindings != null + && Item.DataBindings["Text"] != null) + { + var propertyInfo = Item.ComboBoxItem.GetType() + .GetProperty(Item.DataBindings["Text"].BindingMemberInfo.BindingMember); + text = propertyInfo.GetValue(Item.ComboBoxItem, null) as string; + } + else + { + text = Item.Text; + } + + if (text.CompareTo(displayName) == 0) + { + return Item; + } + } + + throw new ArgumentOutOfRangeException(string.Format("\"{0}\" does not exist in this combo box.", displayName)); + } + } + + #endregion + } +} diff --git a/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxListControl.cs b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxListControl.cs new file mode 100644 index 0000000..206f82f --- /dev/null +++ b/WatchList.WinForms/Control/CheckComboBox/Component/CheckBoxComboBoxListControl.cs @@ -0,0 +1,184 @@ +using System.ComponentModel; +using TestTask.Controls.CheckComboBox; + +namespace WatchList.WinForms.Control.CheckComboBox.Component +{ + /// + /// This ListControl that pops up to the User. It contains the CheckBoxComboBoxItems. + /// The items are docked DockStyle.Top in this control. + /// + [ToolboxItem(false)] + public class CheckBoxComboBoxListControl : ScrollableControl + { + #region CONSTRUCTOR + + public CheckBoxComboBoxListControl(CheckBoxComboBox owner) + : base() + { + DoubleBuffered = true; + + _checkBoxComboBox = owner; + _items = new CheckBoxComboBoxItemList(_checkBoxComboBox); + BackColor = SystemColors.Window; + // AutoScaleMode = AutoScaleMode.Inherit; + AutoScroll = true; + ResizeRedraw = true; + // if you don't set this, a Resize operation causes an error in the base class. + MinimumSize = new Size(1, 1); + MaximumSize = new Size(500, 500); + } + + #endregion + + #region PRIVATE PROPERTIES + + /// + /// Simply a reference to the CheckBoxComboBox. + /// + private CheckBoxComboBox _checkBoxComboBox; + + /// + /// A Typed list of ComboBoxCheckBoxItems. + /// + private CheckBoxComboBoxItemList _items; + + #endregion + + public CheckBoxComboBoxItemList Items { get => _items; } + + #region RESIZE OVERRIDE REQUIRED BY THE POPUP CONTROL + + /// + /// Prescribed by the Popup control to enable Resize operations. + /// + /// + protected override void WndProc(ref Message m) + { + if ((Parent.Parent as Popup).ProcessResizing(ref m)) + { + return; + } + + base.WndProc(ref m); + } + + #endregion + + #region PROTECTED MEMBERS + + [Obsolete] + protected override void OnVisibleChanged(EventArgs e) + { + // Synchronises the CheckBox list with the items in the ComboBox. + SynchroniseControlsWithComboBoxItems(); + base.OnVisibleChanged(e); + } + + /// + /// Maintains the controls displayed in the list by keeping them in sync with the actual + /// items in the combobox. (e.g. removing and adding as well as ordering) + /// + [Obsolete] + public void SynchroniseControlsWithComboBoxItems() + { + SuspendLayout(); + + if (_checkBoxComboBox._mustAddHiddenItem && _checkBoxComboBox.DataSource == null) + { + _checkBoxComboBox.Items.Insert(0, _checkBoxComboBox.GetCSVText(false)); // INVISIBLE ITEM + _checkBoxComboBox.SelectedIndex = 0; + _checkBoxComboBox._mustAddHiddenItem = false; + } + + Controls.Clear(); + + #region Disposes all items that are no longer in the combo box list + + for (var Index = _items.Count - 1; Index >= 0; Index--) + { + var item = _items[Index]; + if (!_checkBoxComboBox.Items.Contains(item.ComboBoxItem)) + { + _items.Remove(item); + item.Dispose(); + } + } + #endregion + + #region Recreate the list in the same order of the combo box items + + var HasHiddenItem = _checkBoxComboBox.DropDownStyle == ComboBoxStyle.DropDownList + && _checkBoxComboBox.DataSource == null + && !DesignMode; + + var NewList = new CheckBoxComboBoxItemList(_checkBoxComboBox); + + for (var index0 = 0; index0 <= _checkBoxComboBox.Items.Count - 1; index0++) + { + var obj = _checkBoxComboBox.Items[index0]; + CheckBoxComboBoxItem? item = null; + + // The hidden item could match any other item when only + // one other item was selected. + if (index0 == 0 && HasHiddenItem && _items.Count > 0) + { + item = _items[0]; + } + else + { + var startIndex = HasHiddenItem + ? 1 // Skip the hidden item, it could match + : 0; + for (var index1 = startIndex; index1 <= _items.Count - 1; index1++) + { + if (_items[index1].ComboBoxItem == obj) + { + item = _items[index1]; + break; + } + } + } + + if (item == null) + { + item = new CheckBoxComboBoxItem(_checkBoxComboBox, obj); + item.ApplyProperties(_checkBoxComboBox.CheckBoxProperties); + } + + NewList.Add(item); + item.Dock = DockStyle.Top; + } + + _items.Clear(); + _items.AddRange(NewList); + + #endregion + #region Add the items to the controls in reversed order to maintain correct docking order + + if (NewList.Count > 0) + { + // This reverse helps to maintain correct docking order. + NewList.Reverse(); + // If you get an error here that "Cannot convert to the desired + // type, it probably means the controls are not binding correctly. + // The Checked property is binded to the ValueMember property. + // It must be a bool for example. + Controls.AddRange(NewList.ToArray()); + } + + #endregion + + // Keep the first item invisible + if (_checkBoxComboBox.DropDownStyle == ComboBoxStyle.DropDownList + && _checkBoxComboBox.DataSource == null + && !DesignMode) + { + _checkBoxComboBox.CheckBoxItems[0].Visible = false; + } + + ResumeLayout(); + } + + #endregion + } +} diff --git a/WatchList.WinForms/Control/CheckComboBox/PopupComboBox.cs b/WatchList.WinForms/Control/CheckComboBox/PopupComboBox.cs index 170e1dd..0c35a99 100644 --- a/WatchList.WinForms/Control/CheckComboBox/PopupComboBox.cs +++ b/WatchList.WinForms/Control/CheckComboBox/PopupComboBox.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using System.Security.Permissions; +using WatchList.WinForms.Control.CheckComboBox.Component; namespace TestTask.Controls.CheckComboBox {