2020-05-11 21:11:29 +08:00
|
|
|
|
/******************************************************************************
|
|
|
|
|
* SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
|
|
|
|
|
* CopyRight (C) 2012-2020 ShenYongHua(沈永华).
|
|
|
|
|
* QQ群:56829229 QQ:17612584 EMail:SunnyUI@qq.com
|
|
|
|
|
*
|
|
|
|
|
* Blog: https://www.cnblogs.com/yhuse
|
|
|
|
|
* Gitee: https://gitee.com/yhuse/SunnyUI
|
|
|
|
|
* GitHub: https://github.com/yhuse/SunnyUI
|
|
|
|
|
*
|
|
|
|
|
* SunnyUI.dll can be used for free under the GPL-3.0 license.
|
|
|
|
|
* If you use this code, please keep this note.
|
|
|
|
|
* 如果您使用此代码,请保留此说明。
|
|
|
|
|
******************************************************************************
|
|
|
|
|
* 文件名称: UIComboBox.cs
|
|
|
|
|
* 文件说明: 组合框
|
|
|
|
|
* 当前版本: V2.2
|
|
|
|
|
* 创建日期: 2020-01-01
|
|
|
|
|
*
|
|
|
|
|
* 2020-01-01: V2.2.0 增加文件说明
|
2020-06-12 20:17:55 +08:00
|
|
|
|
* 2020-06-11: V2.2.5 增加DataSource,支持数据绑定
|
2020-05-11 21:11:29 +08:00
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Drawing.Design;
|
|
|
|
|
using System.Windows.Forms;
|
2020-06-11 23:53:51 +08:00
|
|
|
|
using static System.Windows.Forms.ComboBox;
|
2020-05-11 21:11:29 +08:00
|
|
|
|
|
|
|
|
|
namespace Sunny.UI
|
|
|
|
|
{
|
|
|
|
|
[DefaultProperty("Items")]
|
|
|
|
|
[DefaultEvent("SelectedIndexChanged")]
|
|
|
|
|
[ToolboxItem(true)]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
[LookupBindingProperties("DataSource", "DisplayMember", "ValueMember", "SelectedValue")]
|
2020-05-11 21:11:29 +08:00
|
|
|
|
public sealed partial class UIComboBox : UIDropControl
|
|
|
|
|
{
|
|
|
|
|
public UIComboBox()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
2020-06-11 23:53:51 +08:00
|
|
|
|
|
|
|
|
|
box.SelectedIndexChanged += Box_SelectedIndexChanged;
|
|
|
|
|
box.DataSourceChanged += Box_DataSourceChanged;
|
|
|
|
|
box.DisplayMemberChanged += Box_DisplayMemberChanged;
|
|
|
|
|
box.ValueMemberChanged += Box_ValueMemberChanged;
|
2020-12-28 23:18:33 +08:00
|
|
|
|
DropDownWidth = 150;
|
2020-06-11 23:53:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Box_ValueMemberChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
ValueMemberChanged?.Invoke(sender, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Box_DisplayMemberChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
DisplayMemberChanged?.Invoke(sender, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Box_DataSourceChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
DataSourceChanged?.Invoke(sender, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Box_SelectedIndexChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
Text = box.GetItemText(box.SelectedItem);
|
|
|
|
|
GetSelectedValue();
|
|
|
|
|
SelectedValueChanged?.Invoke(this, e);
|
2020-07-29 20:14:59 +08:00
|
|
|
|
SelectedIndexChanged?.Invoke(this, e);
|
2020-06-11 23:53:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-11 21:11:29 +08:00
|
|
|
|
public event EventHandler SelectedIndexChanged;
|
|
|
|
|
|
2020-06-11 23:53:51 +08:00
|
|
|
|
public event EventHandler DataSourceChanged;
|
|
|
|
|
|
|
|
|
|
public event EventHandler DisplayMemberChanged;
|
|
|
|
|
|
|
|
|
|
public event EventHandler ValueMemberChanged;
|
|
|
|
|
|
|
|
|
|
public event EventHandler SelectedValueChanged;
|
|
|
|
|
|
2020-06-12 20:17:55 +08:00
|
|
|
|
public readonly ComboBox box = new ComboBox();
|
2020-06-11 23:53:51 +08:00
|
|
|
|
|
2020-05-11 21:11:29 +08:00
|
|
|
|
protected override void ItemForm_ValueChanged(object sender, object value)
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
SelectedIndex = ListBox.SelectedIndex;
|
2020-12-19 23:43:03 +08:00
|
|
|
|
Box_SelectedIndexChanged(null, null);
|
2020-05-11 21:11:29 +08:00
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-12 20:17:55 +08:00
|
|
|
|
private readonly UIComboBoxItem dropForm = new UIComboBoxItem();
|
2020-05-11 21:11:29 +08:00
|
|
|
|
|
|
|
|
|
protected override void CreateInstance()
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
ItemForm = new UIDropDown(dropForm);
|
2020-05-11 21:11:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override int CalcItemFormHeight()
|
|
|
|
|
{
|
|
|
|
|
int interval = ItemForm.Height - ItemForm.ClientRectangle.Height;
|
2020-06-12 20:17:55 +08:00
|
|
|
|
return 4 + Math.Min(ListBox.Items.Count, MaxDropDownItems) * ItemHeight + interval;
|
2020-05-11 21:11:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private UIListBox ListBox
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
get => dropForm.ListBox;
|
2020-05-11 21:11:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[DefaultValue(25)]
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("列表项高度"), Category("SunnyUI")]
|
2020-05-11 21:11:29 +08:00
|
|
|
|
public int ItemHeight
|
|
|
|
|
{
|
|
|
|
|
get => ListBox.ItemHeight;
|
|
|
|
|
set => ListBox.ItemHeight = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[DefaultValue(8)]
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("列表下拉最大个数"), Category("SunnyUI")]
|
2020-05-11 21:11:29 +08:00
|
|
|
|
public int MaxDropDownItems { get; set; } = 8;
|
|
|
|
|
|
2020-06-11 23:53:51 +08:00
|
|
|
|
private void UIComboBox_FontChanged(object sender, EventArgs e)
|
2020-05-11 21:11:29 +08:00
|
|
|
|
{
|
2020-06-11 23:53:51 +08:00
|
|
|
|
if (ItemForm != null)
|
2020-05-11 21:11:29 +08:00
|
|
|
|
{
|
2020-06-11 23:53:51 +08:00
|
|
|
|
ListBox.Font = Font;
|
2020-05-11 21:11:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UIComboBox_ButtonClick(object sender, EventArgs e)
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
ListBox.Items.Clear();
|
2020-05-11 21:11:29 +08:00
|
|
|
|
if (Items.Count == 0 || ItemForm.Visible)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-12 20:17:55 +08:00
|
|
|
|
foreach (var data in Items)
|
2020-05-11 21:11:29 +08:00
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
ListBox.Items.Add(GetItemText(data));
|
2020-05-11 21:11:29 +08:00
|
|
|
|
}
|
2020-06-11 23:53:51 +08:00
|
|
|
|
|
|
|
|
|
ListBox.SelectedIndex = SelectedIndex;
|
2020-12-28 23:18:33 +08:00
|
|
|
|
ItemForm.Show(this, new Size(DropDownWidth < Width ? Width : DropDownWidth, CalcItemFormHeight()));
|
2020-05-11 21:11:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void SetStyleColor(UIBaseStyle uiColor)
|
|
|
|
|
{
|
|
|
|
|
base.SetStyleColor(uiColor);
|
|
|
|
|
if (uiColor.IsCustom()) return;
|
|
|
|
|
|
|
|
|
|
ListBox.SetStyleColor(uiColor);
|
|
|
|
|
}
|
2020-06-11 23:53:51 +08:00
|
|
|
|
|
2020-06-12 20:17:55 +08:00
|
|
|
|
private object dataSource;
|
2020-06-11 23:53:51 +08:00
|
|
|
|
|
|
|
|
|
[DefaultValue(null), RefreshProperties(RefreshProperties.Repaint), AttributeProvider(typeof(IListSource))]
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("数据源"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
public object DataSource
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
get => dataSource;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
SetDataConnection(value, new BindingMemberInfo(DisplayMember));
|
|
|
|
|
dataSource = value;
|
|
|
|
|
box.Items.Clear();
|
|
|
|
|
|
2020-07-29 20:14:59 +08:00
|
|
|
|
if (dataManager != null)
|
2020-06-12 20:17:55 +08:00
|
|
|
|
{
|
2020-07-29 20:14:59 +08:00
|
|
|
|
foreach (var obj in dataManager.List)
|
|
|
|
|
{
|
|
|
|
|
box.Items.Add(obj);
|
|
|
|
|
}
|
2020-06-12 20:17:55 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-11 23:53:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-12 20:17:55 +08:00
|
|
|
|
private bool inSetDataConnection;
|
|
|
|
|
private CurrencyManager dataManager;
|
|
|
|
|
|
|
|
|
|
private void SetDataConnection(object newDataSource, BindingMemberInfo newDisplayMember)
|
2020-06-11 23:53:51 +08:00
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
bool dataSourceChanged = dataSource != newDataSource;
|
|
|
|
|
bool displayMemberChanged = !DisplayMember.Equals(newDisplayMember.BindingPath);
|
|
|
|
|
|
|
|
|
|
if (inSetDataConnection)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-07-28 21:01:40 +08:00
|
|
|
|
inSetDataConnection = true;
|
2020-06-12 20:17:55 +08:00
|
|
|
|
if (dataSourceChanged || displayMemberChanged)
|
|
|
|
|
{
|
|
|
|
|
CurrencyManager newDataManager = null;
|
|
|
|
|
if (newDataSource != null && newDataSource != Convert.DBNull)
|
|
|
|
|
{
|
|
|
|
|
newDataManager = (CurrencyManager)BindingContext[newDataSource, newDisplayMember.BindingPath];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dataManager = newDataManager;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
inSetDataConnection = false;
|
|
|
|
|
}
|
2020-06-11 23:53:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-28 23:18:33 +08:00
|
|
|
|
[DefaultValue(150)]
|
|
|
|
|
[Description("下拉框宽度"), Category("SunnyUI")]
|
|
|
|
|
public int DropDownWidth { get; set; }
|
2020-06-11 23:53:51 +08:00
|
|
|
|
|
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
|
|
|
[Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
|
|
|
|
|
[Localizable(true)]
|
|
|
|
|
[MergableProperty(false)]
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("下拉显示项"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
public ObjectCollection Items
|
|
|
|
|
{
|
|
|
|
|
get => box.Items;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("选中索引"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
public int SelectedIndex
|
|
|
|
|
{
|
|
|
|
|
get => box.SelectedIndex;
|
|
|
|
|
set => box.SelectedIndex = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Browsable(false), Bindable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("选中项"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
public object SelectedItem
|
|
|
|
|
{
|
|
|
|
|
get => box.SelectedItem;
|
|
|
|
|
set => box.SelectedItem = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("选中文字"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
public string SelectedText
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (DropDownStyle == UIDropDownStyle.DropDown)
|
|
|
|
|
{
|
|
|
|
|
return edit.SelectedText;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return Text;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-11 23:53:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void ResetText()
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
Clear();
|
2020-06-11 23:53:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("获取或设置要为此列表框显示的属性。"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
[DefaultValue("")]
|
|
|
|
|
[Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
|
|
|
|
|
[TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
|
|
|
|
|
public string DisplayMember
|
|
|
|
|
{
|
|
|
|
|
get => box.DisplayMember;
|
2020-06-12 20:17:55 +08:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
SetDataConnection(dataSource, new BindingMemberInfo(value));
|
|
|
|
|
box.DisplayMember = value;
|
|
|
|
|
}
|
2020-06-11 23:53:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("获取或设置指示显示值的方式的格式说明符字符。"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
[DefaultValue("")]
|
|
|
|
|
[Editor("System.Windows.Forms.Design.FormatStringEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
|
|
|
|
|
[MergableProperty(false)]
|
|
|
|
|
public string FormatString
|
|
|
|
|
{
|
|
|
|
|
get => box.FormatString;
|
|
|
|
|
set => box.FormatString = value;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("获取或设置指示显示值是否可以进行格式化操作。"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
[DefaultValue(false)]
|
|
|
|
|
public bool FormattingEnabled
|
|
|
|
|
{
|
|
|
|
|
get => box.FormattingEnabled;
|
|
|
|
|
set => box.FormattingEnabled = value;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 21:55:50 +08:00
|
|
|
|
[Description("获取或设置要为此列表框实际值的属性。"), Category("SunnyUI")]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
[DefaultValue("")]
|
|
|
|
|
[Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
|
|
|
|
|
public string ValueMember
|
|
|
|
|
{
|
|
|
|
|
get => box.ValueMember;
|
|
|
|
|
set => box.ValueMember = value;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-12 20:17:55 +08:00
|
|
|
|
private object selectedValue;
|
|
|
|
|
|
|
|
|
|
private void GetSelectedValue()
|
|
|
|
|
{
|
|
|
|
|
if (SelectedIndex != -1 && dataManager != null)
|
|
|
|
|
{
|
|
|
|
|
selectedValue = FilterItemOnProperty(SelectedItem, ValueMember);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
selectedValue = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-11 23:53:51 +08:00
|
|
|
|
[
|
2020-06-12 20:17:55 +08:00
|
|
|
|
DefaultValue(null),
|
|
|
|
|
Browsable(false),
|
|
|
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
|
|
|
|
|
Bindable(true)
|
|
|
|
|
]
|
2020-06-11 23:53:51 +08:00
|
|
|
|
public object SelectedValue
|
|
|
|
|
{
|
2020-06-12 20:17:55 +08:00
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
GetSelectedValue();
|
|
|
|
|
return selectedValue;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
selectedValue = value;
|
|
|
|
|
|
|
|
|
|
if (value == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataManager != null)
|
|
|
|
|
{
|
|
|
|
|
int index = DataManagerFind(value);
|
|
|
|
|
SelectedIndex = index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int DataManagerFind(object value)
|
|
|
|
|
{
|
|
|
|
|
if (dataManager == null) return -1;
|
|
|
|
|
for (int i = 0; i < dataManager.List.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var item = dataManager.List[i];
|
|
|
|
|
if (FilterItemOnProperty(item, ValueMember).Equals(value))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private object FilterItemOnProperty(object item, string field)
|
|
|
|
|
{
|
|
|
|
|
if (item != null && field.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// if we have a dataSource, then use that to display the string
|
|
|
|
|
PropertyDescriptor descriptor;
|
|
|
|
|
if (dataManager != null)
|
|
|
|
|
descriptor = dataManager.GetItemProperties().Find(field, true);
|
|
|
|
|
else
|
|
|
|
|
descriptor = TypeDescriptor.GetProperties(item).Find(field, true);
|
|
|
|
|
|
|
|
|
|
if (descriptor != null)
|
|
|
|
|
{
|
|
|
|
|
item = descriptor.GetValue(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return item;
|
2020-06-11 23:53:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string GetItemText(object item)
|
|
|
|
|
{
|
|
|
|
|
return box.GetItemText(item);
|
|
|
|
|
}
|
2020-05-11 21:11:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|