制作停靠窗體、懸浮窗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復制到當前項目的        FloatingForm\FloatingForm\bin\Debug文件下。

(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();
                }
            }
        } 
 
 

 

 

 

 


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM