【无标题】

表格dataGridView

一、基础框架与数据模型

  1. WinForms 窗体结构

    • 命名空间与窗体类:namespace _01表格 包裹窗体类Form1(继承自Form),窗体类标记为partial(分部类),配合自动生成的InitializeComponent()初始化控件。
    • 自定义数据模型:Student类作为数据载体,通过自动属性 定义Name/Age/Info三个字段,作为 DataGridView 的绑定数据源结构。
  2. 集合数据源

    • 声明全局List<Student> list作为数据容器,相比数组更灵活(支持动态增删),是 WinForms 中 DataGridView 最常用的数据源类型之一。

二、DataGridView 核心配置

  1. 列生成模式

    • AutoGenerateColumns = false:关闭自动列生成,需手动在界面(或代码)绑定类的属性(列标题、绑定字段);若设为true,表格会自动根据Student类的属性名生成列(标题 = 属性名)。
    • 手动绑定列的核心:需在窗体设计器中为 DataGridView 添加列,并设置列的DataPropertyName(与 Student 的属性名一致,如 Name/Age/Info)、Name(列的唯一标识,如 Name1)。
  2. 数据源绑定与刷新

    • 绑定方式:dataGridView1.DataSource = list,将集合直接绑定到表格。
    • 刷新机制:由于List<T>不具备自动通知 UI 更新的能力(非绑定源),增删改数据后需通过DataSource = null → 重新赋值DataSource = list 触发表格刷新。

三、DataGridView 数据操作(增删改查)

1. 新增数据(Add)
  • 逻辑:向List<Student>添加新对象 → 刷新表格绑定。

  • 核心代码: csharp

    运行

    复制代码
    list.Add(new Student() { Name = "张三4", Age = 40, Info = "xxx" });
    dataGridView1.DataSource = null;
    dataGridView1.DataSource = list;
2. 删除数据(Delete)
  • 关键步骤:① 校验选中行:SelectedRows.Count == 0 判断是否选中行,无则提示。② 获取绑定对象:SelectedRows[0].DataBoundItem as Student 从选中行提取绑定的 Student 对象(核心,避免直接操作单元格)。③ 确认删除:MessageBox.Show() 带返回值(DialogResult),判断是否点击 "Yes"。④ 移除数据 + 刷新:list.Remove(stu) → 刷新表格。
3. 查询数据(Query)
  • 集合筛选:使用List<T>.FindAll() 结合Lambda 表达式 筛选满足条件的元素(v => v.Name == textBox1.Text)。
  • 空结果处理:判断筛选后的集合Count == 0,提示 "未找到",否则绑定筛选结果到表格。
4. 修改数据(Update)
  • 核心逻辑:① 选中行 → 提取绑定的 Student 对象 → 直接修改对象属性(stu.Name = "高达")→ 刷新表格。② 单元格取值(扩展):SelectedRows[0].Cells["Name1"].Value.ToString() 通过列的 Name 获取单元格内容。

四、DataGridView 界面自定义

  1. 行号自定义绘制

    • 触发事件:RowPostPaint(行重新绘制时触发)。
    • 绘制核心步骤:① 获取行索引:e.RowIndex + 1(行号从 1 开始)。② 定义绘制区域:Rectangle 指定行标题栏的绘制范围(左 / 上 / 宽 / 高)。③ 字符串格式化:StringFormat 设置水平 / 垂直居中对齐。④ 绘制文本:e.Graphics.DrawString() 绘制行号到行标题栏,参数包括字符串、字体、画笔颜色、绘制区域、对齐方式。
  2. 关键绘图类

    • Graphics:图形绘制核心类,提供DrawString等绘制方法。
    • StringFormat:控制字符串对齐 / 排版。
    • Rectangle:定义绘制区域的矩形范围。
    • Brushes:画笔颜色(如Brushes.Black)。

