亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

.net2.0+ Winform項目實現彈出容器層

2020-01-24 01:30:22
字體:
來源:轉載
供稿:網友

適用于:.net2.0+ Winform項目

背景:

有時候我們需要開一個簡單的窗口來做一些事,例如輸入一些東西、點選一個item之類的,可能像這樣:

完了返回原窗體并獲取剛剛的輸入,這樣做并沒有什么問題,但在幾天前我突然產生了一些想法:為什么非得有板有眼的彈出一個窗體給用戶呢,是不是可以在按鈕附近迅速呈現一個層來做這些事呢,類似快捷菜單那樣,用戶高興就在里面做一下該做的事,不高興就在其它地方點一下它就消失,本來很輕便快捷的操作,DUANG~彈出一個窗體來會不會令用戶心里咯噔一下呢,感受層面的事情往往是很微妙的,不管怎樣,我既然起了這個念頭,just try it。

我首先找了一下現成的方案,果然在牛逼的codeproject.com已經有牛人做了這樣的事情:

http://www.codeproject.com/Articles/17502/Simple-Popup-Control

簡單體驗了一下,的確是了不起的創造。原理是利用ToolStripControlHost可以承載自定義控件的這一能力,讓下拉式控件ToolStripDropDown將任何自定義控件像右鍵菜單那樣彈出來(別忘了右鍵菜單ContextMenuStrip就是繼承自ToolStripDropDown),這樣就等于把菜單作為一個容器,可以彈出任何或簡單或復雜的控件組合,同時又具有菜單具有的便捷性,召之即來揮之即去。當時了解到這方案的時候真挺開心,正是我想要的效果,感覺這下好了,不用瞎費勁自己造了。

但很快發現一個在我看來還挺在意的不足,就是ToolStripDropDown只有Show,沒有ShowDialog,就是不能以模式化(Modal,也有叫模態的,鑒于MSDN都稱模式,我也隨流叫它模式)的方式彈出,這是由ToolStripDropDown的固有能力決定的,該方案既然基于ToolStripDropDown,自然也受限于此,不能模式化彈出。這樣帶來的問題是某些情況下的調用體驗不好(體驗這種事當然不是用戶才有的專利,俺們碼農也是人,也要講體驗的說),比如彈出的控件是讓用戶輸入一些東西,完了用戶點擊某個按鈕什么的返回原窗體,然后在原窗體獲取用戶剛剛的輸入,然后接著做后面的事。由于非模式的Show不會阻塞代碼,所以就不能在Show的下方想當然的獲取值、使用值~這是顯然的。要想獲得值可能就得額外采取一些做法,例如響應彈出控件的關閉事件,或者把原窗體傳入彈出控件完了在后者中做原本應該在原窗體中做的事~等等,辦法當然有很多,但這都是因為只能Show帶來的多余的事,有什么比在一個方法中彈出控件、等待返回、繼續處理來的爽滑的呢,像這樣不是很自然嗎:

復制代碼 代碼如下:
string s;using (Popup p = new Popup()){ if (p.ShowDialog() != DialogResult.OK) { return; } s = p.InputText;}//go on...

所以很遺憾,不得不揮別這個優秀的方案,造自己的輪子。不過受該方案的啟發,我想到用ContextMenu來做容器(注意這個菜單類跟上面提到的繼承自ToolStripDropDown的ContextMenuStrip大大的不同,前者是OS原生的菜單,就是在桌面、圖標以及文本框中右鍵彈出的那種菜單,.net是通過調API的方式來操作這樣的菜單,而后者則完全是.net實現,更多信息請參考MSDN,此處不展開),因為ContextMenu的Show是阻塞式的,正合我意。但一番嘗試之后放棄,它的菜單項MenuItem不像ToolStripItem那樣可以通過ToolStripControlHost承載自定義控件,希望是我能力有限,總之我做不到把自定義控件弄到ContextMenu上,也沒見過原生菜單上出現過文本框、復選框等奇怪的東西,如果您知道怎么擴展原生菜單,還望不吝賜教,先行謝過!

