1. 程式人生 > >C#中如何動態載入DockPanel

C#中如何動態載入DockPanel

因工作需要,在WinForm專案中要求實現動態載入DockPanel。

簡單研究了下,演示程式碼如下:

DockPanel runPanel = dockManager1.AddPanel(DockingStyle.Left);
runPanel.Name = “Dock1”;

DockPanel samePanel = null;
//查詢相同位置是否已有停靠外掛
foreach (DockPanel hasPanel in dockManager1.Panels)
{
if (hasPanel.Name != "Dock1" && hasPanel.Dock = = DockingStyle.Left)
{
    samePanel = hasPanel;
    break;
}
}

if (samePanel != null)
{
    runPanel.DockAsTab(samePanel);
}

runPanel.show();

很簡單幾行程式碼,實現了基本意圖。看起來問題很快解決。

但是實際應用中發現幾個問題:

1、當第一次執行時,dockManager1.AddPanel後dockManager1.Panels.Count值為1;當DockAsTab後,dockManager1.Panels.Count值為3,系統居然自動增加了一個DockPanel。

2、使用DockAsTab方式,新的DockPanel總是在已有DockPanel右邊生成,然後再融合進去,使用者體驗非常差,尤其是主程式中間有Mdi子程式時,總會有螢幕不停閃爍的效果。

這是怎麼回事呢?

通過研究DockPanel的相關文件,終於明白DockPanel的執行機制。

在論述下面的一些觀點前,先說明筆者使用的是DX11版本帶的DockManager和DockPanel控制元件。

一個典型的DockPanel如下圖。它包括DockPanel主體和容器兩個部分。DockPanel中要承載其他控制元件時,控制元件容器必須建立。

在DX中,例項化一個DockPanel有三個方法。第一種方法示例如下:

DockPanel runPanel = new DockPanel();

該方法有兩點需要注意:

Ø        它不會自動建立控制元件容器,需要使用者手工新增,程式碼示例如下:

ControlContainer _dockPanelContainer =new

DevExpress.XtraBars.Docking.ControlContainer()

_dockPanelContainer.Name= "dockPanel_Container";

runPanel.Controls.Add(_dockPanelContainer);

//新增控制元件

runPanel.ControlContainer.Add(newControl());

Ø        它需要手工註冊到DockManager中去

runPanel.Register(dockManager1);

第二種方法是常用的方法,示例如下:

DockPanel runPanel = dockManager1.AddPanel(DockStyle.Left);

它會自動註冊DockPanel到DockManager,同時新增一個ControlContainer。

第三種方法示例如下:

DockPanel runPanel = sameDockPanel.AddPanel();

它由一個已存在的DockPanel建立一個新的DockPanel。

該新DockPanel的ParentPanel不是建立者,而是由系統自己建立的一個PanelContainer,該PanelContainer同時被設定為RootPanel。

停靠模式

DockPanel有兩種停靠模式,Split和Tab模式。

Split模式介面示例如下圖,兩個DockPanel根據實際停靠風格並立在一起。

預設情況下,當我們建立好兩個DockPanel,將它們直接show出來,它們呈現的就是如下圖的Split模式。

Tab模式如下圖,兩個DockPanel是以分頁樣式融合在一起。示例程式碼如下:

using DevExpress.XtraBars.Docking;
// ... 
//建立一個左停靠控制元件
DockPanel panel1 = dockManager1.AddPanel(DockingStyle.Left);
panel1.Text = "runDockPanel1";
//由panel1新增一個停靠控制元件;
//如果直接把panel1和panel2都show出來,我們可以看到它們是Split模式
DockPanel panel2 = panel1.AddPanel();
panel2.Text = " runDockPanel2";
//將二者的共同父容器設定為Tab模式
DockPanel container = panel1.ParentPanel;
container.Tabbed = true;

最後演示效果圖如下:


在這裡需要明確的是:

當某個位置(如左邊)只有一個DockPanel時,該DockPanel的ParentPanel和RootPanel都是自己。當存在兩個及以上DockPanel時,所有DockPanel的ParentPanel和RootPanel都是由系統生成的一個公共DockPanelContainer作為父容器,該容器容納所有同位置的DockPanel。

在關閉同位置的DockPanel時,若只剩下一個DockPanel,則DockPanelContainer會被系統自動釋放。

明白了上面的這些原理,對解決上面提出的兩個問題就找到了答案。

第一個問題如上所述,當同一位置存在兩個或兩個以上的DockPanel時,系統自動生成一個容器來容納。

第二個問題,當在使用DockAsTab前,兩個DockPanel是Split模式,之後才變為Tab模式。解決方法就是使用已存在的DockPanel建立新的DockPanel,然後把二者的ParentPanel設定為Tab模式。

另外在這裡提一下,DockPanel中預設只能放置UserControl,如果使用Form型別,需要把TopLevel設定下,但是放置在DockPanel中的Form太有個性了。

一個典型的Tab模式DockPanel如上圖。

