zoukankan      html  css  js  c++  java
  • 制作停靠窗体、悬浮窗Dockpanel

    此功能在借鉴以下链接博文后验证实现,特此感谢,并做补充转发分享!

    http://blog.csdn.net/why_dx/article/details/8751976

    http://blog.csdn.net/jun502525164/article/details/9079481

    http://blog.sina.com.cn/s/blog_9136935e0102vr38.html

    http://blog.csdn.net/zzzhaohaizi/article/details/7064823

    --------------------------------------------------------------  分割线  ----------------------------------------------------

     

    利用DockPanel与C#制作窗体浮动和停靠

     C#Visual Studio 2010DockPanel窗体浮动与停靠
     

    点击功能窗  然后鼠标拖动form2的效果图如下

     

    在SF上能下到最新的版本的DLL和演示

    解压文件得到如下图文件:

      

    2、构建主窗体(父窗体):frmMain的。

         (1)新建工程:FloatingForm
         (2)将DockPanel.config和WeifenLuo.WinFormsUI.Docking.dll复制到当前项目的        FloatingFormFloatingForminDebug文件下。

    (3)首先添加引用WeifenLuo.WinFormsUI.Docking。
                   然后点击工具箱右键添加DockPanel控件到工具箱中。

         (4)添加主窗体frmMain中,并设置主窗体的IsMdiContainer =true;
         (5)在主窗体中添加的DockPanel控件:DockPanel1,并设置DockPanel中的documentstyle:                    dockPanel.DocumentStyle = DocumentStyle.DockingMdi;

    frmMain的界面如下:(如果添加dockpanel控件到frmMain出现错误则转到注意事项查看)

    后台代码如下:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    using WeifenLuo.WinFormsUI.Docking;
    using System.IO;

    namespace FloatingForm
    {
    public partial class frmMain : Form
    {
    public frmMain()
    {
    InitializeComponent();
    }
    private string m_DockPath = string.Empty;

    private void Form1_Load(object sender, EventArgs e)
    {
    this.DockPanel1.DocumentStyle = DocumentStyle.DockingMdi;
    this.m_DockPath=Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"DockPanel.config");
    this.InitDockPanel();
    this.StatusBar.Items.Add("就绪"); //这是状态栏的,可要可不要,不影响!
    }

    #region 按照配置文件初始化Dockpanel
    private void InitDockPanel()
    {
    try
    {
    //根据配置文件动态加载浮动窗体
    this.DockPanel1.LoadFromXml(this.m_DockPath, delegate(stringpersistString)
    {
    //功能窗体
    if (persistString ==typeof(frmFunction).ToString())
    {
    returnfrmFunction.GetInstance();
    }
    //主框架之外的窗体不显示
    return null;
    });
    }
    catch (Exception)
    {
    // 配置文件不存在或配置文件有问题时按系统默认规则加载子窗体
    frmFunction.GetInstance().Show(this.DockPanel1);
    }
    }
    #endregion
    private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
    {
    try
    {
    //为了下次打开程序时,浮动窗体的显示位置和关闭时一致,
    DockPanel1.SaveAsXml(this.m_DockPath);
    }
    catch (Exception ex)
    {
    MessageBox.Show("保存Dockpanel配置文件失败," + ex.Message);
    return;
    }
    }
     
    private void dockPanel1ToolStripMenuItem_Click(object sender, EventArgse)
    {
    frmFunction frmFun = frmFunction.GetInstance();
    frmFun.Show(this.DockPanel1, AppConfig.ms_FrmFunction);
    this.StatusBar.Items[0].Text = frmFun.Text;
    }
    }
    }

    3. 构建需要浮动显示的窗体:FrmFunction。

    (1)在当前工程中添加窗体:FrmFunction;(注意:浮动窗体和标签窗体需要继承自DockContent);
    (2)为了保证在关闭某一浮动窗体之后,再打开时能够在原位置显示,要对浮动窗体处理,处理窗体的    DockstateChanged事件,标签窗体dock位置改变,记录到公共类;

    frmFunction界面如下:(所要浮动的窗体)

     

    后台代码如下:

     1 using System;
     2 
     3 using System.Collections.Generic;
     4 
     5 using System.ComponentModel;
     6 
     7 using System.Data;
     8 
     9 using System.Drawing;
    10 
    11 using System.Linq;
    12 
    13 using System.Text;
    14 
    15 usingSystem.Windows.Forms;
    16 
    17 usingWeifenLuo.WinFormsUI.Docking;
    18 
    19  
    20 
    21 namespace FloatingForm
    22 
    23 {
    24 
    25    public partial class frmFunction : DockContent
    26 
    27     {
    28 
    29        private static frmFunctionInstance;
    30 
    31  
    32 
    33        public frmFunction()
    34 
    35        {
    36 
    37            InitializeComponent();
    38 
    39        }
    40 
    41        public static frmFunction GetInstance()
    42 
    43         {
    44 
    45             if (Instance == null)
    46 
    47             {
    48 
    49                 Instance = new frmFunction();
    50 
    51             }
    52 
    53             return Instance;
    54 
    55         }
    56 
    57     //为了保证在关闭某一浮动窗体之后,再打开时能够在原位置显示,要对浮动窗体处理,处理窗体的DockstateChanged事件,标签窗体dock位置改变,记录到公共类
    58 
    59        private void FrmFunction_DockStateChanged(object sender, EventArgs e)
    60 
    61        {
    62 
    63            //关闭时(dockstate为unknown) 不把dockstate保存 
    64 
    65             if (Instance != null)
    66 
    67             {
    68 
    69                 if (this.DockState ==DockState.Unknown || this.DockState == DockState.Hidden)
    70 
    71                {
    72 
    73                     return;
    74 
    75                 }
    76 
    77               AppConfig.ms_FrmFunction =this.DockState;
    78 
    79             }
    80 
    81        }  
    82 
    83        private void FrmFunction_FormClosing(object sender, FormClosingEventArgse)
    84 
    85        {
    86 
    87            Instance = null;  // 否则下次打开时报错,提示“无法访问已释放对象”
    88 
    89        }
    90 
    91  
    92 
    93     }
    94 
    95 }
    View Code

    4. 在当前工程中添加类AppConfig(公共类)。

    代码如下:

     1 using System;
     2 
     3 using System.Collections.Generic;
     4 
     5 using System.Linq;
     6 
     7 using System.Text;
     8 
     9 using WeifenLuo.WinFormsUI.Docking;
    10 
    11  
    12 
    13 namespace FloatingForm
    14 
    15 {
    16 
    17    class AppConfig
    18 
    19    {   
    20 
    21         public static DockState ms_FrmFunction =DockState.DockLeft;   // 功能窗体,左端停靠  
    22 
    23     }
    24 
    25 }
    View Code

    5.成功运行,实现基本功能(停靠在中间的效果图)


    注意事项

    问题(1)描述:

          vs2010添加WeifenLuo.WinFormsUI.Docking.DockPanel.dll文件后,从工具栏中添加DockPanel控件时报错,提示【类型 Universe 无法解析程序集: System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a。】

    解决方法:

           打开【项目】的FloatingForm属性,选择【应用程序】,,修改【目标Framework(所有配置)】选项,在下拉框选项中选择【.net Framework 4】即可。


     
     --------------------------------------------------------- 分割线二 ---------------------------------------------------

    dockpanel中提供了几个可用的类, 重要的有两个, 一是DockPanel, 一是DockContent,

    DockPanel是从panel继承出来的, 用于提供可浮动的dock的子窗口进行浮动和dock的场所,

    DockContent是从form类中继承出来的, 用于提供可浮动的窗口基类. 就是说: DockContent对象可以在DockPanel对象中任意贴边, 浮动, TAB化等.

    WeiFenLuo.winFormsUI.Docking.dll的使用

    1.建立一个WinForm工程,默认生成了一个WinForm窗体Form1。

    2.引用—>添加引用—>浏览—>weiFenLuo.winFormsUI.Docking.dll。

    3.窗体属性IsMdiContainer设置为True。

    4.工具箱—>右键—>选择项—>.net组件—>浏览—>weiFenLuo.winFormsUI.Docking.dll—>在工具箱出现dockPanel。

    5.将dockPanel拖到窗体Form1上,设置Dock属性,我设置的是:Fill。

    停靠窗体:

    1.新建一个WinForm窗体Form2。

    2.在代码中修改窗体继承于DockContent。

        public partial class Form2 : DockContent

        {

            Form1 form1;

            private DockPanel dp;

            public Form2()

            {

                InitializeComponent();

            }

            public Form2(Form1 fm1)

            {

                form1 = fm1;

                dp = (DockPanel)form1.Controls["dockPanel1"];

            }

        }

    3.在主窗体Form1中显示停靠窗体。

    private void Form1_Load(object sender, EventArgs e)

    {

      Form2 form2 = new Form2();

      form2.Show(this.dockPanel1, DockState.DockLeft);

    }

    dockpanel中其他几个类

    DockWindow:用来划分dockpanel.

              在一个DockPanel上面还有几个DockWindow把DockPanel分成了几块. 默认DockPanel用DockWindow创建了五个区域, 分别是DockTop, DockBottom, DockLeft, DockRight和Document, 任何一个DockPane都棣属于这五个区域中的某一个. DockPanel就是通过DockWindow来管理DockPane的所在位置的.

    DockPane:

              DockPanelSuit的一个基本显示单元, 最终用户看到的UI都是由DockPane组合而来的

    FloatWindow:

             事实上, FloatWindow跟DockPane是同等的, 只不过DockPane是附在DockWindow上, 而FloatWindow是一个浮动窗口而已. 显然, FloatWindow是一个Form, DockPanel管理着FloatWindow跟DockPane之间的转换, 而这个转换过程也无非就是把DockContent从FloatWindow转到DockPane上, 或者把DockContent从DockPane转到FloatWindow上, 然后显示出来

    DockPanel的使用

    1.建立一个WinForm工程,默认生成了一个WinForm窗体Form1。

    2.引用—>添加引用—>浏览—>weiFenLuo.winFormsUI.Docking.dll。

    3.设置Form1窗体属性IsMdiContainer:True

    4.工具箱—>右键—>选择项—>.net组件—>浏览—>weiFenLuo.winFormsUI.Docking.dll—>在工具箱出现dockPanel。

    5.将dockPanel拖到窗体Form1上,设置Dock属性,我设置的是:Fill。

    停靠窗体:

    1.新建一个WinForm窗体Form2。

    2.在代码中修改窗体继承于DockContent。

    using WeifenLuo.WinFormsUI.Docking;

    public partial class Form2 : DockContent

    3.在主窗体Form1中显示停靠窗体。

    private void Form1_Load(object sender, EventArgs e)

    {

      Form2 form2 = new Form2();

      form2.Show(this.dockPanel1);

    }

    如果dockPanel嵌套在另1个容器控件上(如:panel),将dockPanel属性DocumentStyle设置为:DockingWindow/DockingSdi

    Dockpanel 使用技巧 

    DockPanel的基本使用 我就不说了,网上很多,我想说的是在使用DockPanel时 需要注意的几个小问题

    第一个:

    使用过DockPanel的人,都有可能会遇到这样一个错误:

    Invalid Content: ActiveContent must be one of the visible contents, or null if there is no visible content.

    翻译过来的意思大致是:无效的内容: 如果没有一个可见的内容,ActiveContent必须是可见的内容或空。

    具体是什么原因,大家可以相互探讨下。下面我说说出现这个问题的几种情况

    代码中的this关键字代表的就是Dockpanel所在的窗体为Form1

    1)、当Dockpanel的DocumentStyle不为DockingMdi时,以下代码会出现这个问题      

           Frm_A frmA = null;
           //判断子窗体中是否已经存在在DockPanel中
           foreach (DockContent frm in this.dockPanel1.Contents)
            {
                 if (frm is Frm_A)
                  {
                        frm.Activate();     //激活子窗体
                        return;
                  }
                }

                frmA = new Frm_A();
                frmA.MdiParent = this;
                frmA.Show(this.dockPanel1);

            解决方案:看你设置Dockpanel的DocumnetStyle是否为DockingMdi。大家也可以试试其他几种方式(DockingWindow,DockingSdi,SystemMdi)

    2)、设置了Dockpanel的DocumentStyle不为DockingMdi时,如果你想要设置窗体Frm_B为左边浮动窗体,需要设置窗体Frm_B的DockAreas为且仅为DockLeft,如果想要实现其他功能可自行去设置其他属性信息,现在请看下面代码

                Frm_B frmB = null;
                //判断子窗体中是否已经存在在DockPanel中
                foreach (DockContent frm in this.dockPanel1.Contents)
                {
                    if (frm is Frm_B)
                    {
                        frm.Activate();     //激活子窗体
                        return;
                    }
                }

                frmB = new Frm_B();
               //frmB.MdiParent = this;
                frmB.Show(this.dockPanel1,DockState.DockLeft);

                注意,如果你在你的代码中加了红色注释的代码,那么程序运行时 也会报上面的那个错

                解决方案:注释红色的代码。

                原因:(个人理解)frmB.Show(this.dockPanel1,DockState.DockLeft);这句代码其实就设置了frmB只停靠在DockPanel左边,此时的frmB是不属于MDI子窗体的,所以一旦你加入红色的代码,程序就会报错。

    第二个:

    拖动、停靠、固定子窗体(显示在Dockpanel中)

    拖动:如果你想使你的子窗体可以任意拖动,那么你在设置子窗体的DockAreas属性时,保持默认值,不要修改。

    停靠:首先你需设置DockAreas的位置,可以停靠在左、右、下等,也可以通过程序代码控制,参考上面代码。

    固定:只需设置你窗体的DockAreas为Document就行了

    第三个:

    子窗体和Contents的判断

    很多时候你需要判断Dockpanel中存在多少个子窗体或Contents,请参考下面代码:

    foreach(Form in this.MdiChildren)

    {

          //这样判断时,停靠的窗体是不会计算在内的

    }

    foreach (DockContent frm in this.dockPanel1.Contents)
    {

         //这样设置后,所有的继承与DockContent的窗体都会被计算在内的

    }

    第四个:

    寻找主窗体、动态显示子窗体

    实现的功能:这里我们需要实现,右键点击A窗体,通过右键菜单来显示窗体B。

     1   //主窗体的对象
     2   Form1 form1;
     3 
     4 private void showB_Click(object senders, EventArgs e)
     5 {
     6 
     7            GetFrmMain();  //通过此函数来获取form1     
     8 
     9            foreach (Form frm in form1.MdiChildren)
    10             {
    11                 if (frm is Frm_B)
    12                 {
    13                     frm.Activate();
    14                     return;
    15                 }
    16             }
    17 
    18             Frm_B frmB = new Frm_B(this);
    19             frmB.MdiParent = form1;
    20             frmB.Show(form1.dockPanel1);
    21 
    22 }
    23 
    24 private void GetFrmMain()
    25 
    26 {
    27 
    28               if (this.Parent.Parent.Parent.Parent != null)
    29                 {
    30                     form1 = (Form1)this.Parent.Parent.Parent.Parent;
    31                 }
    32                 else
    33                 {
    34                     form1 = (Form1)this.Parent.Parent.Parent;
    35                 }
    36 
    37 }
    View Code

    现在是在A窗体中,this关键字已经代码的不是主窗体了,那么这里我们就需要获取主窗体对象

    当A窗体停靠时,需要this.Parent.Parent.Parent.Parent(四个)

    不停靠时,只需要三个this.Parent.Parent.Parent

    调试代码发现:停靠时

    this.Parent 为 {WeifenLuo.WinFormsUI.Docking.DockPane}

    this.Parent.Parent 为 {WeifenLuo.WinFormsUI.Docking.DockWindow, BorderStyle: System.Windows.Forms.BorderStyle.None}

    this.Parent.Parent.Parent 为 {WeifenLuo.WinFormsUI.Docking.DockPanel, BorderStyle: System.Windows.Forms.BorderStyle.None}

    this.Parent.Parent.Parent 为 {TestEvenhandler.Form1, Text: Form1} 就是我们要找的主窗体Form1

    不停靠时:

    this.Parent 为 {WeifenLuo.WinFormsUI.Docking.DockPane}

    this.Parent.Parent 为 {WeifenLuo.WinFormsUI.Docking.DockPanel+AutoHideWindowControl, BorderStyle: System.Windows.Forms.BorderStyle.None}

    this.Parent.Parent.Parent 为 {TestEvenhandler.Form1, Text: Form1} 就是我们要找的主窗体Form1

    DockPanel使用方法

    DockPanel有人曰浮动窗体,也就是c#编辑器的样式,如下图:

    浮动窗体可以浮动、停靠(上下左右)、分页(如上图的档案录入页面)。

     以下记录以下使用方法:

    (1)首先找到WeifenLuo.WinFormsUI.Docking.dll,下载WeifenLuo.WinFormsUI.Docking.dll组建(点击下载)

    (2)把该组建添加到引用,创建窗体1为主窗体,窗体2、窗体3为子窗体。把dockpanle工具添加上。

    (3)主窗体代码:把dockpanle拖放到主窗体,添加代码 dockPanel1.DocumentStyle = DocumentStyle.DockingMdi;

    (4)子窗体:子窗体继承自: WeifenLuo.WinFormsUI.Docking.DockContent , 不是继承自form;定义子窗体对象

    form1 f1=new form1();

     f1.ShowHint = DockState.Document;
    f1.Show(dockPanel1);

    显示效果即得到。

         另外也记录下状态,下次打开时候任然保持,用以下方法加载记录状态:

    (1)private DeserializeDockContent ddc;

    (2)private IDockContent GetContentFromPersistString(string persistString)
            {
              if (persistString == typeof(f1).ToString())
                    return f1;
                if (persistString == typeof(f2).ToString())
                    return f2;
                   else
               {
                   return null;
                }
            }

    (3)

    string configFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "DockPanel.config");
    if (File.Exists(configFile))
                dockPanel1.LoadFromXml(configFile, ddc);
                ddc = new DeserializeDockContent(GetContentFromPersistString);

    以上方法加载保存的状态,

    string configFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "DockPanel.config");
                dockPanel1.SaveAsXml(configFile);

     另外,要实现各个dockpanle子窗体之间的互动,例如,vs编辑器中,设计界面的时候,选择一个文本框,属性框中的属性随之改变,使用委托可以解决,可以参看本博客的委托应用1.

    布局控件"WeifenLuo.WinFormsUI.Docking"是一个非常棒的开源控件,用过的人都深有体会,该控件之强大、美观、不亚于商业控件。而且控件使用也是比较简单的。先看看控件使用的程序界面展示效果。

      我在几个共享软件都使用了该布局控件,我们先以“深田之星送水管理系统网络版”这款软件为例,介绍如何完成该界面的设计及显示的。

      1、首先,我们添加一个主界面窗体,命名为MainForm,该窗体IsMdiContainer设置为True,也就是设置为多文档窗体格式。拖拉布局控件"WeifenLuo.WinFormsUI.Docking.DockPanel"到主窗体MainForm中,并设置下面几个属性:

      Dock为Fill、DocumentStyle为DockingMdi、RightToLeftLayout为True。

      这几个属性的意思应该不难,Dock就是 覆盖整个MDI窗体的区域,DocumentStyle为多文档类型、RightToLeftLayout是指新打开的窗口都停靠在右边区域。

     

      2、主界面其实基本上就可以了,另外我们看到“送水管理系统网络版”的界面中有一个左边的工具栏,它其实也是在一个停靠的窗体中的,我们增加一个窗体用来承载相关的工具快捷键按钮展示。命名为MainToolWindow的窗体,继承自WeifenLuo.WinFormsUI.Docking.DockContent.

      其中的“HideOnClose”属性很重要,该属性一般设置为True,就是指你关闭窗口时,窗体只是隐藏而不是真的关闭。

      左边的窗口MainToolWindow实现停靠的代码是在MainForm的构造函数或者Load函数中加载即可。

      mainToolWin.Show(this.dockPanel, DockState.DockLeft);

      3、对于工具窗口我们已经完成了,但是主业务窗口还没有做,也就是下面的部分内容。

      为了方便,我们定义一个基类窗体,命名为BaseForm,继承自DockContent,如下所示

      public class BaseForm : DockContent

      然后每个业务窗口继承BaseForm即可。

      4、剩下的内容就是如何在主窗体MainForm中展示相关的业务窗口了,展示的代码如下所示

     1  public partial class MainForm : Form
     2     {
     3         #region 属性字段
     4   
     5          private MainToolWindow mainToolWin = new MainToolWindow();
     6         private FrmProduct frmProduct = new FrmProduct();
     7         private FrmCustomer frmCustomer = new FrmCustomer();
     8         private FrmOrder frmOrder = new FrmOrder();
     9         private FrmStock frmStock = new FrmStock();
    10         private FrmComingCall frmComingCall = new FrmComingCall();
    11         private FrmDeliving frmDeliving = new FrmDeliving();
    12         private FrmTicketHistory frmHistory = new FrmTicketHistory(); 
    13   
    14         #endregion
    15   
    16         public MainForm()
    17         {
    18             InitializeComponent();
    19   
    20             SplashScreen.Splasher.Status = "正在展示相关的内容dockPanel用法";
    21             System.Threading.Thread.Sleep(100);
    22   
    23             mainToolWin.Show(this.dockPanel, DockState.DockLeft);
    24             frmComingCall.Show(this.dockPanel);
    25             frmDeliving.Show(this.dockPanel);
    26             frmHistory.Show(this.dockPanel);
    27             frmStock.Show(this.dockPanel);
    28             frmProduct.Show(this.dockPanel);
    29             frmCustomer.Show(this.dockPanel);
    30             frmOrder.Show(this.dockPanel);
    31   
    32             SplashScreen.Splasher.Status = "初始化完毕dockPanel用法";
    33             System.Threading.Thread.Sleep(50);
    34   
    35             SplashScreen.Splasher.Close();
    36         }
    37   
    private void menu_Window_CloseAll_Click(object sender, EventArgs e)
            {
                CloseAllDocuments();
            }
      
            private void menu_Window_CloseOther_Click(object sender, EventArgs e)
            {
                if (dockPanel.DocumentStyle == DocumentStyle.SystemMdi)
                {
                    Form activeMdi = ActiveMdiChild;
                    foreach (Form form in MdiChildren)
                    {
                        if (form != activeMdi)
                        {
                            form.Close();
                        }
                    }
                }
                else
                {
                    foreach (IDockContent document in dockPanel.DocumentsToArray())
                    {
                        if (!document.DockHandler.IsActivated)
                        {
                            document.DockHandler.Close();
                        }
                    }
                }
            }
      
            private DockContent FindDocument(string text)
            {
                if (dockPanel.DocumentStyle == DocumentStyle.SystemMdi)
                {
                    foreach (Form form in MdiChildren)
                    {
                        if (form.Text == text)
                        {
                            return form as DockContent;
                        }
                    }
      
                    return null;
                }
                else
                {
                    foreach (DockContent content in dockPanel.Documents)
                    {
                        if (content.DockHandler.TabText == text)
                        {
                            return content;
                        }
                    }
      
                    return null;
                }
            }
      
            public DockContent ShowContent(string caption, Type formType)
            {
                DockContent frm = FindDocument(caption);
                if (frm == null)
                {
                    frm = ChildWinManagement.LoadMdiForm(Portal.gc.MainDialog, formType) as DockContent;
                }
      
                frm.Show(this.dockPanel);
                frm.BringToFront();
                return frm;
            }
      
            public void CloseAllDocuments()
            {
                if (dockPanel.DocumentStyle == DocumentStyle.SystemMdi)
                {
                    foreach (Form form in MdiChildren)
                    {
                        form.Close();
                    }
                }
                else
                {
                    IDockContent[] documents = dockPanel.DocumentsToArray();
                    foreach (IDockContent content in documents)
                    {
                        content.DockHandler.Close();
                    }
                }
            } 
     
     


  • 相关阅读:
    C++中的模板编程
    C++中的抽象类
    C++中的多态
    C++中的继承
    操作符重载(二)
    操作符重载(一)
    C++中的类与对象模型
    [八省联考2018] 劈配 (网络流+二分)
    CF51F Caterpillar (边双+树形DP)
    CF36E Two Paths (欧拉回路+构造)
  • 原文地址:https://www.cnblogs.com/marvelousone/p/7423174.html
Copyright © 2011-2022 走看看