/*******************************************************************************
* Copyright(c) 2014 DongkeSoft All rights reserved. / Confidential
* 类的信息:
* 1.程序名称:ObjectSelectionWrapper.cs
* 2.功能描述:下拉用户控件
* 编辑履历:
* 作者 日期 版本 修改内容
* 陈晓野 2014/09/29 1.00 新建
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
namespace Dongke.IBOSS.PRD.Basics.BaseControls
{
///
/// Martin Lottering : 2007-10-27
/// --------------------------------
/// This is a usefull control in Filters. Allows you to save space and can replace a Grouped Box of CheckBoxes.
/// Currently used on the TasksFilter for TaskStatusses, which means the user can select which Statusses to include
/// in the "Search".
/// This control does not implement a CheckBoxListBox, instead it adds a wrapper for the normal ComboBox and Items.
/// See the CheckBoxItems property.
/// ----------------
/// ALSO IMPORTANT: In Data Binding when setting the DataSource. The ValueMember must be a bool type property, because it will
/// be binded to the Checked property of the displayed CheckBox. Also see the DisplayMemberSingleItem for more information.
/// ----------------
/// Extends the CodeProject PopupComboBox "Simple pop-up control" "http://www.codeproject.com/cs/miscctrl/simplepopup.asp"
/// by Lukasz Swiatkowski.
///
public partial class DKCheckBoxComboBox : PopupComboBox
{
#region CONSTRUCTOR
public DKCheckBoxComboBox()
: base()
{
InitializeComponent();
_CheckBoxProperties = new CheckBoxProperties();
_CheckBoxProperties.PropertyChanged += new EventHandler(_CheckBoxProperties_PropertyChanged);
// Dumps the ListControl in a(nother) Container to ensure the ScrollBar on the ListControl does not
// Paint over the Size grip. Setting the Padding or Margin on the Popup or host control does
// not work as I expected. I don't think it can work that way.
CheckBoxComboBoxListControlContainer ContainerControl = new CheckBoxComboBoxListControlContainer();
_CheckBoxComboBoxListControl = new CheckBoxComboBoxListControl(this);
_CheckBoxComboBoxListControl.Items.CheckBoxCheckedChanged += new EventHandler(Items_CheckBoxCheckedChanged);
ContainerControl.Controls.Add(_CheckBoxComboBoxListControl);
// This padding spaces neatly on the left-hand side and allows space for the size grip at the bottom.
ContainerControl.Padding = new Padding(4, 0, 0, 14);
// The ListControl FILLS the ListContainer.
_CheckBoxComboBoxListControl.Dock = DockStyle.Fill;
// The DropDownControl used by the base class. Will be wrapped in a popup by the base class.
DropDownControl = ContainerControl;
// Must be set after the DropDownControl is set, since the popup is recreated.
// NOTE: I made the dropDown protected so that it can be accessible here. It was private.
dropDown.Resizable = true;
//DropDownStyle = ComboBoxStyle.DropDownList;
//ReadOnly = true;
DisplayMemberSingleItem = "Name";
DisplayMember = "NameConcatenated";
ValueMember = "Selected";
}
#endregion
#region PRIVATE PROPERTIES
///
/// The checkbox list control. The public CheckBoxItems property provides a direct reference to its Items.
///
private CheckBoxComboBoxListControl _CheckBoxComboBoxListControl;
///
/// In DataBinding operations, this property will be used as the DisplayMember in the CheckBoxComboBoxListBox.
/// The normal/existing "DisplayMember" property is used by the TextBox of the ComboBox to display
/// a concatenated Text of the items selected. This concatenation and its formatting however is controlled
/// by the Binded object, since it owns that property.
///
private string _DisplayMemberSingleItem = null;
#endregion
#region PUBLIC PROPERTIES
///
/// A direct reference to the Items of CheckBoxComboBoxListControl.
/// You can use it to Get or Set the Checked status of items manually if you want.
/// But do not manipulate the List itself directly, e.g. Adding and Removing,
/// since the list is synchronised when shown with the ComboBox.Items. So for changing
/// the list contents, use Items instead.
///
[Browsable(false)]
public CheckBoxComboBoxItemList CheckBoxItems
{
get { return _CheckBoxComboBoxListControl.Items; }
}
///
/// The DataSource of the combobox. Refreshes the CheckBox wrappers when this is set.
///
public new object DataSource
{
get { return base.DataSource; }
set
{
base.DataSource = value;
if (!string.IsNullOrEmpty(ValueMember))
// This ensures that at least the checkboxitems are available to be initialised.
_CheckBoxComboBoxListControl.SynchroniseControlsWithComboBoxItems();
}
}
///
/// The ValueMember of the combobox. Refreshes the CheckBox wrappers when this is set.
///
public new string ValueMember
{
get { return base.ValueMember; }
set
{
base.ValueMember = value;
if (!string.IsNullOrEmpty(ValueMember))
// This ensures that at least the checkboxitems are available to be initialised.
_CheckBoxComboBoxListControl.SynchroniseControlsWithComboBoxItems();
}
}
///
/// In DataBinding operations, this property will be used as the DisplayMember in the CheckBoxComboBoxListBox.
/// The normal/existing "DisplayMember" property is used by the TextBox of the ComboBox to display
/// a concatenated Text of the items selected. This concatenation however is controlled by the Binded
/// object, since it owns that property.
///
public string DisplayMemberSingleItem
{
get { if (string.IsNullOrEmpty(_DisplayMemberSingleItem)) return DisplayMember; else return _DisplayMemberSingleItem; }
set { _DisplayMemberSingleItem = value; }
}
///
/// Made this property Browsable again, since the Base Popup hides it. This class uses it again.
/// Gets an object representing the collection of the items contained in this
/// System.Windows.Forms.ComboBox.
///
/// A System.Windows.Forms.ComboBox.ObjectCollection representing the items in
/// the System.Windows.Forms.ComboBox.
///
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public new ObjectCollection Items
{
get { return base.Items; }
}
#endregion
#region EVENTS & EVENT HANDLERS
public event EventHandler CheckBoxCheckedChanged;
private void Items_CheckBoxCheckedChanged(object sender, EventArgs e)
{
OnCheckBoxCheckedChanged(sender, e);
}
#endregion
#region EVENT CALLERS and OVERRIDES e.g. OnResize()
protected void OnCheckBoxCheckedChanged(object sender, EventArgs e)
{
if (DropDownStyle != ComboBoxStyle.DropDownList)
{
string ListText = "";
foreach (DKCheckBoxComboBoxItem Item in _CheckBoxComboBoxListControl.Items)
if (Item.Checked)
ListText += string.IsNullOrEmpty(ListText) ? Item.Text : String.Format(", {0}", Item.Text);
Text = ListText;
}
EventHandler handler = CheckBoxCheckedChanged;
if (handler != null)
handler(sender, e);
}
protected override void OnResize(EventArgs e)
{
// When the ComboBox is resized, the width of the dropdown
// is also resized to match the width of the ComboBox. I think it looks better.
Size Size = new Size(Width, DropDownControl.Height);
dropDown.Size = Size;
base.OnResize(e);
}
#endregion
#region HELPER MEMBERS
///
/// Uncheck all items.
///
public void ClearSelection()
{
foreach (DKCheckBoxComboBoxItem Item in CheckBoxItems)
if (Item.Checked)
Item.Checked = false;
}
#endregion
#region CHECKBOX PROPERTIES (DEFAULTS)
private CheckBoxProperties _CheckBoxProperties;
///
/// The properties that will be assigned to the checkboxes as default values.
///
[Description("The properties that will be assigned to the checkboxes as default values.")]
[Browsable(true)]
public CheckBoxProperties CheckBoxProperties
{
get { return _CheckBoxProperties; }
set { _CheckBoxProperties = value; _CheckBoxProperties_PropertyChanged(this, EventArgs.Empty); }
}
private void _CheckBoxProperties_PropertyChanged(object sender, EventArgs e)
{
foreach (DKCheckBoxComboBoxItem Item in CheckBoxItems)
Item.ApplyProperties(CheckBoxProperties);
}
#endregion
}
///
/// A container control for the ListControl to ensure the ScrollBar on the ListControl does not
/// Paint over the Size grip. Setting the Padding or Margin on the Popup or host control does
/// not work as I expected.
///
[ToolboxItem(false)]
public class CheckBoxComboBoxListControlContainer : UserControl
{
#region CONSTRUCTOR
public CheckBoxComboBoxListControlContainer()
: base()
{
BackColor = SystemColors.Window;
BorderStyle = BorderStyle.FixedSingle;
AutoScaleMode = AutoScaleMode.Inherit;
ResizeRedraw = true;
// If you don't set this, then resize operations cause an error in the base class.
MinimumSize = new Size(1, 1);
MaximumSize = new Size(500, 500);
}
#endregion
#region RESIZE OVERRIDE REQUIRED BY THE POPUP CONTROL
///
/// Prescribed by the Popup class to ensure Resize operations work correctly.
///
///
protected override void WndProc(ref Message m)
{
if ((Parent as Popup).ProcessResizing(ref m))
{
return;
}
base.WndProc(ref m);
}
#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(DKCheckBoxComboBox owner)
: base()
{
DoubleBuffered = true;
_CheckBoxComboBox = owner;
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 DKCheckBoxComboBox _CheckBoxComboBox;
///
/// A Typed list of ComboBoxCheckBoxItems.
///
private CheckBoxComboBoxItemList _Items = new CheckBoxComboBoxItemList();
#endregion
public CheckBoxComboBoxItemList Items { get { return _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
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)
///
public void SynchroniseControlsWithComboBoxItems()
{
SuspendLayout();
Controls.Clear();
#region Disposes all items that are no longer in the combo box list
for (int Index = _Items.Count - 1; Index >= 0; Index--)
{
DKCheckBoxComboBoxItem 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
CheckBoxComboBoxItemList NewList = new CheckBoxComboBoxItemList();
foreach (object Object in _CheckBoxComboBox.Items)
{
DKCheckBoxComboBoxItem Item = _Items.Find(new Predicate(
delegate(DKCheckBoxComboBoxItem target)
{
return target.ComboBoxItem == Object;
}));
if (Item == null)
{
Item = new DKCheckBoxComboBoxItem(_CheckBoxComboBox, Object);
Item.ApplyProperties(_CheckBoxComboBox.CheckBoxProperties);
// Item.TextAlign = ContentAlignment.MiddleCenter;
}
NewList.Add(Item);
Item.Dock = DockStyle.Top;
}
//NewList.CheckBoxCheckedChanged += _Items.CheckBoxCheckedChanged;
_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
ResumeLayout();
}
#endregion
}
///
/// The CheckBox items displayed in the Popup of the ComboBox.
///
[ToolboxItem(false)]
public class DKCheckBoxComboBoxItem : CheckBox
{
#region CONSTRUCTOR
///
///
///
/// A reference to the CheckBoxComboBox.
/// A reference to the item in the ComboBox.Items that this object is extending.
public DKCheckBoxComboBoxItem(DKCheckBoxComboBox 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 DKCheckBoxComboBox _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 { return _ComboBoxItem; }
}
#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);
}
#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)
{
this.Appearance = properties.Appearance;
this.AutoCheck = properties.AutoCheck;
this.AutoEllipsis = properties.AutoEllipsis;
this.AutoSize = properties.AutoSize;
this.CheckAlign = properties.CheckAlign;
this.FlatAppearance.BorderColor = properties.FlatAppearanceBorderColor;
this.FlatAppearance.BorderSize = properties.FlatAppearanceBorderSize;
this.FlatAppearance.CheckedBackColor = properties.FlatAppearanceCheckedBackColor;
this.FlatAppearance.MouseDownBackColor = properties.FlatAppearanceMouseDownBackColor;
this.FlatAppearance.MouseOverBackColor = properties.FlatAppearanceMouseOverBackColor;
this.FlatStyle = properties.FlatStyle;
this.ForeColor = properties.ForeColor;
this.RightToLeft = properties.RightToLeft;
this.TextAlign = properties.TextAlign;
this.ThreeState = properties.ThreeState;
}
#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 EVENTS, This could be moved to the list control if needed
public event EventHandler CheckBoxCheckedChanged;
protected void OnCheckBoxCheckedChanged(object sender, EventArgs e)
{
EventHandler handler = CheckBoxCheckedChanged;
if (handler != null)
handler(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(DKCheckBoxComboBoxItem item)
{
item.CheckedChanged += new EventHandler(item_CheckedChanged);
base.Add(item);
}
public new void AddRange(IEnumerable collection)
{
foreach (DKCheckBoxComboBoxItem Item in collection)
Item.CheckedChanged += new EventHandler(item_CheckedChanged);
base.AddRange(collection);
}
public new void Clear()
{
foreach (DKCheckBoxComboBoxItem 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(DKCheckBoxComboBoxItem item)
{
item.CheckedChanged -= item_CheckedChanged;
return base.Remove(item);
}
#endregion
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class CheckBoxProperties
{
public CheckBoxProperties() { }
#region PRIVATE PROPERTIES
private Appearance _Appearance = Appearance.Normal;
private bool _AutoSize = false;
private bool _AutoCheck = true;
private bool _AutoEllipsis = false;
private ContentAlignment _CheckAlign = ContentAlignment.MiddleLeft;
private Color _FlatAppearanceBorderColor = Color.Empty;
private int _FlatAppearanceBorderSize = 1;
private Color _FlatAppearanceCheckedBackColor = Color.Empty;
private Color _FlatAppearanceMouseDownBackColor = Color.Empty;
private Color _FlatAppearanceMouseOverBackColor = Color.Empty;
private FlatStyle _FlatStyle = FlatStyle.Standard;
private Color _ForeColor = SystemColors.ControlText;
private RightToLeft _RightToLeft = RightToLeft.No;
private ContentAlignment _TextAlign = ContentAlignment.MiddleLeft;
private bool _ThreeState = false;
#endregion
#region PUBLIC PROPERTIES
[DefaultValue(Appearance.Normal)]
public Appearance Appearance
{
get { return _Appearance; }
set { _Appearance = value; OnPropertyChanged(); }
}
[DefaultValue(true)]
public bool AutoCheck
{
get { return _AutoCheck; }
set { _AutoCheck = value; OnPropertyChanged(); }
}
[DefaultValue(false)]
public bool AutoEllipsis
{
get { return _AutoEllipsis; }
set { _AutoEllipsis = value; OnPropertyChanged(); }
}
[DefaultValue(false)]
public bool AutoSize
{
get { return _AutoSize; }
set { _AutoSize = true; OnPropertyChanged(); }
}
[DefaultValue(ContentAlignment.MiddleLeft)]
public ContentAlignment CheckAlign
{
get { return _CheckAlign; }
set { _CheckAlign = value; OnPropertyChanged(); }
}
[DefaultValue(typeof(Color), "")]
public Color FlatAppearanceBorderColor
{
get { return _FlatAppearanceBorderColor; }
set { _FlatAppearanceBorderColor = value; OnPropertyChanged(); }
}
[DefaultValue(1)]
public int FlatAppearanceBorderSize
{
get { return _FlatAppearanceBorderSize; }
set { _FlatAppearanceBorderSize = value; OnPropertyChanged(); }
}
[DefaultValue(typeof(Color), "")]
public Color FlatAppearanceCheckedBackColor
{
get { return _FlatAppearanceCheckedBackColor; }
set { _FlatAppearanceCheckedBackColor = value; OnPropertyChanged(); }
}
[DefaultValue(typeof(Color), "")]
public Color FlatAppearanceMouseDownBackColor
{
get { return _FlatAppearanceMouseDownBackColor; }
set { _FlatAppearanceMouseDownBackColor = value; OnPropertyChanged(); }
}
[DefaultValue(typeof(Color), "")]
public Color FlatAppearanceMouseOverBackColor
{
get { return _FlatAppearanceMouseOverBackColor; }
set { _FlatAppearanceMouseOverBackColor = value; OnPropertyChanged(); }
}
[DefaultValue(FlatStyle.Standard)]
public FlatStyle FlatStyle
{
get { return _FlatStyle; }
set { _FlatStyle = value; OnPropertyChanged(); }
}
[DefaultValue(typeof(SystemColors), "ControlText")]
public Color ForeColor
{
get { return _ForeColor; }
set { _ForeColor = value; OnPropertyChanged(); }
}
[DefaultValue(RightToLeft.No)]
public RightToLeft RightToLeft
{
get { return _RightToLeft; }
set { _RightToLeft = value; OnPropertyChanged(); }
}
[DefaultValue(ContentAlignment.MiddleLeft)]
public ContentAlignment TextAlign
{
get { return _TextAlign; }
set { _TextAlign = value; OnPropertyChanged(); }
}
[DefaultValue(false)]
public bool ThreeState
{
get { return _ThreeState; }
set { _ThreeState = value; OnPropertyChanged(); }
}
#endregion
#region EVENTS AND EVENT CALLERS
///
/// Called when any property changes.
///
public event EventHandler PropertyChanged;
protected void OnPropertyChanged()
{
EventHandler handler = PropertyChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
#endregion
}
}