欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

.net2.0+ Winform項(xiàng)目實(shí)現(xiàn)彈出容器層

 更新時(shí)間:2015年08月24日 16:09:13   作者:ahdung  
在實(shí)際工作中,如果能像菜單一樣彈出自定義內(nèi)容,會(huì)方便很多,比如查詢(xún)時(shí),比如下拉列表顯示多列信息時(shí),比如在填寫(xiě)某個(gè)信息需要查看一些信息樹(shù)時(shí)。這個(gè)時(shí)候自定義彈出界面就顯的非常重要了

適用于:.net2.0+ Winform項(xiàng)目

背景:

有時(shí)候我們需要開(kāi)一個(gè)簡(jiǎn)單的窗口來(lái)做一些事,例如輸入一些東西、點(diǎn)選一個(gè)item之類(lèi)的,可能像這樣:

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

我首先找了一下現(xiàn)成的方案,果然在牛逼的codeproject.com已經(jīng)有牛人做了這樣的事情:

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

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

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

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

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

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

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

當(dāng)然,男人不止一面:

還有其它邊框樣式,有待用戶(hù)自行體驗(yàn),最后有demo提供。

可以有調(diào)整尺寸的手柄:

可以點(diǎn)住客戶(hù)區(qū)拖動(dòng):

別的一些應(yīng)用:

這些都只是demo,沒(méi)那么好看和強(qiáng)大,重點(diǎn)是有了這個(gè)FloatLayerBase,就可以實(shí)現(xiàn)自己的浮動(dòng)應(yīng)用。

