C#高级:Winform桌面开发中DataGridView的详解(新)

发布于:2025-06-30 ⋅ 阅读:(22) ⋅ 点赞:(0)

一、数据填充(反射)

1.封装

/// <summary>
/// 渲染DataGridView
/// </summary>
/// <param name="dataGridView">被渲染控件</param>
/// <param name="list">数据集</param>
/// <param name="headtext">字段和展示名称</param>
/// <param name="ButtonList">按钮名称,可为空</param>
private void GetDataGridView<T>(DataGridView dataGridView, List<T> list, List<(Expression<Func<T, object>> fields, string name)> headtext, List<string> ButtonList = null) where T : class
{

    // 使用 LINQ 通过直接提取表达式来获取字段名称
    var propertyNames = headtext
        .Select(x =>
            x.fields.Body is MemberExpression memberExpr
            ? memberExpr.Member.Name
            : ((MemberExpression)((UnaryExpression)x.fields.Body).Operand).Member.Name)
        .ToList();

    //反射获取字段列表
    var field = typeof(T).GetProperties()
        .Where(x=> propertyNames.Contains(x.Name))
        .OrderBy(x => propertyNames.Contains(x.Name) ? propertyNames.IndexOf(x.Name) : int.MaxValue)
        .ToList();

    //设置表头样式和属性
    dataGridView.AllowUserToAddRows = false;//不允许添加、删除
    dataGridView.AllowUserToDeleteRows = false;
    dataGridView.ReadOnly = true;//设置只读
    dataGridView.RowHeadersVisible = false;//隐藏最左边的空白栏
    dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;//自适应宽度
    // 设置表头样式
    dataGridView.ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle
    {
        Alignment = DataGridViewContentAlignment.MiddleCenter, // 中间对齐
        BackColor = Color.LightGray, // 表头背景色
        ForeColor = Color.Black, // 表头文字颜色
        Font = new Font("宋体", 10, FontStyle.Bold), // 表头字体
    };
    //dataGridView.RowTemplate.Height = 80;//设置行高


    //设置表头内容(按实体顺序依次设置名字)
    dataGridView.Columns.Clear();
    foreach (var item in headtext)
    {
        dataGridView.Columns.Add(new DataGridViewTextBoxColumn  //增加文字列
        {
            DefaultCellStyle = new DataGridViewCellStyle { Alignment = DataGridViewContentAlignment.MiddleCenter },//剧中对齐
            HeaderText = item.name,//中文标题
            MinimumWidth = 6,
            Name = field[headtext.FindIndex(x => x == item)].Name,//字段的名字 例如ID Name
            ReadOnly = true,
            SortMode = DataGridViewColumnSortMode.NotSortable,//不要列头排序,否则无法居中
            Width = 110
        });
    }

    //设置表头按钮
    if (ButtonList != null)
    {
        foreach (var item in ButtonList)
        {
            //增加按钮(含样式)
            dataGridView.Columns.Add(new DataGridViewButtonColumn
            {
                DefaultCellStyle = new DataGridViewCellStyle { Alignment = DataGridViewContentAlignment.MiddleCenter },
                HeaderText = "操作",//中文标题
                MinimumWidth = 6,
                Name = item,
                ReadOnly = true,
                SortMode = DataGridViewColumnSortMode.NotSortable,
                Width = 110
            });
        }
    }

    //dataGridView.Columns[0].Width = 200; // 手动调节宽度,注意需要注释掉前面的【AutoSizeColumnsMode 自适应宽度】
    //dataGridView.Columns[1].Width = 200; // 手动调节宽度
    // dataGridView.Columns[2].Width = 80; // 手动调节宽度
    // dataGridView.Columns[3].Width = 80; // 手动调节宽度
    // dataGridView.Columns[4].Width = 80; // 手动调节宽度
    // dataGridView.Columns[5].Width = 80; // 手动调节宽度
    // dataGridView.Columns[6].Width = 300; // 手动调节宽度

    // 清空现有数据
    dataGridView.Rows.Clear();

    //添加数据
    foreach (var item in list)
    {
        int rowIndex = dataGridView.Rows.Add();
        foreach (var jtem in field)
        {
            //添加普通内容数据
            dataGridView.Rows[rowIndex].Cells[jtem.Name.ToString()].Value = jtem.GetValue(item);//字段
            dataGridView.Rows[rowIndex].DefaultCellStyle.ForeColor = Color.Black;

            //if (jtem.Name.ToString().Equals("time"))//对特定的字段处理
            //{
            //dataGridView.Rows[rowIndex].Cells[jtem.Name.ToString()].Value = ((DateTime)(jtem.GetValue(item))).ToString("yyyy年MM月dd日");//格式化日期
            //dataGridView1.Rows[rowIndex].DefaultCellStyle.ForeColor = Color.Red;//文字颜色
            //dataGridView1.Rows[rowIndex].DefaultCellStyle.BackColor = Color.Yellow;//背景颜色
            //}

            //添加按钮数据
            if (ButtonList != null)
            {
                int index = 1;
                foreach (var j in ButtonList)
                {
                    dataGridView.Rows[rowIndex].Cells[j].Value = j;//按钮名称
                    index++;

                    //移除按钮(两步)
                    //if (false)
                    //{
                    //    dataGridView.Rows[rowIndex].Cells["btn1"] = new DataGridViewTextBoxCell();//重新初始化
                    //    dataGridView.Rows[rowIndex].Cells["btn1"].ReadOnly = true;  // 设置为只读
                    //}
                }
            }

        }
        dataGridView.Rows[rowIndex].Tag = item;//绑定到Tag上方便后续调用
    }
}