最後,貼出部分實際程式碼供大家參考:

        /// <summary>
        /// 建立停靠控制元件t
        /// </summary>
        /// <param name="sCaption">標題</param>
        /// <param name="sName">名稱</param>
        /// <param name="ctl">控制元件例項</param>
        /// <param name="dock">停靠位置?</param>
        /// <param name="dockManager">停靠管理器</param>
        /// <param name="IsNew">是否多次新建視窗</param>
        /// <returns>停靠物件</returns>
        [DisplayName("建立停靠控制元件")]
        public static DockPanel CreateCtl(string sCaption, string sName, Control ctl, enum_DockLocation dock,
 DockManager dockManager, bool IsNew = false)
        {
            try
            {
                DockManager runDockManager = dockManager;
                DockPanel newDockPanel = null;
                //查詢當前列表中是否已有同名的dockpanel
                DockPanel oldPaneled = null;

                runDockManager.BeginUpdate();

                //如果是多次新建視窗,則不查詢已有Dock
                if (!IsNew)
                {
                    oldPaneled = GetHaveDockPanel(runDockManager, sName);
                }
             

                if (oldPaneled == null)
                {
                    DockingStyle dockStyle = DockingStyle.Float;
                    switch (dock)
                    {
                        case enum_DockLocation.Left:
                            dockStyle = DockingStyle.Left;
                            break;                          
                        case enum_DockLocation.Buttom:
                            dockStyle = DockingStyle.Bottom;
                            break;
                        case enum_DockLocation.Right:
                            dockStyle = DockingStyle.Right;
                            break;
                        case enum_DockLocation.Center:
                            dockStyle = DockingStyle.Fill;
                            break;
                        default:
                            break;
                    }

                    DockPanel samePaneled = GetSameDockPanel(runDockManager, dockStyle, sName);
                    if (samePaneled != null)
                    {
                        newDockPanel = samePaneled.AddPanel();
                        newDockPanel.Dock = DockingStyle.Fill;
                    }
                    else
                    {
                        newDockPanel = runDockManager.AddPanel(dockStyle);
                    }

                    if (newDockPanel != null)
                    {
                        newDockPanel.ID = new System.Guid();
                        newDockPanel.Name = sName;
                        newDockPanel.Text = sCaption;
                        //newDockPanel.Options.ShowAutoHideButton = false;

                        if (ctl is Form)
                        {
                            Form srcForm = ctl as Form;
                            ctl = ControlLoader.CopyForm2Control(srcForm);
                        }
                        ctl.Dock = DockStyle.Fill;
                        ctl.Visible = true;
                        newDockPanel.Width = ctl.Width;
                        newDockPanel.Height = ctl.Height;
                        newDockPanel.Controls.Add(ctl);

                        //浮動停靠窗體處理
                        if (newDockPanel.Dock.Equals(DockingStyle.Float))
                        {
                            newDockPanel.FloatForm.Size = ctl.Size;
                            newDockPanel.FloatForm.StartPosition = FormStartPosition.CenterScreen;
                            newDockPanel.FloatForm.AutoSizeMode = AutoSizeMode.GrowOnly;
                            newDockPanel.FloatForm.AutoSize = true;
                        }

                        newDockPanel.ClosingPanel += new DockPanelCancelEventHandler(ClosingPanel);
                        newDockPanel.ClosedPanel += new DockPanelEventHandler(ClosedPanel);
                    }
                }
                else
                {
                    newDockPanel = samePaneled;
                }
                //在DockManager中註冊當前外掛
                newDockPanel.Register(runDockManager);

                if (newDockPanel.ParentPanel != null)
                {
                    newDockPanel.ParentPanel.Tabbed = true;
                }

                newDockPanel.Visibility = DockVisibility.Visible;
                newDockPanel.Visible = true;

                runDockManager.EndUpdate();

                return newDockPanel;
            }
            catch (Exception ex)
            {
                caCom.XLogErr(ex.Message);
                return null;
            }
        }

部分圖片擷取自DX網站,若有侵權,概不負責。


相關推薦

C#如何動態載入DockPanel

因工作需要,在WinForm專案中要求實現動態載入DockPanel。 簡單研究了下,演示程式碼如下: DockPanel runPanel = dockManager1.AddPanel(DockingStyle.Left); runPanel.Name = “Dock1

WPFStyle檔案的引用——使用xaml程式碼或者C#程式碼動態載入

  WPF中控制元件擁有很多依賴屬性(Dependency Property),我們可以通過編寫自定義Style檔案來控制控制元件的外觀和行為,如同CSS程式碼一般。   總結一下WPF中Style樣式的引用方法:   一、內聯樣式   直接在控制元件

AppDomain 詳解二【轉】-C#動態加載和卸載DLL

all created 新版本 odin generic reflect 可能 params 詳細 在C++中加載和卸載DLL是一件很容易的事,LoadLibrary和FreeLibrary讓你能夠輕易的在程序中加載DLL,然後在任何地方 卸載。在C#中我們也能使用Asse

WPF動態載入XAML的控制元件

原文: WPF中動態載入XAML中的控制元件 using System; using System.Collections.Generic; using System.Linq; using System.Text;