使用說(shuō)明:確保FloatLayerBase類(lèi)在項(xiàng)目中~廢話(huà)。源碼在此:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace AhDung.WinForm.Controls
{
  /// <summary>
  /// 浮動(dòng)層基類(lèi)
  /// </summary>
  public class FloatLayerBase : Form
  {
    /// <summary>
    /// 鼠標(biāo)消息篩選器
    /// </summary>
    //由于本窗體為WS_CHILD,所以不會(huì)收到在窗體以外點(diǎn)擊鼠標(biāo)的消息
    //該消息篩選器的作用就是讓本窗體獲知鼠標(biāo)點(diǎn)擊情況,進(jìn)而根據(jù)鼠標(biāo)是否在本窗體以外的區(qū)域點(diǎn)擊,做出相應(yīng)處理
    readonly AppMouseMessageHandler _mouseMsgFilter;

    /// <summary>
    /// 指示本窗體是否已ShowDialog過(guò)
    /// </summary>
    //由于多次ShowDialog會(huì)使OnLoad/OnShown重入,故需設(shè)置此標(biāo)記以供重入時(shí)判斷
    bool _isShowDialogAgain;

    //邊框相關(guān)字段
    BorderStyle _borderType;
    Border3DStyle _border3DStyle;
    ButtonBorderStyle _borderSingleStyle;
    Color _borderColor;

    /// <summary>
    /// 獲取或設(shè)置邊框類(lèi)型
    /// </summary>
    [Description("獲取或設(shè)置邊框類(lèi)型。")]
    [DefaultValue(BorderStyle.Fixed3D)]
    public BorderStyle BorderType
    {
      get { return _borderType; }
      set
      {
        if (_borderType == value) { return; }
        _borderType = value;
        Invalidate();
      }
    }

    /// <summary>
    /// 獲取或設(shè)置三維邊框樣式
    /// </summary>
    [Description("獲取或設(shè)置三維邊框樣式。")]
    [DefaultValue(Border3DStyle.RaisedInner)]
    public Border3DStyle Border3DStyle
    {
      get { return _border3DStyle; }
      set
      {
        if (_border3DStyle == value) { return; }
        _border3DStyle = value;
        Invalidate();
      }
    }

    /// <summary>
    /// 獲取或設(shè)置線(xiàn)型邊框樣式
    /// </summary>
    [Description("獲取或設(shè)置線(xiàn)型邊框樣式。")]
    [DefaultValue(ButtonBorderStyle.Solid)]
    public ButtonBorderStyle BorderSingleStyle
    {
      get { return _borderSingleStyle; }
      set
      {
        if (_borderSingleStyle == value) { return; }
        _borderSingleStyle = value;
        Invalidate();
      }
    }

    /// <summary>
    /// 獲取或設(shè)置邊框顏色(僅當(dāng)邊框類(lèi)型為線(xiàn)型時(shí)有效)
    /// </summary>
    [Description("獲取或設(shè)置邊框顏色(僅當(dāng)邊框類(lèi)型為線(xiàn)型時(shí)有效)。")]
    [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窗體才不會(huì)搶父窗體焦點(diǎn)
        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;
      }
    }

    //構(gòu)造函數(shù)
    public FloatLayerBase()
    {
      //初始化消息篩選器。添加和移除在顯示/隱藏時(shí)負(fù)責(zé)
      _mouseMsgFilter = new AppMouseMessageHandler(this);

      //初始化基類(lèi)屬性
      InitBaseProperties();

      //初始化邊框相關(guān)
      _borderType = BorderStyle.Fixed3D;
      _border3DStyle = System.Windows.Forms.Border3DStyle.RaisedInner;
      _borderSingleStyle = ButtonBorderStyle.Solid;
      _borderColor = Color.DarkGray;
    }

    protected override void OnLoad(EventArgs e)
    {
      //防止重入
      if (_isShowDialogAgain) { return; }

      //需得減掉兩層邊框?qū)挾?,運(yùn)行時(shí)尺寸才與設(shè)計(jì)時(shí)完全相符,原因不明
      //確定與ControlBox、FormBorderStyle有關(guān),但具體聯(lián)系不明
      if (!DesignMode)
      {
        Size size = SystemInformation.FrameBorderSize;
        this.Size -= size + size;//不可以用ClientSize,后者會(huì)根據(jù)窗口風(fēng)格重新調(diào)整Size
      }
      base.OnLoad(e);
    }

    protected override void OnShown(EventArgs e)
    {
      //防止重入
      if (_isShowDialogAgain) { return; }

      //在OnShown中為首次ShowDialog設(shè)標(biāo)記
      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)
    {
      //當(dāng)本窗體作為ShowDialog彈出時(shí),在收到WM_SHOWWINDOW前,Owner會(huì)被Disable
      //故需在收到該消息后立即Enable它,不然Owner窗體和本窗體都將處于無(wú)響應(yīng)狀態(tài)
      if (m.Msg == 0x18 && m.WParam != IntPtr.Zero && m.LParam == IntPtr.Zero
        && Modal && Owner != null && !Owner.IsDisposed)
      {
        if (Owner.IsMdiChild)
        {
          //當(dāng)Owner是MDI子窗體時(shí),被Disable的是MDI主窗體
          //并且Parent也會(huì)指向MDI主窗體,故需改回為Owner,這樣彈出窗體的Location才會(huì)相對(duì)于Owner而非MDIParent
          NativeMethods.EnableWindow(Owner.MdiParent.Handle, true);
          NativeMethods.SetParent(this.Handle, Owner.Handle);//只能用API設(shè)置Parent,因?yàn)槟J酱绑w是TopLevel,.Net拒絕為頂級(jí)窗體設(shè)置Parent
        }
        else
        {
          NativeMethods.EnableWindow(Owner.Handle, true);
        }
      }
      base.WndProc(ref m);
    }

    //畫(huà)邊框
    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)//繪制線(xiàn)型邊框
      {
        ControlPaint.DrawBorder(e.Graphics, ClientRectangle, BorderColor, BorderSingleStyle);
      }
    }

    //顯示后添加鼠標(biāo)消息篩選器以開(kāi)始捕捉,隱藏時(shí)則移除篩選器。之所以不放Dispose中是想盡早移除篩選器
    protected override void OnVisibleChanged(EventArgs e)
    {
      if (!DesignMode)
      {
        if (Visible) { Application.AddMessageFilter(_mouseMsgFilter); }
        else { Application.RemoveMessageFilter(_mouseMsgFilter); }
      }
      base.OnVisibleChanged(e);
    }

    //實(shí)現(xiàn)窗體客戶(hù)區(qū)拖動(dòng)
    //在WndProc中實(shí)現(xiàn)這個(gè)較麻煩,所以放到這里做
    protected override void OnMouseDown(MouseEventArgs e)
    {
      //讓鼠標(biāo)點(diǎn)擊客戶(hù)區(qū)時(shí)達(dá)到與點(diǎn)擊標(biāo)題欄一樣的效果,以此實(shí)現(xiàn)客戶(hù)區(qū)拖動(dòng)
      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">觸發(fā)彈出窗體的控件</param>
    /// <param name="offsetX">相對(duì)control水平偏移</param>
    /// <param name="offsetY">相對(duì)control垂直偏移</param>
    public DialogResult ShowDialog(Control control, int offsetX, int offsetY)
    {
      return ShowDialog(control, new Point(offsetX, offsetY));
    }

    /// <summary>
    /// 顯示為模式窗體
    /// </summary>
    /// <param name="control">觸發(fā)彈出窗體的控件</param>
    /// <param name="offset">相對(duì)control偏移</param>
    public DialogResult ShowDialog(Control control, Point offset)
    {
      return this.ShowDialogInternal(control, offset);
    }

    /// <summary>
    /// 顯示為模式窗體
    /// </summary>
    /// <param name="item">顯示在該工具欄項(xiàng)的下方</param>
    public DialogResult ShowDialog(ToolStripItem item)
    {
      return ShowDialog(item, 0, item.Height);
    }

    /// <summary>
    /// 顯示為模式窗體
    /// </summary>
    /// <param name="item">觸發(fā)彈出窗體的工具欄項(xiàng)</param>
    /// <param name="offsetX">相對(duì)item水平偏移</param>
    /// <param name="offsetY">相對(duì)item垂直偏移</param>
    public DialogResult ShowDialog(ToolStripItem item, int offsetX, int offsetY)
    {
      return ShowDialog(item, new Point(offsetX, offsetY));
    }

    /// <summary>
    /// 顯示為模式窗體
    /// </summary>
    /// <param name="item">觸發(fā)彈出窗體的工具欄項(xiàng)</param>
    /// <param name="offset">相對(duì)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">觸發(fā)彈出窗體的控件</param>
    /// <param name="offsetX">相對(duì)control水平偏移</param>
    /// <param name="offsetY">相對(duì)control垂直偏移</param>
    public void Show(Control control, int offsetX, int offsetY)
    {
      Show(control, new Point(offsetX, offsetY));
    }

    /// <summary>
    /// 顯示窗體
    /// </summary>
    /// <param name="control">觸發(fā)彈出窗體的控件</param>
    /// <param name="offset">相對(duì)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">觸發(fā)彈出窗體的工具欄項(xiàng)</param>
    /// <param name="offsetX">相對(duì)item水平偏移</param>
    /// <param name="offsetY">相對(duì)item垂直偏移</param>
    public void Show(ToolStripItem item, int offsetX, int offsetY)
    {
      Show(item, new Point(offsetX, offsetY));
    }

    /// <summary>
    /// 顯示窗體
    /// </summary>
    /// <param name="item">觸發(fā)彈出窗體的工具欄項(xiàng)</param>
    /// <param name="offset">相對(duì)item偏移</param>
    public void Show(ToolStripItem item, Point offset)
    {
      this.ShowInternal(item, offset);
    }

    /// <summary>
    /// ShowDialog內(nèi)部方法
    /// </summary>
    private DialogResult ShowDialogInternal(Component controlOrItem, Point offset)
    {
      //快速連續(xù)彈出本窗體將有可能遇到尚未Hide的情況下再次彈出,這會(huì)引發(fā)異常,故需做處理
      if (this.Visible) { return System.Windows.Forms.DialogResult.None; }

      this.SetLocationAndOwner(controlOrItem, offset);
      return base.ShowDialog();
    }

    /// <summary>
    /// Show內(nèi)部方法
    /// </summary>
    private void ShowInternal(Component controlOrItem, Point offset)
    {
      if (this.Visible) { return; }//原因見(jiàn)ShowDialogInternal

      this.SetLocationAndOwner(controlOrItem, offset);
      base.Show();
    }

    /// <summary>
    /// 設(shè)置坐標(biāo)及所有者
    /// </summary>
    /// <param name="controlOrItem">控件或工具欄項(xiàng)</param>
    /// <param name="offset">相對(duì)偏移</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;

      //設(shè)置Owner屬性與Show[Dialog](Owner)有不同,當(dāng)Owner是MDIChild時(shí),后者會(huì)改Owner為MDIParent
      this.Owner = c.FindForm();
    }

    /// <summary>
    /// 獲取控件在窗體中的坐標(biāo)
    /// </summary>
    private static Point GetControlLocationInForm(Control c)
    {
      Point pt = c.Location;
      while (!((c = c.Parent) is Form))
      {
        pt.Offset(c.Location);
      }
      return pt;
    }

    #region 屏蔽對(duì)本類(lèi)影響重大的基類(lèi)方法和屬性

    /// <summary>
    /// 初始化部分基類(lèi)屬性
    /// </summary>
    private void InitBaseProperties()
    {
      base.ControlBox = false;              //重要
      //必須得是SizableToolWindow才能支持調(diào)整大小的同時(shí),不受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("請(qǐng)使用別的重載!", true)]
    public new DialogResult ShowDialog() { throw new NotImplementedException(); }

    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("請(qǐng)使用別的重載!", true)]
    public new DialogResult ShowDialog(IWin32Window owner) { throw new NotImplementedException(); }

    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("請(qǐng)使用別的重載!", true)]
    public new void Show() { throw new NotImplementedException(); }

    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("請(qǐng)使用別的重載!", 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("設(shè)置邊框請(qǐng)使用Border相關(guān)屬性!", 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>
    /// 程序鼠標(biāo)消息篩選器
    /// </summary>
    private class AppMouseMessageHandler : IMessageFilter
    {
      readonly FloatLayerBase _layerForm;

      public AppMouseMessageHandler(FloatLayerBase layerForm)
      {
        _layerForm = layerForm;
      }

      public bool PreFilterMessage(ref Message m)
      {
        //如果在本窗體以外點(diǎn)擊鼠標(biāo),隱藏本窗體
        //若想在點(diǎn)擊標(biāo)題欄、滾動(dòng)條等非客戶(hù)區(qū)也要讓本窗體消失,取消0xA1的注釋即可
        //本例是根據(jù)坐標(biāo)判斷,亦可以改為根據(jù)句柄,但要考慮子孫控件
        //之所以用API而不用Form.DesktopBounds是因?yàn)楹笳卟豢煽?
        if ((m.Msg == 0x201/*|| m.Msg==0xA1*/)
          && _layerForm.Visible && !NativeMethods.GetWindowRect(_layerForm.Handle).Contains(MousePosition))
        {
          _layerForm.Hide();//之所以不Close是考慮應(yīng)該由調(diào)用者負(fù)責(zé)銷(xiāo)毀
        }

        return false;
      }
    }

    /// <summary>
    /// API封裝類(lèi)
    /// </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類(lèi);也可以新建普通窗體,然后把基類(lèi)由Form改為FloatLayerBase
在設(shè)計(jì)器和源碼中打造浮動(dòng)應(yīng)用
在需要的地方使用它。關(guān)于使用,先看一下FloatLayerBase的部分公開(kāi)成員:

//屬性
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個(gè)屬性都是跟邊框有關(guān)的,邊框總共有3種形態(tài),三維、線(xiàn)型、無(wú),由BorderType指定;當(dāng)為三維形態(tài)時(shí),由Border3DStyle指定具體樣式;為線(xiàn)型時(shí),由BorderSingleStyle和BorderColor分別指定具體線(xiàn)型和顏色。原Form.FormBorderStyle屬性已被屏蔽,不允許子類(lèi)訪(fǎng)問(wèn),還有若干原Form的屬性也已屏蔽,原因都在源碼里。另外,原Form.SizeGripStyle照常使用,是否允許調(diào)整浮動(dòng)層大小就靠它了

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

鼠標(biāo)只會(huì)點(diǎn)在本程序內(nèi)的窗體中時(shí),讓浮動(dòng)層消失。點(diǎn)在程序外的窗口、桌面、任務(wù)欄這些則不會(huì)。為什么要這樣是因?yàn)橐龅酵耆裼益I菜單那樣對(duì)全局鼠標(biāo)敏感,需要全局鉤子,這會(huì)增加代碼量(性能且不說(shuō),沒(méi)測(cè)過(guò)不妄言),而且我認(rèn)為沒(méi)必要全局敏感浮動(dòng)層消失是調(diào)用Hide方法,所以對(duì)于模式化打開(kāi)的浮動(dòng)層,會(huì)返回DialogResult.Cancel,這是.net對(duì)模式對(duì)話(huà)框的設(shè)計(jì)使然,模式對(duì)話(huà)框被Hide或Close時(shí),就是返回Cancel。在此也提醒一下調(diào)用者,在使用模式對(duì)話(huà)框時(shí),永遠(yuǎn)考慮有返回Cancel這種情況,不限于本例,而是所有對(duì)話(huà)框

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

其它:

編寫(xiě)期間一直使用PopupFormBase作為類(lèi)名,發(fā)布最后時(shí)刻才改為現(xiàn)在的FloatLayerBase,所以demo中可能尚有依據(jù)原名起名的子類(lèi)、方法名等。

Demo下載:

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

里面有個(gè)Tester供您體驗(yàn)。

相關(guān)文章

  • c#英文單詞分類(lèi)統(tǒng)計(jì)示例分享

    c#英文單詞分類(lèi)統(tǒng)計(jì)示例分享

    本文給出的題目是給出一段英文,對(duì)其分類(lèi)統(tǒng)計(jì)出英文單詞的個(gè)數(shù)如:長(zhǎng)度為4的單詞有2個(gè),長(zhǎng)度為3的有1個(gè),下面是題目答案
    2014-03-03
  • c#關(guān)于JWT跨域身份驗(yàn)證的實(shí)現(xiàn)代碼

    c#關(guān)于JWT跨域身份驗(yàn)證的實(shí)現(xiàn)代碼

    這篇文章主要介紹了c#關(guān)于JWT跨域身份驗(yàn)證的實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • C#實(shí)現(xiàn)讀取指定盤(pán)符硬盤(pán)序列號(hào)的方法

    C#實(shí)現(xiàn)讀取指定盤(pán)符硬盤(pán)序列號(hào)的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)讀取指定盤(pán)符硬盤(pán)序列號(hào)的方法,涉及C#針對(duì)硬件屬性的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2016-08-08
  • C#實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出任一Word圖表的通用呈現(xiàn)方法

    C#實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出任一Word圖表的通用呈現(xiàn)方法

    應(yīng)人才測(cè)評(píng)產(chǎn)品的需求,導(dǎo)出測(cè)評(píng)報(bào)告是其中一個(gè)重要的環(huán)節(jié),報(bào)告的文件類(lèi)型也多種多樣,其中WORD輸出也扮演了一個(gè)重要的角色,本文給大家介紹了C#實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出任一Word圖表的通用呈現(xiàn)方法及一些體會(huì),需要的朋友可以參考下
    2023-10-10
  • unity 如何獲取Text組件里text內(nèi)容的長(zhǎng)度

    unity 如何獲取Text組件里text內(nèi)容的長(zhǎng)度

    這篇文章主要介紹了unity 獲取Text組件里text內(nèi)容的長(zhǎng)度操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • 探討如何用委托處理排序

    探討如何用委托處理排序

    本篇文章是對(duì)用委托處理排序進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • C# 多線(xiàn)程讀取注冊(cè)表,加載至TreeView

    C# 多線(xiàn)程讀取注冊(cè)表,加載至TreeView

    C#下多線(xiàn)程讀取注冊(cè)表,加載至TreeView的實(shí)現(xiàn)代碼。
    2009-09-09
  • C#中常用的正則表達(dá)式實(shí)例

    C#中常用的正則表達(dá)式實(shí)例

    正則表達(dá)式在程序設(shè)計(jì)中有著重要的位置,它經(jīng)常被用于處理字符串信息,下面是C#中常用的正則表達(dá)式實(shí)例,感興趣的朋友一起看看吧
    2016-10-10
  • 淺析C#中文件路徑的操作

    淺析C#中文件路徑的操作

    在.NET類(lèi)庫(kù)中,有一個(gè)專(zhuān)門(mén)的功能類(lèi)System.IO.Path,對(duì)表示文件或在目錄路徑的string進(jìn)行操作。本文介紹下利用Path來(lái)對(duì)文件路徑進(jìn)行的一些經(jīng)常用操作。感興趣的朋友可以看下
    2016-12-12
  • C#微信接口之推送模板消息功能示例

    C#微信接口之推送模板消息功能示例

    這篇文章主要介紹了C#微信接口之推送模板消息功能,結(jié)合實(shí)例形式分析了C#操作微信推送模板消息接口的具體操作步驟與相關(guān)使用技巧,需要的朋友可以參考下
    2017-07-07

最新評(píng)論