在winform下实现左右布局多窗⼝界⾯的⽅法(⼆)
这篇⽂章主要介绍了在winform下实现左右布局多窗⼝界⾯的⽅法之续篇的相关资料,需要的朋友可以参考下
在上篇⽂章已经实现了左右布局多窗⼝界⾯,今天本来是研究基于winform的插件编程,没想到顺便⼜到了另⼀种实现⽅案,这种实现⽅案更简单,要写的代码也很少,具体实现如下。可视化设计部份:
1.⽗窗⼝:ParentForm的IsMdiContainer 设置为 true,即:this.IsMdiContainer=true;
2.在⽗窗⼝中添加⼀个顶部菜单:menuStrip1,并新增⼀个菜单项:Windows,且将menuStrip1的MdiWindowListItem设置为该Windows菜单对象,即:
3.在⽗窗⼝中添加⼀个树形菜单:treeView1,并将其Dock设为左靠齐,即:View1.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.windowsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.panel1 = new System.Windows.Forms.Panel();
this.SuspendLayout();
/
/
// menuStrip1
//
this.windowsToolStripMenuItem});
/
/
// windowsToolStripMenuItem
//
this.windowsToolStripMenuItem.Name = "windowsToolStripMenuItem";
this.windowsToolStripMenuItem.Size = new System.Drawing.Size(73, 21);
this.windowsToolStripMenuItem.Text = "Windows";
//
// treeView1
//
//
// 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.View1);
this.Controls.uStrip1);
this.IsMdiContainer = true;
this.MainMenuStrip = uStrip1;
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
menustrip和toolstrip
this.Resize += new System.EventHandler(this.Form1_Resize);
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;
}
}
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() //实现情况应该是从数据库及⽤户权限来进⾏动态创建菜单项
{
var root = View1.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>();
}
}
附上完整的实现代码:
using 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;
}
}
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() //实现情况应该是从数据库及⽤户权限来进⾏动态创建菜单项
{
var root = View1.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关于插件式编程(近期⼯作任务要求),到时候同样会分享给⼤家,也欢迎⼤家⼀起交流,当然⾼⼿可以⽆视。