using System; using System.ComponentModel; using System.Drawing; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; namespace Dongke.WinForm.Controls { /// /// 弹出控件 /// [ToolboxItem(false)] public class PopupControlHost : ToolStripDropDown { #region 事件声明 #region SelectedOK /// /// 当确认选择项时发生。 /// private static readonly object EventSelectedOK = new object(); /// /// 当确认选择项时发生。 /// [Description("当确认选择项时发生。"), Category("CustomerEx")] internal event EventHandler SelectedOK { add { base.Events.AddHandler(EventSelectedOK, value); } remove { base.Events.AddHandler(EventSelectedOK, value); } } /// /// 引发 SelectedOK 事件 /// /// 包含事件数据的 EventArgs protected virtual void OnSelectedOK(EventArgs e) { EventHandler eventHandler = (EventHandler)base.Events[EventSelectedOK]; if (eventHandler != null) { eventHandler(this, e); } } #endregion #region SelectedCancel /// /// 当取消选择项时发生。 /// private static readonly object EventSelectedCancel = new object(); /// /// 当取消选择项时发生。 /// [Description("当取消选择项时发生。"), Category("CustomerEx")] internal event EventHandler SelectedCancel { add { base.Events.AddHandler(EventSelectedCancel, value); } remove { base.Events.AddHandler(EventSelectedCancel, value); } } /// /// 引发 SelectedCancel 事件 /// /// 包含事件数据的 EventArgs protected virtual void OnSelectedCancel(EventArgs e) { EventHandler eventHandler = (EventHandler)base.Events[EventSelectedCancel]; if (eventHandler != null) { eventHandler(this, e); } } #endregion #endregion #region 常量 //private static readonly Size GRIP_SIZE = new Size(0x10, 0x10); #endregion #region 成员变量 /// /// 弹出控件的父控件 /// private Control _owner = null; /// /// 承载自定义控件或 Windows 窗体控件。 /// private ToolStripControlHost _controlHost = null; /// /// 弹出的内容 /// private Control _popupControl = null; /// /// 是否改变控件形状 /// private bool _changeRegion = false; /// /// 显示时是否获得焦点 /// private bool _focusOnOpen = true; /// /// 是否接受alt键输入 /// private bool _acceptAlt = true; /// /// 能否改变控件大小 /// private bool _canResize = true; /// /// 控件是否打开 /// private bool _isOpen = false; private PopupControlHost _ownerPopup; private PopupControlHost _childPopup; private bool _resizableTop = false; private bool _resizableLeft = false; //private Color _borderColor = Color.FromArgb(23, 169, 254); //private VisualStyleRenderer sizeGripRenderer; private bool _sizeHasChanged = false; #endregion #region 构造函数 /// /// 弹出控件 /// public PopupControlHost(Control owner) { this.DoubleBuffered = true; this.ResizeRedraw = true; this.AutoSize = false; this.Padding = Padding.Empty; this.Margin = Padding.Empty; this.ResizeRedraw = true; this.SetOwner(owner); } #endregion #region 属性 /// /// 获取弹出的内容 /// public Control Content { get { return this._popupControl; } set { if (this._popupControl != value) { this.CreateHost(value); } } } /// /// 获取弹出的内容 /// public ToolStripControlHost Host { get { return this._controlHost; } } /// /// 获取或设置一个值,该值指示弹出控件是否是异形控件。 /// public bool ChangeRegion { get { return this._changeRegion; } set { this._changeRegion = value; this.UpdateRegion(); } } /// /// 获取或设置一个值,该值指示控件显示时,是否获得焦点。 /// public bool FocusOnOpen { get { return this._focusOnOpen; } set { this._focusOnOpen = value; } } /// /// 获取或设置一个值,该值指示控件是否接受Alt输入。 /// public bool AcceptAlt { get { return this._acceptAlt; } set { this._acceptAlt = value; } } /// /// 获取或设置一个值,该值指示用户能否改变控件大小。 /// public bool CanResize { get { return this._canResize; } set { this._canResize = value; } } ///// ///// 获取或设置一个值,该值指示控件边框颜色。 ///// //public Color BorderColor //{ // get // { // return this._borderColor; // } // set // { // this._borderColor = value; // } //} /// /// 获取一个值,该值指示控件是否打开状态。 /// public bool IsOpen { get { return this._isOpen; } } #endregion #region 重写事件 /// /// 控件正打开时 /// /// protected override void OnOpening(CancelEventArgs e) { if (this._popupControl.IsDisposed || this._popupControl.Disposing) { e.Cancel = true; base.OnOpening(e); return; } //UpdateRegion(); base.OnOpening(e); } /// /// 在打开控件时 /// /// protected override void OnOpened(EventArgs e) { if (this._focusOnOpen) { if (this._popupControl is IPopupControl) { (this._popupControl as IPopupControl).FocusOnShown(); } else { this._popupControl.Focus(); } } this._isOpen = true; base.OnOpened(e); } /// /// 控件正关闭时 /// /// protected override void OnClosing(ToolStripDropDownClosingEventArgs e) { base.OnClosing(e); } /// /// 在关闭控件时 /// /// protected override void OnClosed(ToolStripDropDownClosedEventArgs e) { this._isOpen = false; base.OnClosed(e); } /// /// 大小改变时 /// /// protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); if (this._controlHost != null) { this._controlHost.Size = this.Size - this.Padding.Size; } if (this._isOpen) { this._sizeHasChanged = true; } } /// /// 绘制控件时 /// /// protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); } #endregion #region 重写方法 /// /// 获取新窗口的参数 /// protected override CreateParams CreateParams { [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] get { CreateParams cp = base.CreateParams; cp.ExStyle |= NativeMethods.WS_EX_NOACTIVATE; //cp.ExStyle |= 5242880; //cp.ExStyle &= -12289; return cp; } } /// /// 系统消息处理 /// /// [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { if (this.ProcessGrip(ref m)) { return; } base.WndProc(ref m); } /// /// 处理对话框键 /// /// /// [UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)] protected override bool ProcessDialogKey(Keys keyData) { //if (this._acceptAlt && ((keyData & Keys.Alt) == Keys.Alt)) //{ // if ((keyData & Keys.F4) != Keys.F4) // { // return false; // } // else // { // this.Close(); // } //} // ESC if ((keyData & Keys.KeyCode) == Keys.Escape) { this.OnSelectedCancel(EventArgs.Empty); return base.ProcessDialogKey(Keys.Escape); //bool result = base.ProcessDialogKey(Keys.Escape); //if (result) //{ // this.OnSelectedCancel(EventArgs.Empty); //} //return result; //return true; } // Enter if ((keyData & Keys.KeyCode) == Keys.Enter) { this.OnSelectedOK(EventArgs.Empty); return base.ProcessDialogKey(Keys.Escape); //bool result = base.ProcessDialogKey(Keys.Escape); //if (result) //{ // this.OnSelectedOK(EventArgs.Empty); //} //return result; //return true; } return base.ProcessDialogKey(keyData); } #endregion #region 事件处理 /// /// 控件显示范围改变 /// /// /// private void PopupControlRegionChanged(object sender, EventArgs e) { this.UpdateRegion(); } #endregion #region 公有方法 /// /// 显示控件 /// public new void Show() { this.ShowInternal(); } /// /// 显示控件 /// /// public void Show(Control control) { this.SetOwner(control); this.ShowInternal(); } #endregion #region 保护方法 /// /// 更新空间显示范围 /// protected virtual void UpdateRegion() { if (!this._changeRegion) { return; } if (base.Region != null) { base.Region.Dispose(); base.Region = null; } if (this._popupControl.Region != null) { base.Region = this._popupControl.Region.Clone(); } } #endregion #region 私有方法 /// /// 显示控件 /// private void ShowInternal() { if (this._owner == null) { return; } if (this._canResize && !this._changeRegion) { this.Padding = new Padding(1, 1, 1, 3); } else if (!this._changeRegion) { this.Padding = new Padding(1); } else { this.Padding = Padding.Empty; } Size s = this._popupControl.Size + this.Padding.Size; if (!this._sizeHasChanged && this._owner != null) { s.Width = this._owner.Width; } this.Size = s; base.Show(this._owner, 0, this._owner.Height); } /// /// 设定Owner /// /// private void SetOwner(Control owner) { if (owner == null) { return; } this._owner = owner; this.Font = owner.Font; this.SetOwnerItem(owner); } /// /// 设定OwnerItem /// /// private void SetOwnerItem(Control owner) { if (owner == null) { return; } if (owner is PopupControlHost) { PopupControlHost popupControl = owner as PopupControlHost; this._ownerPopup = popupControl; this._ownerPopup._childPopup = this; this.OwnerItem = popupControl.Items[0]; return; } if (owner.Parent != null) { this.SetOwnerItem(owner.Parent); } } /// /// /// /// private void CreateHost(Control control) { if (this._controlHost != null) { this._controlHost.Dispose(); } this._popupControl = control; if (control == null) { //throw new ArgumentException("control"); return; } this._controlHost = new ToolStripControlHost(control, "popupControlHost"); this._controlHost.Font = this.Font; this._controlHost.AutoSize = false; this._controlHost.Padding = Padding.Empty; this._controlHost.Margin = Padding.Empty; Size maxSize = new Size(500, 500); Size minSize = new Size(5, 5); if (control.MaximumSize.Width > 0 && maxSize.Width > control.MaximumSize.Width) { maxSize.Width = control.MaximumSize.Width; } if (control.MaximumSize.Height > 0 && maxSize.Height > control.MaximumSize.Height) { maxSize.Height = control.MaximumSize.Height; } if (minSize.Width < control.MinimumSize.Width) { minSize.Width = control.MinimumSize.Width; } if (minSize.Height < control.MinimumSize.Height) { minSize.Height = control.MinimumSize.Height; } this.MaximumSize = maxSize; this.MinimumSize = minSize; base.Items.Add(this._controlHost); this._popupControl.RegionChanged += new EventHandler(PopupControlRegionChanged); this.UpdateRegion(); } /// /// /// /// /// [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] private bool ProcessGrip(ref Message m) { //if (m.Msg == NativeMethods.WM_NCACTIVATE && // m.WParam != IntPtr.Zero && // this._childPopup != null && // this._childPopup.Visible) //{ // this._childPopup.Hide(); //} if (this._canResize && !this._changeRegion) { if (m.Msg == NativeMethods.WM_NCHITTEST) { return this.OnNcHitTest(ref m); } if (m.Msg == NativeMethods.WM_GETMINMAXINFO) { return this.OnGetMinMaxInfo(ref m); } } return false; } /// /// 改变大小的范围 /// /// /// [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] private bool OnGetMinMaxInfo(ref Message m) { NativeMethods.MINMAXINFO minmax = (NativeMethods.MINMAXINFO)Marshal.PtrToStructure( m.LParam, typeof(NativeMethods.MINMAXINFO)); minmax.maxTrackSize = this.MaximumSize; minmax.minTrackSize = this.MinimumSize; Marshal.StructureToPtr(minmax, m.LParam, false); return true; } /// /// /// /// /// private bool OnNcHitTest(ref Message m) { Point location = this.PointToClient(new Point( NativeMethods.LOWORD(m.LParam), NativeMethods.HIWORD(m.LParam))); Rectangle gripRect = Rectangle.Empty; if (this._canResize && !this._changeRegion) { if (this._resizableLeft) { if (this._resizableTop) { gripRect = new Rectangle(0, 0, 6, 6); } else { gripRect = new Rectangle( 0, this.Height - 6, 6, 6); } } else { if (this._resizableTop) { gripRect = new Rectangle(this.Width - 6, 0, 6, 6); } else { gripRect = new Rectangle( this.Width - 6, this.Height - 6, 6, 6); } } } if (gripRect.Contains(location)) { if (this._resizableLeft) { if (this._resizableTop) { m.Result = (IntPtr)NativeMethods.HTTOPLEFT; return true; } else { m.Result = (IntPtr)NativeMethods.HTBOTTOMLEFT; return true; } } else { if (this._resizableTop) { m.Result = (IntPtr)NativeMethods.HTTOPRIGHT; return true; } else { m.Result = (IntPtr)NativeMethods.HTBOTTOMRIGHT; return true; } } } else { Rectangle rectClient = this.ClientRectangle; if (location.X > rectClient.Right - 3 && location.X <= rectClient.Right && !this._resizableLeft) { m.Result = (IntPtr)NativeMethods.HTRIGHT; return true; } else if (location.Y > rectClient.Bottom - 3 && location.Y <= rectClient.Bottom && !this._resizableTop) { m.Result = (IntPtr)NativeMethods.HTBOTTOM; return true; } else if (location.X > -1 && location.X < 3 && this._resizableLeft) { m.Result = (IntPtr)NativeMethods.HTLEFT; return true; } else if (location.Y > -1 && location.Y < 3 && this._resizableTop) { m.Result = (IntPtr)NativeMethods.HTTOP; return true; } } return false; } #endregion /* private bool OnNcHitTest(ref Message m, bool contentControl) { int x = NativeMethods.LOWORD(m.LParam); int y = NativeMethods.HIWORD(m.LParam); Point clientLocation = PointToClient(new Point(x, y)); GripBounds gripBouns = new GripBounds(contentControl ? content.ClientRectangle : ClientRectangle); IntPtr transparent = new IntPtr(NativeMethods.HTTRANSPARENT); if (resizableTop) { if (resizableRight && gripBouns.TopLeft.Contains(clientLocation)) { m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTTOPLEFT; return true; } if (!resizableRight && gripBouns.TopRight.Contains(clientLocation)) { m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTTOPRIGHT; return true; } if (gripBouns.Top.Contains(clientLocation)) { m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTTOP; return true; } } else { if (resizableRight && gripBouns.BottomLeft.Contains(clientLocation)) { m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTBOTTOMLEFT; return true; } if (!resizableRight && gripBouns.BottomRight.Contains(clientLocation)) { m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTBOTTOMRIGHT; return true; } if (gripBouns.Bottom.Contains(clientLocation)) { m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTBOTTOM; return true; } } if (resizableRight && gripBouns.Left.Contains(clientLocation)) { m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTLEFT; return true; } if (!resizableRight && gripBouns.Right.Contains(clientLocation)) { m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTRIGHT; return true; } return false; } private VS.VisualStyleRenderer sizeGripRenderer; /// /// Paints the size grip. /// /// The instance containing the event data. public void PaintSizeGrip(PaintEventArgs e) { if (e == null || e.Graphics == null || !resizable) { return; } Size clientSize = content.ClientSize; if (Application.RenderWithVisualStyles) { if (this.sizeGripRenderer == null) { this.sizeGripRenderer = new VS.VisualStyleRenderer(VS.VisualStyleElement.Status.Gripper.Normal); } this.sizeGripRenderer.DrawBackground(e.Graphics, new Rectangle(clientSize.Width - 0x10, clientSize.Height - 0x10, 0x10, 0x10)); } else { ControlPaint.DrawSizeGrip(e.Graphics, content.BackColor, clientSize.Width - 0x10, clientSize.Height - 0x10, 0x10, 0x10); } } */ } }