C#動態呼叫封裝好的opencv(C++)程式碼塊

由於專案需要在C#中呼叫opencv的函式處理影象,而暫時沒時間瞭解CLR/C++,所以就採用封裝API的方式呼叫,使用的IDE是VS2015,記錄過程如下: 一、 建立封裝好的動態連結庫 1、建立新專案 在VS2015新建visual C++專案——Win32專案——應用程式型別DLL

javascript操作向表格動態載入資料

首先在HTML中編寫表格資訊 <table width="500px" border="1"> //表格頭部資訊 <thead> <tr> <th>編號</th

vue動態載入元件+開發者模式+JS引數值傳遞和引用傳遞

今天寫vue裡面通過介面反參動態載入元件時候 跟著同學。。。學習到了 一、先說說vue 內建元件 component 的用法 component元件可以來專門用來進行元件的切換,使用is來繫結你的元件名,本次系統寫的比較簡單。。。 此處::is='元件名'可以直接條用元件。 因為全頁面有十個元件載入,所

如何在C/C 動態分配二維陣列

                如何在C/C++中動態分配二維陣列在C/C++中動態分配二維陣列可以先申請一維的指標陣列,然後該陣列中的每個指標再申請陣列,這樣就相當於二維陣列了,但是這種方法會導致每行可能不相鄰,從而訪問效率比較低。如何申請連續的二維陣列了?本文將分別三個方面講解:一.動態申請列大小固定的二

C++動態定義一維陣列,二維陣列,三維陣列

//動態定義一維陣列、二維陣列、三維陣列 #include<iostream> #include<ctime> using namespace std ; int main() { int hight , row , col ; register

簡潔明瞭,C++動態定義一維陣列,二維陣列,三維陣列

#include<iostream> #include <ctime> #include <cstdlib> using namespace std; int main() { int hight , row , col ; regis

如何在C++動態分配二維陣列

這個問題應該是我以前在CSDN蹭分時回答次數比較多的一個問題了,我的回答一般是三種方法:(1)用vector的vector,(2)先分配一個指標 陣列,然後讓裡面每一個指標再指向一個數組,這個做法的好處是訪問陣列元素時比較直觀,可以用a[x][y]這樣的寫法,缺點是它相當於C

c#實現動態載入Dll

1、利用反射進行動態載入和呼叫. Assembly assembly=Assembly.LoadFrom(DllPath); //利用dll的路徑載入,同時將此程式集所依賴的程式集載入進來,需後輟名.dllAssembly.LoadFile 只加載指定檔案,並不會自動載入依賴程式集.Assmbly.Load無

Spring 執行 動態載入xml並例項化Bean

工作中總有各種各樣另類問題發生,比如像我遇到的需要動態載入指定jar檔案並例項化執行。拿到這個問題,主要問題就是 動態指定的jar檔案不存在於classpath中,如何讓Spring知道並引用 都知道jvm是通過classloader載入class,並且是

C#動態修改ListBox的Item的顏色的方法

最近搞了C#需要在ListBox中顯示不同型別的資料,為了讓使用者容易區分,增加了顏色區分的功能,就是需要不同的型別資料顯示出不同的顏色。針對上述的要求我們需要使用控制元件的重繪方法,就是用重繪的方法啟用重繪事件,在重繪事件內修改Item的字型顏色。方法如下(基於DrawI

C# tableLayoutPanel動態載入控制元件閃爍的解決方案

本文轉載自k_set原創內容點選開啟連結 WinForm載入多個自定義控制元件時,會出現很嚴重的閃爍問題,很卡,一塊一塊的載入(像開啟網頁時,網路很卡的那種感覺)簡直沒法忍受。 在網上搜索了好久,網上大部分的方法是一下4種,但是都不能有效的解決問題。   1.將Do

android動態載入webview,webview載入html資料,並且隱藏滾動條

 ScrollView layouts = (ScrollView) findViewById(R.id.web); WebView webviews = new WebView(DtDetailActivity.this);webviews.setVisibility(

c動態

程式編譯一般需經預處理、編譯、彙編和連結幾個步驟。在應用中,有一些公共程式碼是需要反覆使用,就把這些程式碼編譯為“庫”檔案;在連結步驟中,聯結器將從庫檔案取得所需的程式碼,複製到生成的可執行檔案中。這種庫稱為靜態庫,其特點是可執行檔案中包含了庫程式碼的一份完整拷貝;缺點就是

js動態載入js並且判斷載入完成執行回撥函式

這一段js雖然很少,但是足以知道什麼是動態載入js了,像requirejs,seajs其實原理也就是這樣,下面發出自己寫的函式 <span style="font-size:18px;colo

WPF動態載入資料

<!--動態生成一組按鈕--> <StackPanel> <ItemsControl ItemsSource="{Binding Picture}">

spring工作動態載入其他類

需求:在測試或者其他地方,需要載入service或者mapper的時候,由於該類不是controller類,所以不能用@Autowired直接注入,那麼怎麼解決呢?import org.springframework.web.context.ContextLoader; im