当前位置:首页 > 技术 > 正文内容

C# WinForms DataGridView 深度应用与核心技巧详解

访客 技术 2026年8月8日 1

自定义控件的初始化与数据绑定

在使用扩展的 DataGridView 控件(如 DataGridViewEx)之前,首先需配置数据库连接并正确设置数据源。以下示例展示了如何在应用程序启动时初始化服务,以及在窗口加载时绑定数据。

// 在 Program.cs 中配置数据库连接
SqlSugarServices.SetConnectionString("server=192.168.1.100,1433;database=system_db;uid=dev_user;pwd=secure_password");

// 在窗体的 Load 事件中进行初始化
private void InitializeCustomGrid()
{
    // 配置扩展属性:关联用户、窗体类型及控件标识
    customDataGrid.SetColRelate("admin", this.GetType().FullName, "mainGrid", "1");

    // 准备数据绑定组件
    BindingSource bindingSrc = new BindingSource();
    DataTable sourceData = new DataRepository().GetTableData();
    
    // 设置数据源
    bindingSrc.DataSource = sourceData;
    customDataGrid.DataSource = bindingSrc;
    customDataGrid.DataMember = sourceData.TableName;
    
    // 将 BindingSource 引用赋给自定义控件的扩展属性
    customDataGrid.BoundSource = bindingSrc;
}

界面样式与列宽调整

为了提升用户体验,通常需要对表头对齐、列宽自适应以及单元格颜色进行定制。

// 设置表头居中对齐
mainGrid.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;

// 设置特定列(如第二列)居中并禁用排序
mainGrid.Columns[1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
mainGrid.Columns[1].SortMode = DataGridViewColumnSortMode.NotSortable;

// 自动调整列宽以适应单元格内容
mainGrid.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);

// 也可以单独设置某一列的自适应模式
mainGrid.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;

自动调整模式说明:
AllCells:根据列中所有单元格(包括表头)的内容调整宽度。
DisplayedCells:仅根据当前可见的单元格内容调整。
Fill:列宽将填充控件的可用区域,通常配合 FillWeight 属性使用。

// 设置 Fill 模式下的相对权重
mainGrid.Columns[0].FillWeight = 20; // 占用 20% 宽度
mainGrid.Columns[1].FillWeight = 80; // 占用 80% 宽度

单元格交互与数据获取

处理鼠标点击事件并获取当前单元格数据是常见的需求。同时,理解 ValueEditedFormattedValue 的区别至关重要。

数据属性区别:
EditedFormattedValue:单元格当前正在编辑且尚未提交到底层数据源的值(例如用户正在输入但未按回车)。
Value:单元格已提交的实际数据值。

private void OnCellClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex < 0 || e.ColumnIndex < 0) return;

    // 方法一:直接使用坐标获取
    int rowIndex = e.RowIndex;
    int colIndex = e.ColumnIndex;
    
    // 方法二:通过当前选中状态获取
    int currentRow = mainGrid.CurrentCell.RowIndex;
    var cellContent = mainGrid.CurrentCell.Value;

    MessageBox.Show($"选中: 第 {rowIndex + 1} 行, 内容: {cellContent}");
}

行与列的高级控制

包括设置行号、禁止编辑特定列以及遍历选中行。

// 1. 实现行号显示(处理 RowStateChanged 事件)
private void OnRowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
{
    e.Row.HeaderCell.Value = (e.Row.Index + 1).ToString();
}

// 2. 设置特定列只读并修改样式
mainGrid.EnableHeadersVisualStyles = false; // 允许自定义表头样式
mainGrid.Columns[3].ReadOnly = true; // 禁止编辑第4列
mainGrid.Columns[3].HeaderCell.Style.BackColor = Color.LightBlue;
mainGrid.Columns[3].DefaultCellStyle.BackColor = Color.LightGray;

// 3. 遍历并处理选中行
foreach (DataGridViewRow row in mainGrid.SelectedRows)
{
    var id = row.Cells["UserID"].Value.ToString();
    // 执行业务逻辑...
}

数据验证与输入控制

在单元格编辑完成后验证数据类型,例如限制只能输入数字。

private void OnCellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    string input = mainGrid[e.ColumnIndex, e.RowIndex].Value?.ToString();

    if (string.IsNullOrWhiteSpace(input))
    {
        return; // 允许空值,不做处理
    }

    if (decimal.TryParse(input, out decimal number))
    {
        // 如果是数字,自动跳转到下一行对应列
        if (e.RowIndex + 1 < mainGrid.Rows.Count)
        {
            mainGrid.CurrentCell = mainGrid[e.ColumnIndex, e.RowIndex + 1];
        }
    }
    else
    {
        MessageBox.Show("输入无效:请输入数字。");
        mainGrid.BeginEdit(true); // 重新进入编辑模式
    }
}

实现底部合计行(Footer)

通过自定义绘制来实现固定在底部的合计行,这种方式不随滚动条移动,且不影响数据源。

private void OnCellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    // 确保启用了添加行选项,且仅处理新行(底部的空白行)的绘制
    if (e.RowIndex == mainGrid.NewRowIndex && e.ColumnIndex >= 0)
    {
        int total = 0;

        // 计算当前列的总和
        for (int i = 0; i < mainGrid.RowCount - 1; i++) // 排除新行本身
        {
            object val = mainGrid.Rows[i].Cells[e.ColumnIndex].Value;
            if (val != null && int.TryParse(val.ToString(), out int num))
            {
                total += num;
            }
        }

        // 绘制背景
        e.PaintBackground(e.CellBounds, true);

        // 自定义绘制合计文本
        string text = total.ToString();
        TextRenderer.DrawText(e.Graphics, text, mainGrid.Font, 
            new Point(e.CellBounds.X + 5, e.CellBounds.Y + 5), 
            Color.Red, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);

        e.Handled = true; // 阻止系统默认绘制
    }
}

DataBindingComplete 事件触发优化

在绑定数据源时,如果先设置 DataMember 后设置 DataSource,可能会导致 DataBindingComplete 事件触发多次。建议按以下顺序赋值:

// 正确的绑定顺序
mainGrid.DataSource = null; // 先清空
mainGrid.DataMember = "TargetTable"; // 再指定成员
mainGrid.DataSource = dataSet; // 最后绑定源

这种顺序可以避免因属性自动更新导致的重复事件触发,从而提高性能并减少不必要的逻辑执行。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。