C#MDI多文档窗体+FlowLayoutPanel 流式布局

MDI多文档窗体

一、MDI窗体核心概念(必考)

1. 什么是MDI窗体

MDI(Multiple Document Interface)多文档界面。

作用:一个主窗体中可以嵌套打开多个子窗体,所有子窗体只能在主窗体内活动,不会独立弹出窗口。

常见软件:Word、Excel、PS 多文档窗口模式。

2. MDI两大角色

父窗体(容器窗体) :必须设置属性 IsMdiContainer = true

子窗体(内容窗体) :通过代码指定 子窗体.MdiParent = 父窗体对象

3. MDI常用布局枚举

MdiLayout.TileVertical垂直平铺(左右均分)

MdiLayout.TileHorizontal水平平铺(上下均分)

MdiLayout.Cascade:层叠窗口


二、前期准备工作

1、创建窗体:Form1(主窗体)、Form2(子窗体1)、Form3(子窗体2)

2、设置 Form1 属性:IsMdiContainer = true(必须设置,否则无法嵌套子窗体)

3、给Form1添加菜单栏 MenuStrip,创建对应菜单项:

打开窗体、设置窗体、打开窗体1、打开窗体2


三、完整代码逐段拆解精讲

复制代码
namespace _2MDI窗体
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

1、功能一:一次性打开多个子窗体 + 垂直平铺布局

菜单项:打开窗体

复制代码
        private void 打开窗体ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //=================打开子窗体2=================
            Form2 f2 = new Form2();
            //设置父容器为当前主窗体Form1
            f2.MdiParent = this; 
            f2.Show();

            //=================打开子窗体3=================
            Form3 f3 = new Form3();
            f3.MdiParent = this;
            //单独设置窗体背景色
            f3.BackColor = Color.Red;
            f3.Show();

            //设置所有子窗体:垂直平铺(左右排列)
            LayoutMdi(MdiLayout.TileVertical); 
        }

核心知识点解析

f2.MdiParent = this:指定当前f2的父容器是主窗体,变成MDI子窗体

LayoutMdi():系统自带布局方法,专门用于排列所有MDI子窗体

MdiLayout.TileVertical:垂直平铺,多个子窗体左右等分屏幕显示

2、功能二:切换为水平平铺布局

菜单项:设置窗体

复制代码
        private void 设置窗体ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //水平平铺:子窗体上下等分排列
            LayoutMdi(MdiLayout.TileHorizontal);
        }

3、功能三:封装通用打开窗体方法(核心重点)

需求:同类窗体唯一显示,不同类窗体切换显示

逻辑:

1、如果要打开的窗体已经存在 → 隐藏所有窗体,激活显示当前同类窗体

2、如果是新窗体 → 隐藏所有旧窗体,展示新窗体

复制代码
        //打开窗体1菜单:打开Form2
        private void 打开窗体1ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Open(new Form2());
        }

        //打开窗体2菜单:打开Form3
        private void 打开窗体2ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Open(new Form3());
        }

4、核心通用Open方法(重难点逐行解析)

复制代码
        /// <summary>
        /// MDI窗体通用打开、去重、切换方法
        /// </summary>
        /// <param name="f">要打开的子窗体对象</param>
        public void Open(Form f)
        {
            //遍历当前主窗体所有已打开的子窗体
            foreach (var item in this.MdiChildren)
            {
                //判断:将要打开的窗体 和 已存在的窗体 类型是否一致
                if (f.GetType() == item.GetType())
                {
                    //隐藏所有子窗体
                    foreach (Form child in this.MdiChildren)
                    {
                        child.Hide();
                    }
                    //显示当前同类窗体
                    item.Show();
                    //激活置顶聚焦
                    item.Activate();
                    //终止方法,不再创建新窗体(实现单例)
                    return;
                }
            }

            //走到这里说明:没有同类窗体,需要打开全新窗体
            //先隐藏所有旧窗体
            foreach (Form child in this.MdiChildren)
            {
                child.Hide();
            }
            //设置父容器
            f.MdiParent = this;
            //展示新窗体
            f.Show();
        }

四、核心属性精讲

this.MdiChildren :获取当前主窗体下所有子窗体集合

GetType():获取窗体的类型(判断是Form2还是Form3)

Hide():隐藏窗体,窗体对象还在内存,只是看不见

Show():显示隐藏的窗体

Activate():激活窗体,置顶、获取焦点

五、整体逻辑流程图解

点击菜单 → 调用Open方法 → 判断是否存在同类窗体

