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
_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
WPF中Style檔案的引用——使用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