五、WinForms 通用知识点

  1. MessageBox 进阶使用

    • 带确认框的提示:MessageBox.Show("提示内容", "标题", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
    • 返回值处理:DialogResult result 判断用户点击 "Yes/No",控制后续逻辑。
  2. 控件事件与参数

    • 事件触发时机:RowPostPaint 事件在每行绘制完成后触发,适合自定义行样式(如行号)。
    • 事件参数:DataGridViewRowPostPaintEventArgs e 包含行索引(e.RowIndex)、行边界(e.RowBounds)、绘图对象(e.Graphics)等核心信息。
  3. DataGridView 行 / 单元格操作

    • SelectedRows:选中行集合,SelectedRows[0] 取第一行(默认单选场景)。
    • DataBoundItem:选中行绑定的原始数据对象(核心,避免直接操作单元格,降低耦合)。
    • Cells["列Name"].Value:获取指定列的单元格值,需转ToString()使用。

六、核心易错点与注意事项

  1. List<T>作为数据源的局限性:无 INotifyPropertyChanged 接口,修改对象属性后必须刷新绑定(DataSource=null再赋值),否则 UI 不更新。
  2. 行索引处理:e.RowIndex 从 0 开始,显示行号需+1
  3. 类型转换:DataBoundItem 需用as Student 强制转换为目标类型,避免类型错误。
  4. 列名匹配:手动绑定列时,DataPropertyName 必须与 Student 的属性名一致,Cells["列Name"] 中的 Name 需与设计器中列的 Name 一致。

实例

cs 复制代码
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 _01表格
{
    public partial class Form1 : Form
    {
        public List<Student> list = new List<Student>(); //学生集合对象
        public Form1()
        {

            //label、textbox 、button
            //panel、pictureBox、 radionButton  checkboxButton
            //MenuStrip、 ContextMenuStrip、toolStrip
            //Combobox
            InitializeComponent();
          



            list.Add(new Student() { Name = "张三1", Age = 10, Info = "被捕" });
            list.Add(new Student() { Name = "张三2", Age = 20, Info = "被捕" });
            list.Add(new Student() { Name = "张三3", Age = 30, Info = "被捕" });





            //AutoGenerateColumns是否自动生成列,设置为false 需要自己通过界面绑定类的属性(自己设置列的标题、自己设置列显示哪个属性)
            //设置为true,表格自动显示列的标题为绑定类的属性
            dataGridView1.AutoGenerateColumns = false;
            

            //dataGridView1 表格 可以通过DataSource属性进行绑定数据源,但是后续添加的新的数据不会立即显示到控件上,需要
            // 再次对 dataGridView1.DataSource=null之后 再重新赋值
            dataGridView1.DataSource = list;
            
         
        }
        //添加数据源的方法
        private void button1_Click(object sender, EventArgs e)
        {
            list.Add(new Student() { Name = "张三4", Age = 40, Info = "委被捕" });
            dataGridView1.DataSource = null;
            dataGridView1.DataSource = list;

        }

        //删除数据源的方法
        private void button2_Click(object sender, EventArgs e)
        {
            //先判断是否选中行
            //SelectedRows 选中的行 可以选择多个
            
            if (dataGridView1.SelectedRows.Count==0) //没选中行
            {
                MessageBox.Show("请先选中要删除的一行");
                return;
            }
            //选中行了 获取选中的一行索引值 或者这一行对象
            Student stu = null; //要删除的一行对象

           // DataBoundItem 获取选中行绑定对象  
           // as 强制转换成Student对象
            stu =  dataGridView1.SelectedRows[0].DataBoundItem as Student;
            //MessageBox.Show(stu.Name);

            //MessageBox.Show是有返回值的,为DialogResult对象(对话结果对象),
            DialogResult result =  MessageBox.Show("是否要删除改行", "温馨提示", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            if (result != DialogResult.Yes) //如果没有选择yes 直接return
            {
                return;
            }

            //如果选择警告框的Yes键时候 再删除
            list.Remove(stu);

            //刷新界面
            dataGridView1.DataSource = null;
            dataGridView1.DataSource = list;

            //删除成功之后 可以再次提示一下
            MessageBox.Show("删除成功");


        }

        //查询数据源 把满足查询条件的数据源重新绑定给表格
        private void button3_Click(object sender, EventArgs e)
        {
            //FindAll() 查找满足条件的所有的元素对象, 与输入框文本内容一样的对象
           List<Student> currentList =  list.FindAll(v => v.Name == textBox1.Text);
            if (currentList.Count==0)
            {
                MessageBox.Show("没找到要找的学生");
                return;
            }

            dataGridView1.DataSource = null;
            dataGridView1.DataSource = currentList;
        }
        
        //修改数据源
        private void button4_Click(object sender, EventArgs e)
        {
            if (dataGridView1.SelectedRows.Count == 0)
            {
                MessageBox.Show("请先选中要修改的一行");
                return;
            }
            // 获取选中一行的对象
            DataGridViewRow cc = dataGridView1.SelectedRows[0];
           
            Student stu = cc.DataBoundItem as Student;
            stu.Name = "高达";
            stu.Age = 20;
            stu.Info = "人在搭在";
      
            dataGridView1.DataSource = null;
            dataGridView1.DataSource = list;

            // 获取单元格的内容
            // Cells["Name1"] 获取name属性为Name1单元格的内容
            //  MessageBox.Show(dataGridView1.SelectedRows[0].Cells["Name1"].Value.ToString());

            // DataGridViewRow cc1 = dataGridView1.SelectedRows[0];
           // MessageBox.Show(cc1.Cells["Name1"].Value.ToString());

        }

        //当行重新绘制的时候触发函数
        private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
        {
            string s = e.RowIndex + 1 + "";// 显示的内容
            //dataGridView1.Font; //表格的默认字体

            //创建一个矩形 绘制的区域
            //e.RowBounds.Left,开始绘制行的左边界位置
            // e.RowBounds.Top, 开始绘制行的上边界位置
            Rectangle rect  = new Rectangle(e.RowBounds.Left,
                e.RowBounds.Top,
                dataGridView1.RowHeadersWidth,// 行标题的宽度
                e.RowBounds.Height);

            //格式化字符串 字符串的对齐方式
            StringFormat sf = new StringFormat()
            {
                Alignment = StringAlignment.Center,// 水平对齐方式居中
                LineAlignment = StringAlignment.Center, //竖直对齐方式居中
            };
            
            //Brushes.Black 画笔的颜色
            //Graphics 图形类
            //DrawString 绘制一个文本 参数1是绘制的字符串,参数2是绘制字体,参数3绘制的笔刷颜色 ,参数4 绘制的区域 , 参数5绘制字符串对齐方式
            e.Graphics.DrawString(s,dataGridView1.Font,Brushes.Black, rect,sf);

        }
    }
    public class Student
    {
        public string Name { get; set; }
        public int Age {  get; set; }
        public string Info {  get; set; }

    }
}

2 自定义表格样式

一、类与方法的基础设计

  1. 静态工具类设计

    • 类定位:DatagridviewStyle静态工具类 (所有方法 / 字段均为static),无需实例化即可调用(如DatagridviewStyle.DgvStyle2(dataGridView1)),符合 WinForms 通用工具类的设计规范。
    • 静态字段:public static int A = 10; 演示静态字段的定义,可作为通用常量(如默认行高、颜色值)复用。
  2. 方法注释与参数规范

    • 完整的 XML 注释:每个方法都标注了<summary>(功能描述)、<param>(参数说明),提升代码可读性和可维护性。
    • 参数设计:所有方法均接收DataGridView实例(dgv)作为参数,实现「一套逻辑适配任意表格控件」,是通用工具类的核心特征。

二、DataGridView 核心样式配置(DgvStyle1/DgvStyle2)

1. 基础外观样式
配置项 作用 核心知识点
BackgroundColor 表格无数据区域的背景色 区分「有数据行背景」和「空白区域背景」,可通过SystemColors调用系统预设颜色
RowsDefaultCellStyle.BackColor 数据行默认背景色 所有行的基础背景样式,优先级低于AlternatingRowsDefaultCellStyle
AlternatingRowsDefaultCellStyle.BackColor 奇数行(交替行)背景色 实现「隔行变色」效果,提升表格可读性(如黄色 / 青色交替)
GridColor 表格网格线颜色 控制单元格之间分隔线的颜色(如红色)
EnableHeadersVisualStyles = false 关闭列标题默认视觉样式 关键配置:若需自定义列标题样式(颜色 / 字体 / 边框),必须关闭此属性,否则自定义样式不生效
2. 边框样式
配置项 作用 核心知识点
CellBorderStyle 单元格边框样式 支持Sunken(凹陷)、Raised(凸起)、Single(单线)等样式,实现「凹凸质感」表格
ColumnHeadersBorderStyle 列标题边框样式 CellBorderStyle配合,统一表格边框风格(如均设为Sunken
RowHeadersBorderStyle 行标题(行号列)边框样式 控制行标题区域的边框样式,保持整体风格统一
RowTemplate.DividerHeight 行分隔线高度 配合Sunken边框样式使用,增强凹凸视觉效果
3. 标题栏样式
配置项 作用 核心知识点
ColumnHeadersHeight 列标题高度 需配合ColumnHeadersHeightSizeMode = EnableResizing才能生效(允许调整高度)
ColumnHeadersHeightSizeMode 列标题高度调整模式 EnableResizing(允许手动调整)、DisableResizing(固定)、AutoSize(自动适配)
ColumnHeadersDefaultCellStyle 列标题样式集合 可配置ForeColor(字体色)、BackColor(背景色)、Font(字体)等
4. 字体与文字样式
配置项 作用 核心知识点
ColumnHeadersDefaultCellStyle.Font 列标题字体 自定义字体(如宋体 10 号),需实例化Font对象(new Font("宋体", 10F)
RowsDefaultCellStyle.Font 数据行字体 统一设置所有行的字体(如楷体 8 号),也可通过列单独配置(dgv.Columns[i].DefaultCellStyle.Font
Columns[i].DefaultCellStyle.ForeColor 指定列字体颜色 遍历列集合(dgv.ColumnCount获取列数),为每列单独设置文字颜色(如黄色)

三、自定义行号绘制(DgvRowCount)

  1. 绘图核心类与对象

    • SolidBrush:实心笔刷,用于绘制文本 / 图形的填充色,此处绑定行标题的默认字体色(dgv.RowHeadersDefaultCellStyle.ForeColor),保证行号颜色与表格风格统一。
    • Graphics:绘图核心对象(e.Graphics),通过DrawString方法绘制文本,是 GDI + 绘图的基础类。
    • DataGridViewRowPostPaintEventArgs:事件参数,提供关键绘图信息:
      • e.RowIndex:当前行索引(从 0 开始,行号需+1);
      • e.RowBounds.Location:当前行的坐标(X/Y),用于定位行号绘制位置;
      • e.InheritedRowStyle.Font:当前行的字体样式,保证行号字体与行内容一致。
  2. 绘制逻辑

    • 行号计算:e.RowIndex + 1 实现行号从 1 开始(而非 0);
    • 文本绘制:DrawString(字符串, 字体, 笔刷, X坐标, Y坐标),通过固定偏移(+15/+5)调整行号位置,避免与行边界重叠。

四、关键易错点与注意事项

  1. EnableHeadersVisualStyles 的坑
    • 若未设置EnableHeadersVisualStyles = false,所有自定义列标题样式(颜色 / 字体 / 边框)都会被系统默认样式覆盖,导致配置无效。
  2. 列标题高度生效条件
    • 设置ColumnHeadersHeight前,必须将ColumnHeadersHeightSizeMode设为EnableResizing,否则高度设置不生效。
  3. 交替行样式优先级
    • AlternatingRowsDefaultCellStyle 优先级高于RowsDefaultCellStyle,会覆盖奇数行的默认背景色。
  4. GDI + 资源释放(扩展)
    • SolidBrush属于非托管资源,若频繁绘制建议使用using包裹(using (SolidBrush s1 = new SolidBrush(...)) { ... }),避免内存泄漏。

五、样式配置的最佳实践

  1. 样式分类封装:将不同风格的样式(如基础样式 DgvStyle1、凹凸样式 DgvStyle2)拆分为独立方法,便于业务场景切换。
  2. 系统颜色复用 :使用System.Drawing.SystemColors(如SystemColors.ButtonFace)代替硬编码颜色值,适配系统主题。
  3. 字体统一管理 :可将常用字体(如宋体 10 号、楷体 8 号)封装为静态字段,避免重复实例化Font对象。

实例

cs 复制代码
 public class DatagridviewStyle
 {
     public static int A = 10;
     /// <summary>
     /// 设置表格样式 参数是表格
     /// </summary>
     /// <param name="dgv"></param>
     public  static void DgvStyle1(DataGridView dgv)
     {
         //未显示数据时候背景颜色  StudentManager.Common.DatagridviewStyle.A
         dgv.BackgroundColor = System.Drawing.SystemColors.ButtonFace;

         //显示数据时候背景颜色
         dgv.RowsDefaultCellStyle.BackColor = System.Drawing.Color.Black;

         //设置网格的颜色
         dgv.GridColor = System.Drawing.Color.Red;

         // 设置列表题边框的样式
         dgv.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;

         //设置行的边框样式
         dgv.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;

         // 表格的默认样式不可见
         dgv.EnableHeadersVisualStyles = false;

         // 设置列的宽度高度 单位是px
         dgv.ColumnHeadersHeight = 35;

         //设置列表题宽度可以被修改
         dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
         
         //列标题的字体颜色
         dgv.ColumnHeadersDefaultCellStyle.ForeColor = System.Drawing.Color.Green;

         //列背景颜色
         dgv.ColumnHeadersDefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(255, 255, 192);

         // 设置行的字体颜色
         int a = dgv.ColumnCount; //列数  2
         for (int i = 0;i < a; i++)
         {
            dgv.Columns[i].DefaultCellStyle.ForeColor = System.Drawing.Color.Yellow;
         }
       
     }


     /// <summary>
     ///   表格格式第二种 凹凸样式
     /// </summary>
     /// <param name="dgv"></param>
      public static void DgvStyle2(DataGridView dgv)
     {
         // 设置单元格的边框样式
        dgv.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.Sunken;

         // 列表题的样式
         dgv.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Sunken;

         //列表题字体
         dgv.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("宋体", 10F);

         // 背景颜色
         dgv.ColumnHeadersDefaultCellStyle.BackColor =  System.Drawing.Color.FromArgb(0,0, 255);

         //设置分割符号的高度 设置凹凸Sunken样式 需要把分割符号高度加上
         dgv.RowTemplate.DividerHeight = 1;

         // 列标题的高度
        // 需要把表格的列标题的高度模式改成 EnableResizing
         dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
         dgv.ColumnHeadersHeight = 30;

         // 行的边框样式
         dgv.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Sunken;

         //设置行的字体
         dgv.RowsDefaultCellStyle.Font = new System.Drawing.Font("楷体", 8f);

         dgv.RowsDefaultCellStyle.BackColor = Color.Yellow;

         // 奇数行的背景颜色
         dgv.AlternatingRowsDefaultCellStyle.BackColor = Color.Cyan;

         // 关闭默认样式
         dgv.EnableHeadersVisualStyles = false;

     }
    







     /// <summary>
     /// 绘制表格的行号 事先给datagridview绑定事件RowPosPaint,在这个方法
     /// 调用以下这个方法
     /// 参数1是表格
     /// 参数2 是绘制的事件对象
     /// </summary>
     /// 
     public static void DgvRowCount(DataGridView dgv,DataGridViewRowPostPaintEventArgs e)
     {
         // 设置一个笔刷 包含绘制各种图形的样式,带了表格行的默认字体颜色
         SolidBrush s1 = new SolidBrush(dgv.RowHeadersDefaultCellStyle.ForeColor);
         int  num = e.RowIndex +1;//RowIndex 行的索引值加1
         string numString = num.ToString();
         //DrawString 绘制字符串
         //参数1 是绘制的字符串
         //参数2 是绘制字体字体类型
         //参数3 是笔刷
         //参数4 5 坐标
         e.Graphics.DrawString(numString, e.InheritedRowStyle.Font, s1, e.RowBounds.Location.X + 15, e.RowBounds.Location.Y + 5);

     }
 }

使用方法

cs 复制代码
 public partial class Form1 : Form
 {
     public List<Student> list = new List<Student>(); //学生集合对象
     public Form1()
     {
         InitializeComponent();


         list.Add(new Student() { Name = "张三1", Age = 10, Info = "委内瑞拉总统被捕" });
         list.Add(new Student() { Name = "张三2", Age = 20, Info = "委内瑞拉总统被捕" });
         list.Add(new Student() { Name = "张三3", Age = 30, Info = "委内瑞拉总统被捕" });
         dataGridView1.DataSource = list;

         //DatagridviewStyle 关于表格样式的一个类文件,DgvStyle1()和 DgvStyle2() 设计表格样式
         //DgvRowCount() 绘制行标题
         DatagridviewStyle.DgvStyle2(dataGridView1);
     }

     private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
     {
         DatagridviewStyle.DgvRowCount(dataGridView1,e);
     }
 }
 public class Student
 {
     public string Name { get; set; }
     public int Age { get; set; }
     public string Info { get; set; }

 }

3、Timer 定时器核心知识点

1. 定时器基础配置
配置项 / 方法 作用 核心说明
Interval 触发间隔 单位为毫秒(ms) ,代码中设为10(即每 10ms 触发一次Tick事件);值越小,触发频率越高,动态效果越流畅(但过高频率可能占用 CPU)。
Start() 开启定时器 调用后定时器开始按Interval间隔触发Tick事件(代码中绑定到 "启动" 按钮点击事件)。
Stop() 停止定时器 调用后定时器暂停触发Tick事件(代码中绑定到 "停止" 按钮点击事件)。
Enabled 激活状态 Enabled = true 等价于Start()false等价于Stop();初始化时若未设置,默认可能为false(需手动启动)。
Tick事件 定时触发逻辑 定时器核心事件,每到Interval间隔就执行事件内的代码(如修改标签样式、位置)。
2. 定时器生命周期控制
  • 初始化:窗体构造函数中仅配置Interval和标签字体,未直接启动定时器(避免窗体加载后立即触发),通过按钮手动控制启停,符合 "按需触发" 的交互逻辑。
  • 终止逻辑:未显式释放定时器(WinForms 中控件随窗体销毁自动释放,若需手动释放可在FormClosed事件中调用timer1.Dispose())。

二、随机数生成(Random 类)

  1. Random 对象创建
    • 声明全局Random ran = new Random();(避免在Tick事件内重复创建,否则因系统时钟精度问题导致随机数重复)。
  2. 随机数取值
    • ran.Next(256):生成0~255之间的整数(包含 0,不包含 256),恰好匹配 RGB 颜色通道的取值范围(0-255)。
  3. RGB 颜色合成
    • Color.FromArgb(r, g, b):通过红(r)、绿(g)、蓝(b)三原色值合成自定义颜色:
      • (255,255,255)= 白色,(0,0,0)= 黑色;
      • 某一通道值越大,颜色越偏向该通道(如r=255, g=0, b=0为纯红)。

三、WinForms 控件样式与位置动态修改

1. 标签(Label)样式配置
  • 字体自定义:label1.Font = new Font(new FontFamily("楷体"), 20); 实例化Font对象,设置字体为楷体、字号 20(窗体初始化时配置)。
  • 背景色动态修改:label1.BackColor = Color.FromArgb(r, g, b); 每 10ms 更新一次背景色,实现 "炫彩" 效果。
2. 控件位置控制(Point/Location)
  • Location属性:控件在窗体中的坐标,类型为Point(包含XY两个整型属性):
    • label1.Left 等价于 label1.Location.X(控件左边缘距窗体左边缘的距离);
    • label1.Location.Y 等价于控件上边缘距窗体上边缘的距离(代码中用count变量控制)。
  • 位置更新:label1.Location = new Point(label1.Left, count); 保持 X 坐标不变,Y 坐标随count递增,实现标签垂直向下移动
  • 边界重置:if (count>=400) count=0; 当 Y 坐标达到 400 时重置为 0,避免标签移出窗体可视区域。

四、变量与逻辑控制

  1. 全局计数器
    • 声明int count = 0;作为全局变量(需在Tick事件外定义),用于累计标签 Y 坐标偏移量;若声明在Tick事件内,每次触发都会重置为 0,无法实现移动效果。
  2. 循环移动逻辑
    • 通过count++实现持续下移,count>=400时重置为 0,形成 "循环下移" 的动画效果。

五、关键易错点与注意事项

  1. Random 对象创建位置
    • 错误写法:在Tick事件内每次创建Random ran = new Random(); → 因系统时钟(TickCount)精度问题,短时间内创建的 Random 会生成重复随机数,导致颜色无变化。
    • 正确写法:声明为全局变量,仅初始化一次。
  2. Interval 取值平衡
    • 过小(如 1ms):CPU 占用率升高,可能导致窗体卡顿;
    • 过大(如 1000ms):动画效果卡顿,不流畅;
    • 推荐范围:10~50ms(兼顾流畅度与性能)。
  3. 控件坐标边界
    • 需结合窗体实际尺寸调整count的阈值(如窗体高度为 500 时,阈值设为 400,避免标签被窗体边框遮挡)。
  4. 定时器启停状态
    • 多次点击 "启动" 按钮不会重复触发(Start()方法调用时若定时器已启动,无额外影响);
    • 停止后再次启动,count变量不会重置(代码中仅在count>=400时重置,若需停止后复位,可在Stop()后加count=0;)。

4、纯代码创建 Timer 定时器

1. 定时器对象的手动创建与配置
核心步骤 代码 / 知识点 说明
声明对象 Timer timer; 声明类级别的 Timer 变量(避免局部变量被回收)
实例化 + 初始化 timer = new Timer() { Enabled=true,Interval=10}; 采用对象初始化器直接配置核心属性:- Enabled=true:创建后立即激活(等价于Start());- Interval=10:触发间隔 10ms。
绑定事件 timer.Tick += Timer_Tick; 通过委托绑定Tick事件处理方法,替代设计器的事件绑定;语法:事件 += 事件处理方法(方法签名需匹配EventHandler)。
2. 定时器事件的通用逻辑
  • 无需设计器拖拽 Timer 控件,完全通过代码控制生命周期,适合动态创建 / 销毁定时器的场景(如按需生成多个定时器);
  • 定时器触发后遍历窗体控件,体现「动态控件批量操作」的思路。

二、动态生成控件(Label)

  1. 控件创建与初始化

    • 通过new Label()创建标签,使用对象初始化器 一次性配置核心属性:

      csharp

      运行

      复制代码
      Label label = new Label()
      {
          Text = i.ToString(), // 文本内容
          Location = new Point(100 * i, 200), // 坐标(X轴按i*100偏移,实现横向排列)
          BackColor = Color.Aqua, // 背景色
          Size = new Size(50, 50), // 尺寸(宽50,高50)
          TextAlign = ContentAlignment.MiddleCenter // 文本居中对齐
      };
  2. 控件添加到窗体

    • this.Controls.Add(label);:将动态创建的 Label 添加到窗体的控件集合中,否则控件不会显示。
  3. 批量生成逻辑

    • 通过for循环生成 10 个 Label,X 坐标按100*i递增,实现横向等距排列,无需在设计器中逐个拖拽。

三、窗体控件集合遍历与类型判断

  1. 控件集合(Controls)
    • this.Controls:窗体的所有子控件集合(包括动态创建和设计器添加的控件);
    • this.Controls.Count:获取控件总数,用于循环遍历的边界判断。
  2. 类型判断(is 关键字)
    • if (this.Controls[i] is Label):判断当前遍历的控件是否为 Label 类型,避免修改非 Label 控件的样式(如按钮、文本框);
    • 替代方案:as关键字(Label lbl = this.Controls[i] as Label; if(lbl != null)),适合需要获取控件实例的场景。
  3. 批量样式修改
    • 遍历中动态修改 Label 的BackColor(背景色)和ForeColor(字体色),通过Random生成随机 RGB 值,实现 "炫彩" 效果;
    • 核心:Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256))(0-255 随机三原色合成颜色)。

四、GDI + 高级绘图(渐变文本)

1. 窗体绘制重写(OnPaint 方法)
  • protected override void OnPaint(PaintEventArgs e):重写窗体的绘制方法,窗体刷新 / 加载时触发;
  • base.OnPaint(e):必须调用基类的 OnPaint 方法,否则窗体默认绘制逻辑(如控件显示)会失效;
  • PaintEventArgs e:提供绘图核心对象e.Graphics(画布)。
2. 线性渐变笔刷(LinearGradientBrush)
核心参数 说明
构造函数 LinearGradientBrush(rect, Color.Red, Color.Yellow, 45f)
rect 渐变应用的矩形区域(与文本绘制区域匹配)
Color.Red/Color.Yellow 渐变的起始色和结束色
45f 渐变角度(0°= 水平渐变,45°= 斜向渐变,90°= 垂直渐变)
3. 渐变文本绘制步骤

csharp

运行

复制代码
// 1. 创建画布
Graphics g = e.Graphics;
// 2. 定义绘制区域
Rectangle rect = new Rectangle(10, 10, 300, 50);
// 3. 创建字体(Arial,32号,加粗)
Font font = new Font("Arial", 32, FontStyle.Bold);
// 4. 创建线性渐变笔刷
LinearGradientBrush brush = new LinearGradientBrush(rect, Color.Red, Color.Yellow, 45f);
// 5. 绘制渐变文本
g.DrawString("渐变文本", font, brush, new PointF(10, 10));

五、关键易错点与注意事项

  1. Timer 对象的作用域

    • 必须声明为类级变量(Timer timer;),若在构造函数中声明为局部变量,会被 GC 回收,定时器立即失效。
  2. GDI + 资源释放(扩展)

    • FontLinearGradientBrush属于非托管资源,重写 OnPaint 时若频繁创建,需用using包裹释放:

      csharp

      运行

      复制代码
      using (Font font = new Font("Arial", 32, FontStyle.Bold))
      using (LinearGradientBrush brush = new LinearGradientBrush(rect, Color.Red, Color.Yellow, 45f))
      {
          g.DrawString("渐变文本", font, brush, new PointF(10, 10));
      }
  3. 控件遍历的效率

    • this.Controls仅遍历直接子控件,若 Label 嵌套在 Panel 中,需递归遍历(panel1.Controls);
    • 频繁遍历控件集合(如 10ms 一次)可能轻微占用 CPU,可通过缓存 Label 集合优化(如创建List<Label> lblList存储动态生成的 Label)。
  4. Random 对象的全局化

    • Random rnd = new Random();声明为类级变量,避免在 Timer_Tick 中重复创建导致随机数重复。
相关推荐
好好学习啊天天向上5 小时前
C盘容量不够,python , pip,安装包的位置
linux·python·pip
li_wen015 小时前
文件系统(八):Linux JFFS2文件系统工作原理、优势与局限
大数据·linux·数据库·文件系统·jffs2
wypywyp5 小时前
2.虚拟机一直显示黑屏,无法打开,可能是分配的硬盘空间不够
linux·运维·服务器
SongYuLong的博客6 小时前
TL-WR710N-V2.1 硬改刷机OpenWRT源码编译固件
linux·物联网·网络协议
AlfredZhao6 小时前
Docker 快速入门:手把手教你打包 Python 应用
linux·docker·podman
HIT_Weston7 小时前
107、【Ubuntu】【Hugo】搭建私人博客:模糊搜索 Fuse.js(三)
linux·javascript·ubuntu
艾莉丝努力练剑7 小时前
【优选算法必刷100题】第007~008题(双指针算法):三数之和、四数之和问题求解
linux·算法·双指针·优选算法
chinesegf8 小时前
Ubuntu 安装 Python 虚拟环境:常见问题与解决指南
linux·python·ubuntu
crownyouyou8 小时前
Ubuntu输入法使用回车键后字符间距异常的问题
linux·运维·ubuntu
济6178 小时前
linux 系统移植(第十七期)---Linux 内核移植(5)-- 修改网络驱动(2)--- Ubuntu20.04
linux·运维·网络