在上篇文章在winform下實現左右布局多窗口界面的方法已經實現了左右布局多窗口界面,今天本來是研究基於winform的插件編程,沒想到順便又找到了另一種實現方案,這種實現方案更簡單,要寫的代碼也很少,具體實現如下。
可視化設計部份:
1.父窗口:ParentForm的IsMdiContainer 設置為 true,即:this.IsMdiContainer=true;
2.在父窗口中添加一個頂部菜單:menuStrip1,並新增一個菜單項:Windows,且將menuStrip1的MdiWindowListItem設置為該Windows菜單對象,即: this.menuStrip1.MdiWindowListItem = this.WindowsToolStripMenuItem;
3.在父窗口中添加一個樹形菜單:treeView1,並將其Dock設為左靠齊,即:this.treeVIEw1.Dock = System.Windows.Forms.DockStyle.Left;且將margin設為0;
4.在父窗口中添加一個Panel:panel1,且將其width設為3;
以下是設計後自動生成的代碼:
namespace
WinFormTest
{
partial
class
ParentForm
{
/// <summary>
/// 必需的設計器變量。
/// </summary>
private
System.ComponentModel.IContainer components =
null
;
/// <summary>
/// 清理所有正在使用的資源。
/// </summary>
/// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param>
protected
override
void
Dispose(
bool
disposing)
{
if
(disposing && (components !=
null
))
{
components.Dispose();
}
base
.Dispose(disposing);
}
#region Windows 窗體設計器生成的代碼
/// <summary>
/// 設計器支持所需的方法 - 不要
/// 使用代碼編輯器修改此方法的內容。
/// </summary>
private
void
InitializeComponent()
{
this
.menuStrip1 =
new
System.Windows.Forms.MenuStrip();
this
.WindowsToolStripMenuItem =
new
System.Windows.Forms.ToolStripMenuItem();
this
.treeVIEw1 =
new
System.Windows.Forms.TreeVIEw();
this
.panel1 =
new
System.Windows.Forms.Panel();
this
.menuStrip1.SuspendLayout();
this
.SuspendLayout();
//
// menuStrip1
//
this
.menuStrip1.Items.AddRange(
new
System.Windows.Forms.ToolStripItem[] {
this
.WindowsToolStripMenuItem});
this
.menuStrip1.Location =
new
System.Drawing.Point(0, 0);
this
.menuStrip1.MdiWindowListItem =
this
.WindowsToolStripMenuItem;
this
.menuStrip1.Name =
"menuStrip1"
;
this
.menuStrip1.Size =
new
System.Drawing.Size(684, 25);
this
.menuStrip1.TabIndex = 0;
this
.menuStrip1.Text =
"menuStrip1"
;
//
// WindowsToolStripMenuItem
//
this
.WindowsToolStripMenuItem.Name =
"WindowsToolStripMenuItem"
;
this
.WindowsToolStripMenuItem.Size =
new
System.Drawing.Size(73, 21);
this
.WindowsToolStripMenuItem.Text =
"Windows"
;
//
// treeVIEw1
//
this
.treeVIEw1.Dock = System.Windows.Forms.DockStyle.Left;
this
.treeVIEw1.Location =
new
System.Drawing.Point(0, 25);
this
.treeVIEw1.Margin =
new
System.Windows.Forms.Padding(0);
this
.treeVIEw1.Name =
"treeVIEw1"
;
this
.treeVIEw1.Size =
new
System.Drawing.Size(228, 380);
this
.treeVIEw1.TabIndex = 3;
this
.treeVIEw1.NodeMouseDoubleClick +=
new
System.Windows.Forms.TreeNodeMouseClickEventHandler(
this
.treeVIEw1_NodeMouseDoubleClick);
//
// panel1
//
this
.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this
.panel1.BackColor = System.Drawing.Color.Red;
this
.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this
.panel1.Cursor = System.Windows.Forms.Cursors.VSplit;
this
.panel1.Location =
new
System.Drawing.Point(230, 28);
this
.panel1.Margin =
new
System.Windows.Forms.Padding(0);
this
.panel1.Name =
"panel1"
;
this
.panel1.Size =
new
System.Drawing.Size(3, 100);
this
.panel1.TabIndex = 5;
//
// Form1
//
this
.AutoScaleDimensions =
new
System.Drawing.SizeF(6F, 12F);
this
.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this
.ClIEntSize =
new
System.Drawing.Size(684, 405);
this
.Controls.Add(
this
.panel1);
this
.Controls.Add(
this
.treeVIEw1);
this
.Controls.Add(
this
.menuStrip1);
this
.IsMdiContainer =
true
;
this
.MainMenuStrip =
this
.menuStrip1;
this
.Name =
"Form1"
;
this
.Text =
"Form1"
;
this
.Load +=
new
System.EventHandler(
this
.Form1_Load);
this
.Resize +=
new
System.EventHandler(
this
.Form1_Resize);
this
.menuStrip1.ResumeLayout(
false
);
this
.menuStrip1.PerformLayout();
this
.ResumeLayout(
false
);
this
.PerformLayout();
}
#endregion
private
System.Windows.Forms.MenuStrip menuStrip1;
private
System.Windows.Forms.ToolStripMenuItem WindowsToolStripMenuItem;
private
System.Windows.Forms.TreeView treeVIEw1;
private
System.Windows.Forms.Panel panel1;
}
}
編碼部份:
其實上面的設計後,如果通過以下定義的方法打開一個子窗口,則直接實現了左右布局且包含多子窗口的界面。
private
void
ShowChildForm<TForm>() where TForm : Form,
new
()
{
Form childForm =
new
TForm();
childForm.MdiParent =
this
;
childForm.Name =
"ChildForm - "
+ DateTime.Now.Millisecond.ToString();
childForm.Text = childForm.Name;
childForm.Show();
}
當然仍然有不完美的地方,那就是左邊菜單欄寬度不能動態調整,而又沒有用到splitContainer,故我們只有自己來實現,其實也很簡單,步驟如下:
1.在父窗口構造函數中加入初始化panel1(用作分割器)位置及訂閱相關事件,代碼如下:
public
ParentForm()
{
InitializeComponent();
panel1.MouseDown += panel1_MouseDown;
panel1.MouseUp += panel1_MouseUp;
panel1.MouseMove += panel1_MouseMove;
panel1.Top = menuStrip1.Height;
panel1.Left = treeView1.Left + treeVIEw1.Width;
panel1.Height = panel1.Parent.Height;
}
上述代碼的作用是:1.保證panel1的高度與位置與左側樹形菜單控件相匹配;2.訂閱的三個Mouse事件主要是為了後面實現移動panel1。
2.實現訂閱的三個Mouse事件所對應的方法,分別為鼠標按下、鼠標移動、鼠標松開,代碼如下:
private
bool
startMove =
false
;
//用於標記是否在移動中
void
panel1_MouseMove(
object
sender, MouseEventArgs e)
{
if
(startMove)
{
panel1.Left += e.X;
}
}
void
panel1_MouseUp(
object
sender, MouseEventArgs e)
{
if
(startMove)
{
panel1.Left += e.X;
startMove =
false
;
this
.treeVIEw1.Width = panel1.Left;
}
}
void
panel1_MouseDown(
object
sender, MouseEventArgs e)
{
startMove =
true
;
}
上述代碼作用:按下鼠標標記為開始移動,然後移動鼠標,若是標記移動中,說明是要移動panel1,故直接將鼠標當前的X坐標位置累加到panel1.Left屬性上,從而實現移動,當鼠標彈起後,則將樹形菜單的寬度設置為panel1.Left,從而實現樹形菜單隨panel1的移動而改變大小。
同時為了保證panel1的高度始終與樹形菜單相同,在父窗口的Resize方法加入動態調整panel1的高度,代碼如下:
private
void
ParentForm_Resize(
object
sender, EventArgs e)
{
panel1.Height = panel1.Parent.Height;
}
到此就完成了整個的實現方案,為了便於模擬在樹形菜單中雙擊打開子窗口的效果,同時也添加了如下代碼:
private
void
ParentForm_Load(
object
sender, EventArgs e)
{
LoadMenuNodes();
}
private
void
LoadMenuNodes()
//實現情況應該是從數據庫及用戶權限來進行動態創建菜單項
{
this
.treeVIEw1.Nodes.Clear();
var root =
this
.treeVIEw1.Nodes.Add(
"Root"
);
for
(
int
i = 1; i <= 10; i++)
{
var section = root.Nodes.Add(
"Section-"
+ i);
int
maxNodes =
new
Random(i).Next(1, 10);
for
(
int
n = 1; n <= maxNodes; n++)
{
section.Nodes.Add(
string
.Format(
"Level-{0}-{1}"
, i, n));
}
}
}
private
void
treeVIEw1_NodeMouseDoubleClick(
object
sender, TreeNodeMouseClickEventArgs e)
{
if
(e.Node.Nodes.Count <= 0)
//當非父節點(即:實際的功能節點)
{
ShowChildForm<ChildForm>();
}
}
附上完整的實現代碼:
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Linq;
using
System.Text;
using
System.Threading.Tasks;
using
System.Windows.Forms;
namespace
WinFormTest
{
public
partial
class
ParentForm : Form
{
private
bool
startMove =
false
;
public
ParentForm()
{
InitializeComponent();
panel1.MouseDown += panel1_MouseDown;
panel1.MouseUp += panel1_MouseUp;
panel1.MouseMove += panel1_MouseMove;
panel1.Top = menuStrip1.Height;
panel1.Left = treeView1.Left + treeVIEw1.Width;
panel1.Height = panel1.Parent.Height;
}
void
panel1_MouseMove(
object
sender, MouseEventArgs e)
{
if
(startMove)
{
panel1.Left += e.X;
}
}
void
panel1_MouseUp(
object
sender, MouseEventArgs e)
{
if
(startMove)
{
panel1.Left += e.X;
startMove =
false
;
this
.treeVIEw1.Width = panel1.Left;
}
}
void
panel1_MouseDown(
object
sender, MouseEventArgs e)
{
startMove =
true
;
}
private
void
ParentForm_Load(
object
sender, EventArgs e)
{
LoadMenuNodes();
}
private
void
treeVIEw1_NodeMouseDoubleClick(
object
sender, TreeNodeMouseClickEventArgs e)
{
if
(e.Node.Nodes.Count <= 0)
//當非父節點(即:實際的功能節點)
{
ShowChildForm<ChildForm>();
}
}
private
void
ParentForm_Resize(
object
sender, EventArgs e)
{
panel1.Height = panel1.Parent.Height;
}
private
void
LoadMenuNodes()
//實現情況應該是從數據庫及用戶權限來進行動態創建菜單項
{
this
.treeVIEw1.Nodes.Clear();
var root =
this
.treeVIEw1.Nodes.Add(
"Root"
);
for
(
int
i = 1; i <= 10; i++)
{
var section = root.Nodes.Add(
"Section-"
+ i);
int
maxNodes =
new
Random(i).Next(1, 10);
for
(
int
n = 1; n <= maxNodes; n++)
{
section.Nodes.Add(
string
.Format(
"Level-{0}-{1}"
, i, n));
}
}
}
private
void
ShowChildForm<TForm>() where TForm : Form,
new
()
{
Form childForm =
new
TForm();
childForm.MdiParent =
this
;
childForm.Name =
"ChildForm - "
+ DateTime.Now.Millisecond.ToString();
childForm.Text = childForm.Name;
childForm.Show();
}
}
}
最終效果如下圖示:
說明:我這裡為了體現分割器,故將其背景色設為紅色,便於大家觀察,這種解決方案與之前的解決方案功能上是相同的,但有一點小小區別,之前的解決方案中子窗口的標題欄是在父窗口的容器內,而本文的解決方案中子窗口在最大化後,子窗口的標題欄會與父窗口合並,如下圖示,至於大家用哪種依實際場景。
關於在winform下實現左右布局多窗口界面的方法之續篇的相關知識就給大家介紹到這裡,後續時間我會繼續研究winform關於插件式編程(近期工作任務要求),到時候同樣會分享給大家,也歡迎大家一起交流,當然高手可以無視。