分享在winform下实现左右布局多窗口界面-续篇
之前的这篇文章《分享在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>();
}
}
附上完整的实现代码:
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;
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下实现左右布局多窗口界面-续篇的更多相关文章
- 分享在winform下实现左右布局多窗口界面
在web页面上我们可以通过frameset,iframe嵌套框架很容易实现各种导航+内容的布局界面,而在winform.WPF中实现其实也很容易,我这里就分享一个:在winform下实现左右布局多窗口 ...
- 在winform下实现左右布局多窗口界面的方法(二)
这篇文章主要介绍了在winform下实现左右布局多窗口界面的方法之续篇 的相关资料,需要的朋友可以参考下 在上篇文章在winform下实现左右布局多窗口界面的方法(一)已经实现了左右布局多窗口界面,今 ...
- 在winform下实现左右布局多窗口界面的方法(一)
在web页面上我们可以通过frameset,iframe嵌套框架很容易实现各种导航+内容的布局界面,而在winform.WPF中实现其实也很容易,通过本文给大家介绍在winform下实现左右布局多窗口 ...
- 分享在winform下实现模块化插件编程
其实很早之前我就已经了解了在winform下实现插件编程,原理很简单,主要实现思路就是:先定一个插件接口作为插件样式及功能的约定,然后具体的插件就去实现这个插件接口,最后宿主(应用程序本身)就利用反射 ...
- 分享在winform下实现模块化插件编程-优化版
上一篇<分享在winform下实现模块化插件编程>已经实现了模块化编程,但我认为不够完美,存在以下几个问题: 1.IAppContext中的CreatePlugInForm方法只能依据完整 ...
- Win10下PB停在欢迎窗口界面
问题:Win10下不能打开PB12.5,PB12.6,一直停在欢迎窗口界面. 解决方法:把服务"Touch Keyboard and Handwriting Panel Service&qu ...
- Winform下实现图片切换特效的方法
本文实例讲述了Winform下实现图片切换特效的方法,是应用程序开发中非常实用的一个功能.分享给大家供大家参考之用.具体方法如下: 本实例源自网络,功能较为齐全.丰富!主要功能代码如下: using ...
- 关于Winform下DataGridView中实现checkbox全选反选、同步列表项的处理
近期接手一个winform 项目,虽然之前有.net 的经验,但是对一些控件的用法还不是很熟悉. 这段时间将会记录一些在工作中遇到的坎坷以及对应的解决办法,写出来与大家分享并希望大神提出更好解决方法来 ...
- 请问在C#的Winform下如何用正则表达式限制用户只能在textBox中输入18位的身份证号码。
请问在C#的Winform下如何用正则表达式限制用户只能在textBox中输入18位的身份证号码. 2013-06-18 11:07会飞的鱼儿18 | 分类:C#/.NET | 浏览101次 不能有空 ...
随机推荐
- maven filter 乱码,MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8 sequence.
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactI ...
- java中类的加载情况
当一个类存在继承且与其他类有关联情况时,类中各模块加载顺序如下: 1.首先找到public类,判断该类是否继承其他类,如果没有继承其他类(Object类除外),则加载该类:否则转去加载该类的超类,超类 ...
- 剑指Offer面试题:33.二叉树的深度
一.题目一:二叉树的深度 1.1 题目说明 题目一:输入一棵二叉树的根结点,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.例如下图中的二叉树的 ...
- 一个App完成入门篇-终结篇(八)- 应用收官
经过以上几步的学习,我们终于来到最后一个步骤了,应用APP也接近尾声. 通过之前的几节教程,不知道您对使用DeviceOne开发一个应用是不是已经得心应手了,本节教程将教会大家如何在开发完成之后通过D ...
- .NET 基础 一步步 一幕幕 [注释、命名规则、访问修饰符、数据类型、常量、变量]
注释.命名规则.访问修饰符.数据类型.常量.变量 话说一个不会写注释的程序猿的不是一个好吃货,我们本篇就从注释开始说起好了. 在C#中有三种注释: 第一种:单行注释 以//开头,后面的就是注释内容 ...
- Node.js教程系列~目录
Node.js这个东西在近几年火起来了,而且会一直火下去,无论在infoq还是在cnblogs,csdn上,都可以到处看到它的样子,它主推的应该就是异步式I/O 吧,是的,设计的很完美,很吸引人,虽然 ...
- 2013 duilib入门简明教程 -- 简单控件介绍 (12)
前面的教程应该让大家对duilib的整体有所映像了,下面就来介绍下duilib具体控件的使用. 由于官方没有提供默认的控件样式,所以我就尽量使用win7或者XP自带的按钮样式了,虽然界 ...
- WebDriver--操控浏览器
前一篇讲述了元素的定位方法,现在开始练习如何写自动化测试脚本 我使用的编辑工具是PyCharm,今后该博客中所写的有关Python脚本,都是在该工具中编写的. WebDriver提供了控制浏览器大小. ...
- JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式
相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...
- defered,promise回顾
defered,promise回顾 http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_o ...