我還是打回.net的主意,當中仍然是做了許多不同的嘗試,Form、Panel、UserControl、ContainerControl、Control等等看起來適合做容器層的東西都試了個遍,甚至重新在ToolStripDropDown上打主意,最后選用Form,改造一番,自我感覺較理想的實現了我要的東西:一個叫做FloatLayerBase的基類,它本身繼承自System.Windows.Forms.Form類,而需要作為浮動層顯示的應用則繼承自FloatLayerBase進行實現,例如下面這個接受用戶輸入數值的NumInputDemo實現:

樣子和特點:不會令父窗口失去焦點(不會搶焦點的層才是好層):

當然,男人不止一面:

還有其它邊框樣式,有待用戶自行體驗,最后有demo提供。

可以有調整尺寸的手柄:

可以點住客戶區拖動:

別的一些應用:

這些都只是demo,沒那么好看和強大,重點是有了這個FloatLayerBase,就可以實現自己的浮動應用。

使用說明:確保FloatLayerBase類在項目中~廢話。源碼在此:

using System;using System.ComponentModel;using System.Drawing;using System.Runtime.InteropServices;using System.Windows.Forms;namespace AhDung.WinForm.Controls{  /// <summary>  /// 浮動層基類  /// </summary>  public class FloatLayerBase : Form  {    /// <summary>    /// 鼠標消息篩選器    /// </summary>    //由于本窗體為WS_CHILD,所以不會收到在窗體以外點擊鼠標的消息    //該消息篩選器的作用就是讓本窗體獲知鼠標點擊情況,進而根據鼠標是否在本窗體以外的區域點擊,做出相應處理    readonly AppMouseMessageHandler _mouseMsgFilter;    /// <summary>    /// 指示本窗體是否已ShowDialog過    /// </summary>    //由于多次ShowDialog會使OnLoad/OnShown重入,故需設置此標記以供重入時判斷    bool _isShowDialogAgain;    //邊框相關字段    BorderStyle _borderType;    Border3DStyle _border3DStyle;    ButtonBorderStyle _borderSingleStyle;    Color _borderColor;    /// <summary>    /// 獲取或設置邊框類型    /// </summary>    [Description("獲取或設置邊框類型。")]    [DefaultValue(BorderStyle.Fixed3D)]    public BorderStyle BorderType    {      get { return _borderType; }      set      {        if (_borderType == value) { return; }        _borderType = value;        Invalidate();      }    }    /// <summary>    /// 獲取或設置三維邊框樣式    /// </summary>    [Description("獲取或設置三維邊框樣式。")]    [DefaultValue(Border3DStyle.RaisedInner)]    public Border3DStyle Border3DStyle    {      get { return _border3DStyle; }      set      {        if (_border3DStyle == value) { return; }        _border3DStyle = value;        Invalidate();      }    }    /// <summary>    /// 獲取或設置線型邊框樣式    /// </summary>    [Description("獲取或設置線型邊框樣式。")]    [DefaultValue(ButtonBorderStyle.Solid)]    public ButtonBorderStyle BorderSingleStyle    {      get { return _borderSingleStyle; }      set      {        if (_borderSingleStyle == value) { return; }        _borderSingleStyle = value;        Invalidate();      }    }    /// <summary>    /// 獲取或設置邊框顏色(僅當邊框類型為線型時有效)    /// </summary>    [Description("獲取或設置邊框顏色(僅當邊框類型為線型時有效)。")]    [DefaultValue(typeof(Color), "DarkGray")]    public Color BorderColor    {      get { return _borderColor; }      set      {        if (_borderColor == value) { return; }        _borderColor = value;        Invalidate();      }    }    protected override sealed CreateParams CreateParams    {      get      {        CreateParams prms = base.CreateParams;        //prms.Style = 0;        //prms.Style |= -2147483648;  //WS_POPUP        prms.Style |= 0x40000000;   //WS_CHILD 重要,只有CHILD窗體才不會搶父窗體焦點        prms.Style |= 0x4000000;    //WS_CLIPSIBLINGS        prms.Style |= 0x10000;     //WS_TABSTOP        prms.Style &= ~0x40000;    //WS_SIZEBOX    去除        prms.Style &= ~0x800000;    //WS_BORDER    去除        prms.Style &= ~0x400000;    //WS_DLGFRAME   去除        //prms.Style &= ~0x20000;   //WS_MINIMIZEBOX  去除        //prms.Style &= ~0x10000;   //WS_MAXIMIZEBOX  去除        prms.ExStyle = 0;        //prms.ExStyle |= 0x1;     //WS_EX_DLGMODALFRAME 立體邊框        //prms.ExStyle |= 0x8;     //WS_EX_TOPMOST        prms.ExStyle |= 0x10000;    //WS_EX_CONTROLPARENT        //prms.ExStyle |= 0x80;    //WS_EX_TOOLWINDOW        //prms.ExStyle |= 0x100;    //WS_EX_WINDOWEDGE        //prms.ExStyle |= 0x8000000;  //WS_EX_NOACTIVATE        //prms.ExStyle |= 0x4;     //WS_EX_NOPARENTNOTIFY        return prms;      }    }    //構造函數    public FloatLayerBase()    {      //初始化消息篩選器。添加和移除在顯示/隱藏時負責      _mouseMsgFilter = new AppMouseMessageHandler(this);      //初始化基類屬性      InitBaseProperties();      //初始化邊框相關      _borderType = BorderStyle.Fixed3D;      _border3DStyle = System.Windows.Forms.Border3DStyle.RaisedInner;      _borderSingleStyle = ButtonBorderStyle.Solid;      _borderColor = Color.DarkGray;    }    protected override void OnLoad(EventArgs e)    {      //防止重入      if (_isShowDialogAgain) { return; }      //需得減掉兩層邊框寬度,運行時尺寸才與設計時完全相符,原因不明      //確定與ControlBox、FormBorderStyle有關,但具體聯系不明      if (!DesignMode)      {        Size size = SystemInformation.FrameBorderSize;        this.Size -= size + size;//不可以用ClientSize,后者會根據窗口風格重新調整Size      }      base.OnLoad(e);    }    protected override void OnShown(EventArgs e)    {      //防止重入      if (_isShowDialogAgain) { return; }      //在OnShown中為首次ShowDialog設標記      if (Modal) { _isShowDialogAgain = true; }      if (!DesignMode)      {        //激活首控件        Control firstControl;        if ((firstControl = GetNextControl(this, true)) != null)        {          firstControl.Focus();        }      }      base.OnShown(e);    }    protected override void WndProc(ref Message m)    {      //當本窗體作為ShowDialog彈出時,在收到WM_SHOWWINDOW前,Owner會被Disable      //故需在收到該消息后立即Enable它,不然Owner窗體和本窗體都將處于無響應狀態      if (m.Msg == 0x18 && m.WParam != IntPtr.Zero && m.LParam == IntPtr.Zero        && Modal && Owner != null && !Owner.IsDisposed)      {        if (Owner.IsMdiChild)        {          //當Owner是MDI子窗體時,被Disable的是MDI主窗體          //并且Parent也會指向MDI主窗體,故需改回為Owner,這樣彈出窗體的Location才會相對于Owner而非MDIParent          NativeMethods.EnableWindow(Owner.MdiParent.Handle, true);          NativeMethods.SetParent(this.Handle, Owner.Handle);//只能用API設置Parent,因為模式窗體是TopLevel,.Net拒絕為頂級窗體設置Parent        }        else        {          NativeMethods.EnableWindow(Owner.Handle, true);        }      }      base.WndProc(ref m);    }    //畫邊框    protected override void OnPaintBackground(PaintEventArgs e)    {      base.OnPaintBackground(e);      if (_borderType == BorderStyle.Fixed3D)//繪制3D邊框      {        ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle);      }      else if (_borderType == BorderStyle.FixedSingle)//繪制線型邊框      {        ControlPaint.DrawBorder(e.Graphics, ClientRectangle, BorderColor, BorderSingleStyle);      }    }    //顯示后添加鼠標消息篩選器以開始捕捉,隱藏時則移除篩選器。之所以不放Dispose中是想盡早移除篩選器    protected override void OnVisibleChanged(EventArgs e)    {      if (!DesignMode)      {        if (Visible) { Application.AddMessageFilter(_mouseMsgFilter); }        else { Application.RemoveMessageFilter(_mouseMsgFilter); }      }      base.OnVisibleChanged(e);    }    //實現窗體客戶區拖動    //在WndProc中實現這個較麻煩,所以放到這里做    protected override void OnMouseDown(MouseEventArgs e)    {      //讓鼠標點擊客戶區時達到與點擊標題欄一樣的效果,以此實現客戶區拖動      NativeMethods.ReleaseCapture();      NativeMethods.SendMessage(Handle, 0xA1/*WM_NCLBUTTONDOWN*/, (IntPtr)2/*CAPTION*/, IntPtr.Zero);      base.OnMouseDown(e);    }    /// <summary>    /// 顯示為模式窗體    /// </summary>    /// <param name="control">顯示在該控件下方</param>    public DialogResult ShowDialog(Control control)    {      return ShowDialog(control, 0, control.Height);    }    /// <summary>    /// 顯示為模式窗體    /// </summary>    /// <param name="control">觸發彈出窗體的控件</param>    /// <param name="offsetX">相對control水平偏移</param>    /// <param name="offsetY">相對control垂直偏移</param>    public DialogResult ShowDialog(Control control, int offsetX, int offsetY)    {      return ShowDialog(control, new Point(offsetX, offsetY));    }    /// <summary>    /// 顯示為模式窗體    /// </summary>    /// <param name="control">觸發彈出窗體的控件</param>    /// <param name="offset">相對control偏移</param>    public DialogResult ShowDialog(Control control, Point offset)    {      return this.ShowDialogInternal(control, offset);    }    /// <summary>    /// 顯示為模式窗體    /// </summary>    /// <param name="item">顯示在該工具欄項的下方</param>    public DialogResult ShowDialog(ToolStripItem item)    {      return ShowDialog(item, 0, item.Height);    }    /// <summary>    /// 顯示為模式窗體    /// </summary>    /// <param name="item">觸發彈出窗體的工具欄項</param>    /// <param name="offsetX">相對item水平偏移</param>    /// <param name="offsetY">相對item垂直偏移</param>    public DialogResult ShowDialog(ToolStripItem item, int offsetX, int offsetY)    {      return ShowDialog(item, new Point(offsetX, offsetY));    }    /// <summary>    /// 顯示為模式窗體    /// </summary>    /// <param name="item">觸發彈出窗體的工具欄項</param>    /// <param name="offset">相對item偏移</param>    public DialogResult ShowDialog(ToolStripItem item, Point offset)    {      return this.ShowDialogInternal(item, offset);    }    /// <summary>    /// 顯示窗體    /// </summary>    /// <param name="control">顯示在該控件下方</param>    public void Show(Control control)    {      Show(control, 0, control.Height);    }    /// <summary>    /// 顯示窗體    /// </summary>    /// <param name="control">觸發彈出窗體的控件</param>    /// <param name="offsetX">相對control水平偏移</param>    /// <param name="offsetY">相對control垂直偏移</param>    public void Show(Control control, int offsetX, int offsetY)    {      Show(control, new Point(offsetX, offsetY));    }    /// <summary>    /// 顯示窗體    /// </summary>    /// <param name="control">觸發彈出窗體的控件</param>    /// <param name="offset">相對control偏移</param>    public void Show(Control control, Point offset)    {      this.ShowInternal(control, offset);    }    /// <summary>    /// 顯示窗體    /// </summary>    /// <param name="item">顯示在該工具欄下方</param>    public void Show(ToolStripItem item)    {      Show(item, 0, item.Height);    }    /// <summary>    /// 顯示窗體    /// </summary>    /// <param name="item">觸發彈出窗體的工具欄項</param>    /// <param name="offsetX">相對item水平偏移</param>    /// <param name="offsetY">相對item垂直偏移</param>    public void Show(ToolStripItem item, int offsetX, int offsetY)    {      Show(item, new Point(offsetX, offsetY));    }    /// <summary>    /// 顯示窗體    /// </summary>    /// <param name="item">觸發彈出窗體的工具欄項</param>    /// <param name="offset">相對item偏移</param>    public void Show(ToolStripItem item, Point offset)    {      this.ShowInternal(item, offset);    }    /// <summary>    /// ShowDialog內部方法    /// </summary>    private DialogResult ShowDialogInternal(Component controlOrItem, Point offset)    {      //快速連續彈出本窗體將有可能遇到尚未Hide的情況下再次彈出,這會引發異常,故需做處理      if (this.Visible) { return System.Windows.Forms.DialogResult.None; }      this.SetLocationAndOwner(controlOrItem, offset);      return base.ShowDialog();    }    /// <summary>    /// Show內部方法    /// </summary>    private void ShowInternal(Component controlOrItem, Point offset)    {      if (this.Visible) { return; }//原因見ShowDialogInternal      this.SetLocationAndOwner(controlOrItem, offset);      base.Show();    }    /// <summary>    /// 設置坐標及所有者    /// </summary>    /// <param name="controlOrItem">控件或工具欄項</param>    /// <param name="offset">相對偏移</param>    private void SetLocationAndOwner(Component controlOrItem, Point offset)    {      Point pt = Point.Empty;      if (controlOrItem is ToolStripItem)      {        ToolStripItem item = (ToolStripItem)controlOrItem;        pt.Offset(item.Bounds.Location);        controlOrItem = item.Owner;      }      Control c = (Control)controlOrItem;      pt.Offset(GetControlLocationInForm(c));      pt.Offset(offset);      this.Location = pt;      //設置Owner屬性與Show[Dialog](Owner)有不同,當Owner是MDIChild時,后者會改Owner為MDIParent      this.Owner = c.FindForm();    }    /// <summary>    /// 獲取控件在窗體中的坐標    /// </summary>    private static Point GetControlLocationInForm(Control c)    {      Point pt = c.Location;      while (!((c = c.Parent) is Form))      {        pt.Offset(c.Location);      }      return pt;    }    #region 屏蔽對本類影響重大的基類方法和屬性    /// <summary>    /// 初始化部分基類屬性    /// </summary>    private void InitBaseProperties()    {      base.ControlBox = false;              //重要      //必須得是SizableToolWindow才能支持調整大小的同時,不受SystemInformation.MinWindowTrackSize的限制      base.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;      base.Text = string.Empty;             //重要      base.HelpButton = false;      base.Icon = null;      base.IsMdiContainer = false;      base.MaximizeBox = false;      base.MinimizeBox = false;      base.ShowIcon = false;      base.ShowInTaskbar = false;      base.StartPosition = FormStartPosition.Manual;   //重要      base.TopMost = false;      base.WindowState = FormWindowState.Normal;    }    //屏蔽原方法    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("請使用別的重載!", true)]    public new DialogResult ShowDialog() { throw new NotImplementedException(); }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("請使用別的重載!", true)]    public new DialogResult ShowDialog(IWin32Window owner) { throw new NotImplementedException(); }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("請使用別的重載!", true)]    public new void Show() { throw new NotImplementedException(); }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("請使用別的重載!", true)]    public new void Show(IWin32Window owner) { throw new NotImplementedException(); }    //屏蔽原屬性    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new bool ControlBox { get { return false; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("設置邊框請使用Border相關屬性!", true)]    public new FormBorderStyle FormBorderStyle { get { return System.Windows.Forms.FormBorderStyle.SizableToolWindow; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public override sealed string Text { get { return string.Empty; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new bool HelpButton { get { return false; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new Image Icon { get { return null; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new bool IsMdiContainer { get { return false; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new bool MaximizeBox { get { return false; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new bool MinimizeBox { get { return false; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new bool ShowIcon { get { return false; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new bool ShowInTaskbar { get { return false; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new FormStartPosition StartPosition { get { return FormStartPosition.Manual; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new bool TopMost { get { return false; } set { } }    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    [Obsolete("禁用該屬性!", true)]    public new FormWindowState WindowState { get { return FormWindowState.Normal; } set { } }    #endregion    /// <summary>    /// 程序鼠標消息篩選器    /// </summary>    private class AppMouseMessageHandler : IMessageFilter    {      readonly FloatLayerBase _layerForm;      public AppMouseMessageHandler(FloatLayerBase layerForm)      {        _layerForm = layerForm;      }      public bool PreFilterMessage(ref Message m)      {        //如果在本窗體以外點擊鼠標,隱藏本窗體        //若想在點擊標題欄、滾動條等非客戶區也要讓本窗體消失,取消0xA1的注釋即可        //本例是根據坐標判斷,亦可以改為根據句柄,但要考慮子孫控件        //之所以用API而不用Form.DesktopBounds是因為后者不可靠        if ((m.Msg == 0x201/*|| m.Msg==0xA1*/)          && _layerForm.Visible && !NativeMethods.GetWindowRect(_layerForm.Handle).Contains(MousePosition))        {          _layerForm.Hide();//之所以不Close是考慮應該由調用者負責銷毀        }        return false;      }    }    /// <summary>    /// API封裝類    /// </summary>    private static class NativeMethods    {      [DllImport("user32.dll")]      [return: MarshalAs(UnmanagedType.Bool)]      public static extern bool EnableWindow(IntPtr hWnd, bool bEnable);      [DllImport("user32.dll", CharSet = CharSet.Auto)]      public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);      [DllImport("user32.dll")]      public static extern bool ReleaseCapture();      [DllImport("user32.dll", SetLastError = true)]      public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);      [DllImport("user32.dll", SetLastError = true)]      private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);      [StructLayout(LayoutKind.Sequential)]      private struct RECT      {        public int left;        public int top;        public int right;        public int bottom;        public static explicit operator Rectangle(RECT rect)        {          return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);        }      }      public static Rectangle GetWindowRect(IntPtr hwnd)      {        RECT rect;        GetWindowRect(hwnd, out rect);        return (Rectangle)rect;      }    }  }}

新建繼承窗體,選擇繼承自FloatLayerBase類;也可以新建普通窗體,然后把基類由Form改為FloatLayerBase
在設計器和源碼中打造浮動應用
在需要的地方使用它。關于使用,先看一下FloatLayerBase的部分公開成員:

//屬性public BorderStyle BorderType { get; set; }public Border3DStyle Border3DStyle { get; set; }public ButtonBorderStyle BorderSingleStyle { get; set; }public Color BorderColor { get; set; }//方法public void Show(Control control);public void Show(Control control, Point offset);public void Show(Control control, int offsetX, int offsetY);public void Show(ToolStripItem item);public void Show(ToolStripItem item, Point offset);public void Show(ToolStripItem item, int offsetX, int offsetY);public DialogResult ShowDialog(Control control);public DialogResult ShowDialog(Control control, Point offset);public DialogResult ShowDialog(Control control, int offsetX, int offsetY);public DialogResult ShowDialog(ToolStripItem item);public DialogResult ShowDialog(ToolStripItem item, Point offset);public DialogResult ShowDialog(ToolStripItem item, int offsetX, int offsetY);

上面4個屬性都是跟邊框有關的,邊框總共有3種形態,三維、線型、無,由BorderType指定;當為三維形態時,由Border3DStyle指定具體樣式;為線型時,由BorderSingleStyle和BorderColor分別指定具體線型和顏色。原Form.FormBorderStyle屬性已被屏蔽,不允許子類訪問,還有若干原Form的屬性也已屏蔽,原因都在源碼里。另外,原Form.SizeGripStyle照常使用,是否允許調整浮動層大小就靠它了

方法就說一下Show和ShowDialog,顯然分別是用來非模式化/模式化顯示浮動層的,兩者在調用角度的重大區別就是,前者不會阻塞代碼,后者則會,實際應用中根據情況選用。每個方法從參數又分Control和ToolStripItem兩類,都是代表從什么控件上彈出浮動層的意思,前者接受Button、TextBox等控件(不能傳入Form,后果會不愉快),后者接受工具欄上面的項目,例如ToolStripButton、ToolStripTextBox之類的。重載可以指定相對control或item的偏移位置,默認是在control/item的下方彈出浮動層。最后無論是Show還是ShowDialog彈出來的浮動層,都可以像右鍵菜單那樣通過在其它地方點鼠標使之消失,這里需要說明一下:

鼠標只會點在本程序內的窗體中時,讓浮動層消失。點在程序外的窗口、桌面、任務欄這些則不會。為什么要這樣是因為要做到完全像右鍵菜單那樣對全局鼠標敏感,需要全局鉤子,這會增加代碼量(性能且不說,沒測過不妄言),而且我認為沒必要全局敏感浮動層消失是調用Hide方法,所以對于模式化打開的浮動層,會返回DialogResult.Cancel,這是.net對模式對話框的設計使然,模式對話框被Hide或Close時,就是返回Cancel。在此也提醒一下調用者,在使用模式對話框時,永遠考慮有返回Cancel這種情況,不限于本例,而是所有對話框

原Show()/Show(IWin32Window)和ShowDialog()/ShowDialog(IWin32Window)已被屏蔽,原因見源碼。

其它:

編寫期間一直使用PopupFormBase作為類名,發布最后時刻才改為現在的FloatLayerBase,所以demo中可能尚有依據原名起名的子類、方法名等。

Demo下載:

http://pan.baidu.com/s/1mgnGPGc

里面有個Tester供您體驗。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美一区二粉嫩精品国产一线天| 日韩欧美成人免费视频| 日韩电视剧在线观看免费网站| 一区二区中文字幕| 欧美怡红院视频一区二区三区| 国产精品久久久久久久久免费看| 亚洲第一色在线| www欧美xxxx| 久久视频国产精品免费视频在线| 亚洲国产中文字幕在线观看| 国产一区二区三区网站| 国产精品视频网| 国产丝袜一区视频在线观看| 91夜夜揉人人捏人人添红杏| 亚洲精品99久久久久中文字幕| 日韩高清电影好看的电视剧电影| 91亚洲国产成人久久精品网站| 欧美性色视频在线| 日韩av日韩在线观看| 国产欧美在线看| 亚洲色图美腿丝袜| 国产精品丝袜一区二区三区| 91精品久久久久久久久久久久久久| 亚洲美女自拍视频| 国产一区二区激情| 亚洲热线99精品视频| 亚洲精品资源在线| 亚洲午夜国产成人av电影男同| 国内精品中文字幕| 亚洲免费视频一区二区| 日韩毛片中文字幕| 日韩国产精品视频| 欧美尤物巨大精品爽| 亚洲午夜色婷婷在线| 久久精品电影网站| 美女性感视频久久久| 久久香蕉频线观| 韩国三级电影久久久久久| 日韩欧美在线视频日韩欧美在线视频| 激情亚洲一区二区三区四区| 久久精品中文字幕免费mv| 欧美性猛交xxxx免费看| 国产精品成人aaaaa网站| 日韩中文字幕久久| 国产999精品久久久| 国产日韩精品在线观看| 久久久精品一区二区| 久久99亚洲热视| 日韩乱码在线视频| 午夜精品三级视频福利| 国产成人精品视频在线观看| 欧美一级大片在线观看| 亚洲欧美综合区自拍另类| 性色av香蕉一区二区| 欧美激情视频免费观看| 国产精品高潮呻吟久久av无限| 国产成人涩涩涩视频在线观看| 色综合久久精品亚洲国产| 91在线视频成人| 色偷偷偷亚洲综合网另类| 亚洲福利在线观看| 91探花福利精品国产自产在线| 日韩网站免费观看高清| 精品视频www| 日韩欧美中文字幕在线播放| 日韩av有码在线| 国产成人高潮免费观看精品| 国产精品视频色| 亚洲成人a级网| 亚洲欧美日韩精品久久奇米色影视| 日韩中文字幕视频| 久久人体大胆视频| 91视频国产精品| 日韩在线观看高清| 日韩精品一区二区视频| 国产精品视频白浆免费视频| 成人福利网站在线观看11| 精品久久久久久亚洲精品| 日韩欧美福利视频| 久久欧美在线电影| 久久久久久久久国产精品| 欧美视频在线观看 亚洲欧| 久久久久久久久国产精品| 91嫩草在线视频| 欧美色道久久88综合亚洲精品| 精品久久久久久久久久久久久久| 久久久精品日本| 欧美日韩一区免费| 日韩欧美国产成人| 精品一区二区三区四区| 日韩电影在线观看永久视频免费网站| 中文字幕日韩在线观看| 欧美影院久久久| 98精品在线视频| 亚洲黄色www网站| 亚洲乱码av中文一区二区| 久久久免费精品| 国产美女精品视频免费观看| 日韩天堂在线视频| 欧美亚洲国产日韩2020| 亚洲电影中文字幕| 欧美日韩亚洲成人| 日韩网站免费观看| 国内精品久久久| 日本亚洲欧美成人| 亚洲欧洲一区二区三区在线观看| 96sao精品视频在线观看| 中文日韩在线观看| 欧美一区三区三区高中清蜜桃| 亚洲国产欧美一区二区三区同亚洲| 伊人亚洲福利一区二区三区| 日日骚久久av| 欧美成人午夜激情| 91欧美精品成人综合在线观看| 亚洲欧美日韩综合| 91美女片黄在线观| 亚洲影院色在线观看免费| 日韩美女毛茸茸| 欧美在线视频免费播放| 九色91av视频| 欧美在线观看一区二区三区| 98午夜经典影视| 精品久久久久久久久久| 久久夜精品va视频免费观看| 成人在线观看视频网站| 久久青草精品视频免费观看| 不用播放器成人网| 北条麻妃一区二区在线观看| 久久香蕉国产线看观看网| 日韩在线播放视频| 成人h猎奇视频网站| 欧美专区中文字幕| 国产视频精品久久久| 欧美激情免费视频| 日韩电影在线观看永久视频免费网站| 日韩电影在线观看免费| 一区二区三区视频观看| 亚洲欧美日本伦理| 日韩小视频在线| 国产精品福利片| 日韩国产精品一区| 精品日本高清在线播放| 国产一区二区久久精品| 亚洲欧美成人网| 国产精品免费视频xxxx| 久久777国产线看观看精品| 国模私拍一区二区三区| 精品成人国产在线观看男人呻吟| 精品久久久久久中文字幕| 亚洲www永久成人夜色| 精品一区二区三区四区在线| 国产福利精品视频| 欧美精品videossex88| 日韩在线小视频| 精品久久久久久| 亚洲一区二区三区在线免费观看| 精品久久久在线观看| 亚洲欧美制服综合另类| 日韩精品亚洲元码| 国产剧情日韩欧美| 精品亚洲男同gayvideo网站| 91精品久久久久久综合乱菊| 激情懂色av一区av二区av| 国产精品高潮呻吟久久av无限|