存在同类 → 全部隐藏 → 显示同类旧窗体 → 返回

不存在同类 → 隐藏所有旧窗体 → 创建新窗体 → 显示

六、备用极简写法(第二种写法)

注释里的极简逻辑:每次打开新窗体前隐藏全部旧窗体,始终只显示一个窗体

复制代码
            //第二种最简写法
            //foreach (var item in this.MdiChildren)//先遍历所有子窗体 把子窗隐藏
            //{
            //    item.Hide();
            //}
            //f.MdiParent = this; //设置子父关系
            //f.Show(); //显示当前窗体

七、MDI核心必考知识点总结

1、主窗体必须设置 IsMdiContainer = true

2、子窗体必须赋值 MdiParent = this 才能嵌套

3、MdiChildren 获取所有子窗体

4、LayoutMdi 专门用于批量布局子窗体

5、GetType() 用于判断窗体类型,实现窗体去重

6、Hide隐藏不销毁、Show显示、Activate激活

八、易错点总结

1、忘记设置主窗体 IsMdiContainer,子窗体无法嵌套

2、不判断窗体类型,重复创建多个一模一样的窗体

3、不写return,导致重复弹窗

4、混淆Hide和Close:Hide只是隐藏,Close才是销毁窗体

FlowLayoutPanel 流式布局

一、流式布局核心知识点

1. 什么是流式布局

FlowLayoutPanel(流式布局面板)是 WinForm 自带的自动布局容器

普通Panel:控件需要手动设置坐标固定位置,排版繁琐、适配差。

流式布局:控件自动从左到右排列,一行排满自动换行,无需手动设置Location坐标。

2. 核心特点

1、自动流式排版:左 → 右、上 → 下

2、窗口大小改变时,控件位置自动自适应

3、支持批量动态添加控件,排版整齐统一

4、通过 Margin 属性设置控件之间的边距间距

3. 必备界面控件

窗体拖拽控件:FlowLayoutPanel(命名默认 flowLayoutPanel1)


二、完整代码逐段精细拆解

复制代码
namespace _3流式布局
{
    public partial class Form1 : Form
    {
        //窗体构造方法:程序启动自动执行
        public Form1()
        {
            InitializeComponent();

1、循环批量创建按钮

复制代码
            //循环10次,批量生成10个按钮
            for (int i = 0; i < 10; i++)
            {
                //1、实例化按钮对象
                Button btn = new Button()
                {
                    //设置按钮显示文本
                    Text = "按钮",
                };

2、设置控件间距(核心属性)

复制代码
                //设置按钮外边距:上、左间距10像素,右、下0
                btn.Margin = new Padding(10, 10, 0, 0);

Padding参数详解(顺序固定)

new Padding(左, 上, 右, 下)

本代码效果:按钮距离左侧、上方留白10像素,按钮之间产生间距,排版不拥挤

3、将控件添加到流式布局面板

复制代码
                //将创建好的按钮添加到流式布局容器中
                this.flowLayoutPanel1.Controls.Add(btn);
            }
        }
    }
}

核心原理

所有动态创建的控件,必须通过 容器.Controls.Add(控件) 添加到容器,界面才会显示。

添加后 FlowLayoutPanel 自动按照流式规则从左到右排列。


三、代码运行效果

1、程序启动,自动生成10个【按钮】

2、按钮从左向右依次排列,每个按钮左上侧留白10px间距

3、一行放不下自动换行,自适应窗体宽度

4、拖拽窗体拉大缩小,按钮排版自动适配


四、关键属性超详细解析

1. Margin 外边距

作用:控件与其他控件、容器边缘的距离

区别:Padding是控件内部留白,Margin是控件外部间距

2. Controls.Add()

动态控件显示的唯一方式,将内存中的控件对象挂载到界面容器

3. FlowLayoutPanel 自动布局规则

默认排版方向:LeftToRight 从左到右

自动换行:超出容器宽度自动换行到下一行


五、易错点总结

1、动态new控件后,不执行Add方法 → 界面看不到控件

2、不设置Margin → 所有按钮紧贴在一起,排版拥挤难看

3、普通Panel无法自动换行,必须使用FlowLayoutPanel

4、循环创建控件,无需手动命名,批量生成效率极高


六、知识点总结

1、FlowLayoutPanel 专门用于批量控件自动流式排版

2、Margin 控制控件外部间距,优化界面美观度

3、Controls.Add() 实现动态控件挂载显示

4、循环批量创建控件,是WinForm动态界面核心写法