2.使用

private void Form1_Load(object sender, EventArgs e)
{
    GetDataGridView(
        dataGridView1,
        students,
        new List<(Expression<Func<Student, object>>,string)>
        {
            (x => x.StudentId, "学号"),
            (x => x.StudentName, "姓名"),
            (x => x.StudentScore, "成绩") 
        },
        new List<string> { "删除", "修改" });
}

3.效果

二、数据填充(遍历)

暂未写

三、点击按钮获取实体 

1.方法

找到你的 dataGridView1 双击进入 CellClick

双击进去后写代码:

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == dataGridView1.Columns["删除"].Index && e.RowIndex >= 0)//若点击了【删除】按钮
    {
        // 获取当前行对应的实体对象【注意修改此处Student类】,此处能获取到StudentDorm字段(虽然没有显示在界面上,但整个实体也绑定到Tag了)
        var item =  dataGridView1.Rows[e.RowIndex].Tag as Student;
        MessageBox.Show($"展示内容:学生姓名{item.StudentName},分数{item.StudentScore},学生宿舍{item.StudentDorm}", "点击了删除按钮");
    }
}

2.效果

 四、点击单元格获取实体

 这个和标题三实现起来很相似的

1.方法

找到你的 dataGridView1 双击进入 CellClick

双击进去后写代码:

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == dataGridView1.Columns["StudentName"].Index && e.RowIndex >= 0)//若点击了【姓名】单元格
    {
        // 获取当前行对应的实体对象【注意修改此处Student类】,此处能获取到StudentDorm字段(虽然没有显示在界面上,但整个实体也绑定到Tag了)
        var item =  dataGridView1.Rows[e.RowIndex].Tag as Student;
        MessageBox.Show($"展示内容:学生姓名{item.StudentName},分数{item.StudentScore},学生宿舍{item.StudentDorm}", "点击了【姓名】单元格");
    }
}

2.效果

五、获取DatagridView列表

1.封装

/// <summary>
/// 获取指定datagridview的列表,并转化为T实体
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dataGridView"></param>
/// <returns></returns>
private List<T> GetDataGridList<T>(DataGridView dataGridView) where T : class
{
    List<T> list = new List<T>();
    foreach (DataGridViewRow row in dataGridView.Rows)
    {
        var item = row.Tag as T;
        list.Add(item);
    }
    return list;
}

2.使用

//点击触发查询列表
private void button1_Click(object sender, EventArgs e)
{
    var myList = GetDataGridList<Student>(dataGridView1);
}

3.效果

六、列表的编辑

暂未写,需要传出编辑前和编辑后的状态

七、单条数据的编辑(Key=字段,Value=内容)

暂未写