using System; using System.ComponentModel; using System.Data; using System.Drawing; using System.Windows.Forms; using Dongke.WinForm.Utilities; namespace Dongke.WinForm.Controls { /// /// 标准下拉框控件 /// [ToolboxBitmap(typeof(ComboBox))] public class CmbComboBox : ComboBox, IDKControl, IDataVerifiable, IAsyncControl, IChildNativeWindow { #region 内部类 #endregion #region 事件声明 #region HasErrorChanged /// /// 当 HasError 属性的值更改时发生。 /// private static readonly object EventHasErrorChanged = new object(); /// /// 当 HasError 属性的值更改时发生。 /// [Description("当 HasError 属性的值更改时发生。"), Category("CustomerEx")] public event EventHandler HasErrorChanged { add { base.Events.AddHandler(EventHasErrorChanged, value); } remove { base.Events.RemoveHandler(EventHasErrorChanged, value); } } /// /// 引发 HasErrorChanged 事件 /// /// 包含事件数据的 EventArgs protected virtual void OnHasErrorChanged(EventArgs e) { EventHandler eventHandler = (EventHandler)base.Events[EventHasErrorChanged]; if (eventHandler != null) { eventHandler(this, e); } } #endregion #region ReadOnlyChanged /// /// 当 ReadOnly 属性的值更改时发生。 /// private static readonly object EventReadOnlyChanged = new object(); /// /// 当 ReadOnly 属性的值更改时发生 /// [Description("当 ReadOnly 属性的值更改时发生。"), Category("CustomerEx")] public event EventHandler ReadOnlyChanged { add { base.Events.AddHandler(EventReadOnlyChanged, value); } remove { base.Events.RemoveHandler(EventReadOnlyChanged, value); } } /// /// 引发 ReadOnlyChanged 事件 /// /// protected virtual void OnReadOnlyChanged(EventArgs e) { EventHandler eventHandler = base.Events[EventReadOnlyChanged] as EventHandler; if (eventHandler != null) { eventHandler(this, e); } } #endregion #region EditReadOnlyChanged /// /// 当 EditReadOnly 属性的值更改时发生。 /// private static readonly object EventEditReadOnlyChanged = new object(); /// /// 当 EditReadOnly 属性的值更改时发生 /// [Description("当 EditReadOnly 属性的值更改时发生。"), Category("CustomerEx")] public event EventHandler EditReadOnlyChanged { add { base.Events.AddHandler(EventEditReadOnlyChanged, value); } remove { base.Events.RemoveHandler(EventEditReadOnlyChanged, value); } } /// /// 引发 EditReadOnlyChanged 事件 /// /// protected virtual void OnEditReadOnlyChanged(EventArgs e) { EventHandler eventHandler = base.Events[EventEditReadOnlyChanged] as EventHandler; if (eventHandler != null) { eventHandler(this, e); } } #endregion #endregion #region 成员变量 /// /// 焦点是否进入控件 /// private bool _entered = false; /// /// 鼠标是否进入控件 /// private bool _mouseOver = false; /// /// 边框颜色 /// private Color? _borderColor = null; /// /// 边框样式 /// private BorderStyle _borderStyle = BorderStyle.Fixed3D; /// /// 指示控件中的文本是否为只读 /// private bool _editReadOnly = true; /// /// 指示控件中是否为只读 /// private bool _readOnly = false; /// /// ComboBox内部的Edit /// private ChildNativeWindow _childEdit = null; private bool _hasNullData = false; #endregion #region 构造函数 /// /// 标准复选框列表控件 /// public CmbComboBox() { base.FormattingEnabled = false; CommonSetting.InitControls(this); } #endregion #region 属性 /// /// 获取一个值,该值指示控件是否有输入焦点。 /// [DefaultValue(false)] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [EditorBrowsable(EditorBrowsableState.Advanced)] public virtual bool Entered { get { return this._entered; } protected set { if (this._entered != value) { this._entered = value; this.InvalidateBorder(); } } } /// /// 获取一个值,该值指示鼠标是否在控件上方。 /// [DefaultValue(false)] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [EditorBrowsable(EditorBrowsableState.Advanced)] public virtual bool MouseOver { get { return this._mouseOver; } protected set { if (this._mouseOver != value) { this._mouseOver = value; this.InvalidateBorder(); } } } /// /// 获取或设置控件四周绘制的边框的类型 /// [Description("获取或设置控件四周绘制的边框的类型。"), Category("CustomerEx")] [DefaultValue(BorderStyle.Fixed3D)] //[Browsable(false)] //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] //[EditorBrowsable(EditorBrowsableState.Advanced)] public virtual BorderStyle BorderStyle { get { return this._borderStyle; } set { if (!Enum.IsDefined(typeof(BorderStyle), value)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(BorderStyle)); } if (this._borderStyle != value) { this._borderStyle = value; base.UpdateStyles(); base.RecreateHandle(); this.InvalidateBorder(); } } } /// /// 获取或设置一个值,该值指示此控件是否只读。 /// [Description("获取或设置一个值,该值指示此控件是否只读。"), Category("CustomerEx")] [DefaultValue(false)] public virtual bool ReadOnly { get { return this._readOnly; } set { if (this._readOnly != value) { this._readOnly = value; this.SetEditReadOnly(); this.OnReadOnlyChanged(EventArgs.Empty); } } } /// /// 获取或设置一个值,该值指示文本框中的文本是否为只读。 /// [Description("获取或设置一个值,该值指示文本框中的文本是否为只读。"), Category("CustomerEx")] [DefaultValue(true)] public virtual bool EditReadOnly { get { return this._editReadOnly; } set { if (this._editReadOnly != value) { this._editReadOnly = value; this.SetEditReadOnly(); this.OnEditReadOnlyChanged(EventArgs.Empty); } } } /// /// 获取或设置一个值,该值指示是否向数据源中插入null选项(数据源为DataTable)。 /// [Description("获取或设置一个值,该值指示是否向数据源中插入null选项(数据源为DataTable)。"), Category("CustomerEx")] [DefaultValue(false)] public virtual bool HasNullData { get { return this._hasNullData; } set { if (this._hasNullData != value) { this._hasNullData = value; this.SetNullData(this.DataSource, true); } } } #endregion #region 重写属性 /// /// 获取或设置控件的数据源 /// [Description("获取或设置控件的数据源。"), Category("ListControl")] [AttributeProvider(typeof(IListSource))] [DefaultValue(null)] [RefreshProperties(RefreshProperties.Repaint)] public new virtual object DataSource { get { return base.DataSource; } set { this.SetNullData(value, false); base.DataSource = value; } } #endregion #region 重写事件 #region 属性改变 /// /// 句柄创建时 /// /// protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); if (this._childEdit != null) { return; } //if (this.DropDownStyle != ComboBoxStyle.DropDownList) //{ // IntPtr window = WindowsAPI.GetWindow(new HandleRef(this, base.Handle), 5); // if (window != IntPtr.Zero) // { // if (this.DropDownStyle == ComboBoxStyle.Simple) // { // NativeWindow childListBox = new CmbComboBox.ComboBoxChildEditNativeWindow(this); // childListBox.AssignHandle(window); // window = WindowsAPI.GetWindow(new HandleRef(this, window), 2); // } // this._childEdit = new CmbComboBox.ComboBoxChildEditNativeWindow(this); // this._childEdit.AssignHandle(window); // } //} IntPtr window = WindowsAPI.FindWindowEx(base.Handle, IntPtr.Zero, "Edit", ""); this._childEdit = new ChildNativeWindow(this, "Edit"); this._childEdit.AssignHandle(window); this.SetEditReadOnly(); } /// /// 选择项目改变 /// /// protected override void OnSelectedIndexChanged(EventArgs e) { this.SetDefaultOnCheck(); base.OnSelectedIndexChanged(e); this.ValidateData(); } /// /// 数据源改变事件 /// /// protected override void OnDataSourceChanged(EventArgs e) { base.OnDataSourceChanged(e); } #endregion #region 行为事件 #endregion #region 键盘事件 /// /// 键盘点击 /// /// protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); if (this._readOnly) { switch (e.KeyCode) { case Keys.Up: case Keys.Down: case Keys.PageUp: case Keys.PageDown: case Keys.Back: case Keys.Delete: e.Handled = true; break; default: break; } return; } if (this._editReadOnly) { if (e.KeyCode == Keys.Delete || e.KeyCode == Keys.Back) { if (!this._mustInput) { this.ClearValue(); } e.Handled = true; return; } } if (this.Items.Count > 0) { if (e.KeyCode == Keys.Up && this.SelectedIndex < 1) { this.SelectPrevItem(); this.SelectAll(); e.Handled = true; return; } if (e.KeyCode == Keys.Down && (this.SelectedIndex < 1 || this.SelectedIndex == this.Items.Count - 1)) { this.SelectNextItem(); this.SelectAll(); e.Handled = true; return; } } } #endregion #region 焦点事件 /// /// 输入焦点进入控件 /// /// protected override void OnEnter(EventArgs e) { this.Entered = true; base.OnEnter(e); } /// /// 获得焦点 /// /// protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); } /// /// 失去焦点 /// /// protected override void OnLostFocus(EventArgs e) { base.OnLostFocus(e); } /// /// 输入焦点离开控件 /// /// protected override void OnLeave(EventArgs e) { base.OnLeave(e); //this.Entered = false; } /// /// 控件正在验证 /// /// protected override void OnValidating(CancelEventArgs e) { base.OnValidating(e); if (this.HasError && !this._canLostFocusOnError) { e.Cancel = true; } } /// /// 控件完成验证 /// /// protected override void OnValidated(EventArgs e) { this.Entered = false; base.OnValidated(e); } #endregion #region 鼠标事件 /// /// 鼠标进入控件 /// /// protected override void OnMouseEnter(EventArgs e) { this.MouseOver = true; base.OnMouseEnter(e); } /// /// 鼠标离开控件 /// /// protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); this.MouseOver = false; } /// /// 鼠标移动 /// /// protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); } /// /// 鼠标按下 /// /// protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); } /// /// 鼠标抬起 /// /// protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); } /// /// 鼠标滚轮滚动 /// /// protected override void OnMouseWheel(MouseEventArgs e) { base.OnMouseWheel(e); if (this._readOnly) { return; } if (this.DropDownStyle == ComboBoxStyle.Simple && this.Items.Count > 0) { if (e.Delta > 0) { this.SelectPrevItem(); } else { this.SelectNextItem(); } } } #endregion #endregion #region 重写方法 /// /// 处理 Windows 消息 /// /// 要处理的 Windows System.Windows.Forms.Message protected override void WndProc(ref Message m) { if (this._readOnly) { if (m.Msg == (int)WindowsMessage.WM_LBUTTONDBLCLK || m.Msg == (int)WindowsMessage.WM_LBUTTONDOWN) { return; } } base.WndProc(ref m); if (m.Msg == (int)WindowsMessage.WM_NCDESTROY) { this.ReleaseChildWindow(); return; } if (m.Msg == (int)WindowsMessage.WM_PAINT || m.Msg == (int)WindowsMessage.WM_NCPAINT || m.Msg == (int)WindowsMessage.WM_CTLCOLOREDIT) { BorderColorPaint.WmBorderPaint(this._borderColor, this.Width, this.Height, ref m); return; } } #endregion #region 公有方法 /// /// 初始化显示的值 /// /// /// public DataRow InitValue(string text, object value) { if (this.DataManager == null) { if (this.Items.Count > 0) { foreach (object item in this.Items) { string t = this.GetItemText(item); if (t == text) { this.SelectedItem = item; return null; } } } this.Items.Insert(0, value); this.SelectedIndex = 0; //this.Text = text; return null; } DataTable data = this.DataSource as DataTable; if (data == null) { return null; } if (value == null) { value = DBNull.Value; } foreach (DataRow item in data.Rows) { object v = item[this.ValueMember]; if (value.Equals(v)) { this.SelectedValue = v; return null; } } DataRow row = data.NewRow(); row[this.ValueMember] = value; row[this.DisplayMember] = text + "【停用】"; if (this.HasNullData) { data.Rows.InsertAt(row, 1); this.SelectedIndex = 1; } else { data.Rows.InsertAt(row, 0); this.SelectedIndex = 0; } return row; } /// /// 选择下一个Item /// /// 是否能选择空 public void SelectNextItem(bool clearSelect = true) { int boxItemCount = this.Items.Count; if (boxItemCount < 1) { return; } int boxSelectedIndex = this.SelectedIndex; boxSelectedIndex++; if (boxSelectedIndex >= boxItemCount) { if (this._mustInput || !clearSelect || this._hasNullData) { boxSelectedIndex = 0; } else { boxSelectedIndex = -1; } } //if (boxSelectedIndex < 0) //{ // //this.ClearSelected(); //} //else { this.SelectedIndex = boxSelectedIndex; } } /// /// 选择上一个Item /// /// 是否能选择空 public void SelectPrevItem(bool clearSelect = true) { int boxItemCount = this.Items.Count; if (boxItemCount < 1) { return; } int boxSelectedIndex = this.SelectedIndex; boxSelectedIndex--; if (boxSelectedIndex < -1 || ((this._mustInput || !clearSelect || this._hasNullData) && boxSelectedIndex < 0)) { boxSelectedIndex = boxItemCount - 1; } //if (boxSelectedIndex < 0) //{ // this.ClearSelected(); //} //else { this.SelectedIndex = boxSelectedIndex; } } #endregion #region 内部方法 /// /// 处理ComboBox内部Edit的消息 /// /// Edit /// 消息 /// 消息是否已经处理过 public virtual bool ChildWndProc(ChildNativeWindow child, ref Message m) { if (this._editReadOnly || this._readOnly) { if (m.Msg == (int)WindowsMessage.WM_PASTE) { WindowsAPI.MessageBeep(BeepType.MB_OK); return true; } if (m.Msg == (int)WindowsMessage.WM_CUT) { if (this.SelectionLength > 0) { Clipboard.SetText(this.SelectedText); } WindowsAPI.MessageBeep(BeepType.MB_OK); return true; } if (m.Msg == (int)WindowsMessage.WM_CHAR) { int wp = m.WParam.ToInt32(); // = Cut(0x18) if (wp == 0x18) { if (this.SelectionLength > 0) { Clipboard.SetText(this.SelectedText); } WindowsAPI.MessageBeep(BeepType.MB_OK); return true; } // = Copy(0x3) esc(27) enter(13) if (wp == 0x3 || wp == 27 || wp == 13) { return false; } // back(8) else if (wp == 8) { return this._readOnly; } else { WindowsAPI.MessageBeep(BeepType.MB_OK); return true; } } } if (m.Msg == (int)WindowsMessage.WM_LBUTTONDBLCLK) { this.OnDoubleClick(EventArgs.Empty); } return false; } #endregion #region 保护方法 /// /// 引发 System.Windows.Forms.Control.KeyDown 事件。 /// /// protected virtual void OnComBoxKeyDown(KeyEventArgs e) { base.OnKeyDown(e); } /// /// 输入验证时,设定默认值。 /// protected virtual void SetDefaultOnCheck() { if (this._mustInput && this.SelectedIndex < 0 && this.Items.Count > 0) { this.SelectedIndex = 0; } } /// /// 设置文本框只读 /// protected virtual void SetEditReadOnly() { this.SetEditReadOnly(this._readOnly || this._editReadOnly); } #endregion #region 私有方法 /// /// 使父控件的指定区域无效(将其添加到控件的更新区域,下次绘制操作时将重新绘制更新区域),并向父控件发送绘制消息。 /// private void InvalidateBorder() { Color? borderColor = BorderColorPaint.GetBorderColor(this as IDataVerifiable, this._entered, this._mouseOver); if (borderColor != this._borderColor) { this._borderColor = borderColor; if (this.Parent == null) { this.Invalidate(); } else { this.Parent.Invalidate(this.Bounds, true); } } } /// /// 释放与此窗口组合Edit关联的句柄 /// private void ReleaseChildWindow() { if (this._childEdit != null) { this._childEdit.ReleaseHandle(); this._childEdit = null; } //if (this.childListBox != null) //{ // this.childListBox.ReleaseHandle(); // this.childListBox = null; //} } private void SetNullData(object dataSource, bool canRemove) { System.Data.DataTable dt = dataSource as System.Data.DataTable; if (dt == null) { return; } if (this._hasNullData) { dt.Rows.InsertAt(dt.NewRow(), 0); } else if (canRemove) { dt.Rows.RemoveAt(0); } } /// /// 设置文本框只读 /// /// protected void SetEditReadOnly(bool readOnly) { if (this._childEdit != null) { WindowsAPI.SendMessage(this._childEdit.Handle, (int)WindowsMessage.EM_SETREADONLY, readOnly ? -1 : 0, 0); } } #endregion #region IDataVerifiable 成员 #region 成员变量 /// /// 显示边框颜色 /// private bool _showBorderColor = true; /// /// 控件的项目名 /// private string _itemName = null; /// /// 控件是否是必须输入项目 /// private bool _mustInput = false; /// /// 控件在验证输入错误时,如何提示 /// private InputErrorAlert _errorAlert = InputErrorAlert.Validated; /// /// 是否显示必须输入项目的提示 /// private bool _showMustInputAlert = true; /// /// 验证不通过时,焦点能否离开 /// private bool _canLostFocusOnError = true; /// /// 验证是否有错误 /// private bool _hasError = false; /// /// 是否自定义错误 /// private bool _hasCustomerError = false; /// /// 错误编码 /// private ControlErrorCode _errorCode = ControlErrorCode.DKC_0000; /// /// 错误消息 /// private string _errorMessage = null; /// /// 自定义错误消息 /// private string _customerErrorMessage = null; #endregion #region 属性 /// /// 获取或设置控件是否显示边框颜色。 /// [Description("获取或设置控件是否显示边框颜色。"), Category("IDataVerifiable")] [DefaultValue(true)] public bool ShowBorderColor { get { return this._showBorderColor; } set { if (this._showBorderColor != value) { this._showBorderColor = value; this.InvalidateBorder(); } } } /// /// 获取或设置控件的项目名 /// [Description("获取或设置控件的项目名。"), Category("IDataVerifiable")] [DefaultValue(null)] public string CDItemName { get { return this._itemName; } set { this._itemName = value; } } /// /// 获取或设置控件是否必须选中项目。 /// [Description("获取或设置控件是否必须选中项目。"), Category("IDataVerifiable")] [DefaultValue(false)] public virtual bool MustInput { get { return this._mustInput; } set { if (this._mustInput != value) { this._mustInput = value; this.ValidateData(); if (value && this._showMustInputAlert) { this.InvalidateBorder(); } } } } /// /// 获取或设置控件是否必须选中项目。 /// [Description("获取或设置控件在验证输入错误时,如何提示。"), Category("IDataVerifiable")] [DefaultValue(typeof(InputErrorAlert), "Validated")] public InputErrorAlert InputErrorAlert { get { return this._errorAlert; } set { if (this._errorAlert != value) { this._errorAlert = value; this.InvalidateBorder(); } } } /// /// 获取或设置控件是否显示必须输入项目提示 /// [Description("获取或设置控件是否显示必须输入项目提示。"), Category("IDataVerifiable")] [DefaultValue(true)] public bool ShowMustInputAlert { get { return this._showMustInputAlert; } set { if (this._showMustInputAlert != value) { this._showMustInputAlert = value; this.InvalidateBorder(); } } } /// /// 获取或设置当验证不通过时,控件是否可以失去焦点 /// [Description("获取或设置当验证不通过时,控件是否可以失去焦点。"), Category("IDataVerifiable")] [DefaultValue(true)] public bool CanLostFocusOnError { get { return this._canLostFocusOnError; } set { this._canLostFocusOnError = value; } } /// /// 获取控件校验时是否有错误 /// [Description("获取控件校验时是否有错误。"), Category("IDataVerifiable")] [DefaultValue(false)] public bool HasError { get { return this._hasCustomerError || this._hasError; } } /// /// 获取控件校验时的错误编码 /// [Description("获取控件校验时的错误编码。"), Category("IDataVerifiable")] [DefaultValue(typeof(ControlErrorCode), "DKC_0000")] public ControlErrorCode ErrorCode { get { return this._hasCustomerError ? ControlErrorCode.DKC_C001 : this._errorCode; } } /// /// 获取控件校验时的错误消息 /// [Description("获取控件校验时的错误编码。"), Category("IDataVerifiable")] [DefaultValue(null)] public string ErrorMessage { get { return this._hasCustomerError ? this._customerErrorMessage : this._errorMessage; } } #endregion #region 公有方法 /// /// 设置自定义错误 /// /// 输入是否有错误 /// 错误消息 public virtual void SetCustomerError(bool hasError, string errorMessage) { if (this._hasCustomerError != hasError || this._customerErrorMessage != errorMessage) { this._hasCustomerError = hasError; this._customerErrorMessage = errorMessage; this.OnHasErrorChanged(EventArgs.Empty); this.InvalidateBorder(); } } /// /// 清除自定义错误 /// public virtual void ClearCustomerError() { this.SetCustomerError(false, null); } /// /// 验证输入内容 /// /// 验证结果 public virtual bool ValidateData() { if (this._mustInput && this.SelectedIndex < 0) { this.SetError(true, ControlErrorCode.DKC_0001, this._itemName); return false; } this.ClearError(); return true; } /// /// 清除输入项 /// public virtual void ClearValue() { this.Text = null; this.SelectedIndex = -1; } #endregion #region 保护方法 /// /// 设置验证不通过错误 /// /// 是否有错误 /// 错误编码 /// 设置格式的对象 protected void SetError(bool hasError, ControlErrorCode code, params object[] args) { if (this._hasError != hasError || this._errorCode != code) { this._hasError = hasError; this._errorCode = code; if (args != null && args.Length > 0) { this._errorMessage = string.Format(code.GetDescription(), args); } else { this._errorMessage = code.GetDescription(); } this.OnHasErrorChanged(EventArgs.Empty); this.InvalidateBorder(); } } /// /// 清除验证不通过错误 /// protected void ClearError() { this.SetError(false, ControlErrorCode.DKC_0000); } #endregion #endregion #region IAsyncControl 成员 #region 成员变量 /// /// 异步处理开始时,控件状态 /// private bool _asyncBeginStatus = false; private bool _asyncBeginFocused = false; #endregion #region 公有方法 /// /// 开始异步处理 /// /// 是否处理焦点 public virtual void BeginAsync(ref bool doFocus) { this._asyncBeginFocused = false; if (doFocus && this.Focused) { this._asyncBeginFocused = true; doFocus = false; } this._asyncBeginStatus = this.ReadOnly; this.ReadOnly = true; } /// /// 结束异步处理 /// public virtual void EndAsync() { this.ReadOnly = this._asyncBeginStatus; if (this._asyncBeginFocused) { this.Focus(); } } #endregion #endregion } }