LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C# DataGridView 自定义单元格渲染深入解析

admin
2025年6月10日 9:55 本文热度 58

DataGridView作为Windows窗体应用程序中最常用的数据展示控件,其灵活的单元格渲染机制为开发者提供了无限可能。本文将深入剖析DataGridView单元格渲染的核心技术,帮助开发者解锁自定义单元格渲染的艺术。

单元格渲染基础详解

基础渲染类继承

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AppDataGrid
{
    publicclass CustomTextCell : DataGridViewTextBoxCell
    {
        protected override void Paint(
            Graphics graphics,
            Rectangle clipBounds,
            Rectangle cellBounds,
            int rowIndex,
            DataGridViewElementStates cellState,
            object value,
            object formattedValue,
            string errorText,
            DataGridViewCellStyle cellStyle,
            DataGridViewAdvancedBorderStyle advancedBorderStyle,
            DataGridViewPaintParts paintParts)

        
{
            // 修改:我们需要绘制除了文本之外的所有部分(背景、边框等)  
            // 通过排除文本部分,避免基类绘制文本造成重叠  
            DataGridViewPaintParts partsWithoutText = paintParts & ~DataGridViewPaintParts.ContentForeground;

            // 调用基类渲染方法,但不包括文本部分  
            base.Paint(graphics, clipBounds, cellBounds, rowIndex,
                       cellState, value, formattedValue,
                       errorText, cellStyle, advancedBorderStyle, partsWithoutText);

            // 只有当需要绘制内容前景(文本)时才进行自定义文本绘制  
            if ((paintParts & DataGridViewPaintParts.ContentForeground) != 0 && value != null)
            {
                // 抗锯齿绘制  
                graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

                // 自定义文本样式  
                using (SolidBrush brush = new SolidBrush(Color.Navy))
                using (Font customFont = new Font("微软雅黑"9, FontStyle.Bold))
                {
                    // 创建适合文本对齐的StringFormat  
                    StringFormat stringFormat = new StringFormat();
                    stringFormat.Alignment = StringAlignment.Center;
                    stringFormat.LineAlignment = StringAlignment.Center;

                    // 调整文本绘制区域,留出边距  
                    Rectangle textRect = new Rectangle(
                        cellBounds.X + 2,
                        cellBounds.Y + 2,
                        cellBounds.Width - 4,
                        cellBounds.Height - 4);

                    graphics.DrawString(
                        value.ToString(),
                        customFont,
                        brush,
                        textRect,
                        stringFormat
                    );
                }
            }
        }

        // 重写Clone方法以确保正确复制单元格  
        public override object Clone()
        
{
            returnnew CustomTextCell();
        }

        // 确保默认新行单元格值正确  
        public override object DefaultNewRowValue => string.Empty;

        // ====== 修复编辑功能 ======  

        // 使用标准的TextBox作为编辑控件  
        public override Type EditType => typeof(DataGridViewTextBoxEditingControl);

        // 设置值类型  
        public override Type ValueType => typeof(string);

        // 正确处理准备编辑状态  
        public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
        
{
            // 调用基类方法确保正确初始化编辑控件  
            base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);

            // 获取并配置编辑控件  
            if (DataGridView.EditingControl is DataGridViewTextBoxEditingControl textBox)
            {
                // 如果单元格值不为空,则设置文本框内容  
                textBox.Text = (Value == null) ? string.Empty : Value.ToString();

                // 可选:配置文本框的其他属性,比如字体等  
                textBox.Font = new Font("微软雅黑"9, FontStyle.Regular);
            }
        }

        // 确保可以编辑  
        public override bool ReadOnly
        {
            get { return base.ReadOnly; }
            set { base.ReadOnly = value; }
        }
    }

    // 创建自定义列类型以使用自定义单元格  
    publicclass CustomTextColumn : DataGridViewColumn
    {
        public CustomTextColumn() : base(new CustomTextCell())
        
{
            // 设置列的默认属性  
            SortMode = DataGridViewColumnSortMode.Automatic;
            DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
        }

        public override DataGridViewCell CellTemplate
        {
            get { return base.CellTemplate; }
            set
            {
                // 确保始终使用自定义单元格类型  
                if (value != null &&
                    !value.GetType().IsAssignableFrom(typeof(CustomTextCell)))
                {
                    thrownew InvalidCastException("必须使用CustomTextCell类型的单元格");
                }
                base.CellTemplate = value;
            }
        }
    }
}

进度条单元格渲染

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AppDataGrid
{
    publicclass ProgressBarCell : DataGridViewTextBoxCell
    {
        protected override void Paint(
            Graphics graphics,
            Rectangle clipBounds,
            Rectangle cellBounds,
            int rowIndex,
            DataGridViewElementStates cellState,
            object value,
            object formattedValue,
            string errorText,
            DataGridViewCellStyle cellStyle,
            DataGridViewAdvancedBorderStyle advancedBorderStyle,
            DataGridViewPaintParts paintParts)

        
{
            // 解析进度值  
            int progressValue = 0;
            if (value != null && int.TryParse(value.ToString(), out progressValue))
            {
                progressValue = Math.Max(0, Math.Min(100, progressValue));

                // 绘制背景  
                using (SolidBrush backgroundBrush = new SolidBrush(Color.LightGray))
                {
                    graphics.FillRectangle(backgroundBrush, cellBounds);
                }

                // 绘制进度条  
                using (SolidBrush progressBrush = new SolidBrush(GetProgressColor(progressValue)))
                {
                    int width = (int)((progressValue / 100.0) * cellBounds.Width);
                    Rectangle progressRect = new Rectangle(
                        cellBounds.X,
                        cellBounds.Y,
                        width,
                        cellBounds.Height
                    );
                    graphics.FillRectangle(progressBrush, progressRect);
                }

                // 绘制文本  
                using (SolidBrush textBrush = new SolidBrush(Color.Black))
                using (StringFormat sf = new StringFormat())
                {
                    sf.Alignment = StringAlignment.Center;
                    sf.LineAlignment = StringAlignment.Center;

                    graphics.DrawString(
                        $"{progressValue}%",
                        cellStyle.Font,
                        textBrush,
                        cellBounds,
                        sf
                    );
                }
            }
            else
            {
                // 如果值不是有效的整数,则调用基类绘制方法  
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState,
                          value, formattedValue, errorText, cellStyle,
                          advancedBorderStyle, paintParts);
            }
        }

        // 根据进度值选择颜色  
        private Color GetProgressColor(int progressValue)
        
{
            if (progressValue < 30)
                return Color.Red;
            elseif (progressValue < 60)
                return Color.Orange;
            else
                return Color.Green;
        }
    }

    // 进度条列类定义  
    publicclass ProgressBarColumn : DataGridViewColumn
    {
        public ProgressBarColumn() : base(new ProgressBarCell())
        
{
        }

        public override DataGridViewCell CellTemplate
        {
            get { return base.CellTemplate; }
            set
            {
                // 确保使用的单元格类型为ProgressBarCell  
                if (value != null && !value.GetType().IsAssignableFrom(typeof(ProgressBarCell)))
                {
                    thrownew InvalidCastException("单元格必须是ProgressBarCell类型");
                }
                base.CellTemplate = value;
            }
        }
    }

}

Form4 窗口

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 AppDataGrid
{
    public partial class Form4 : Form
    {
        private Random random = new Random();
        public Form4()
        
{
            InitializeComponent();
            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.AutoGenerateColumns = false;
            InitializeDataGridView();
        }

        private void InitializeDataGridView()
        
{
            // 添加普通文本列  
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                HeaderText = "任务名称",
                Name = "TaskName",
                Width = 200
            });

            // 添加进度条列  
            dataGridView1.Columns.Add(new ProgressBarColumn
            {
                HeaderText = "完成进度",
                Name = "Progress",
                Width = 150
            });

            // 添加一些示例数据  
            dataGridView1.Rows.Add("任务 1"25);
            dataGridView1.Rows.Add("任务 2"50);
            dataGridView1.Rows.Add("任务 3"75);
            dataGridView1.Rows.Add("任务 4"100);
        }

        private void btnUpdateProgress_Click(object sender, EventArgs e)
        
{
            // 随机更新进度  
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                int progress = random.Next(0101);
                row.Cells["Progress"].Value = progress;
            }
        }
    }
}

复杂条件渲染

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 AppDataGrid
{
    public partial class Form5 : Form
    {
        private DataGridView dataGridView1;
        public Form5()
        
{
            InitializeComponent();
            // 初始化界面  
            InitializeUI();

            // 加载数据  
            LoadData();

            // 配置条件格式化  
            ConfigureConditionalRendering();
        }
        private void InitializeUI()
        
{
            // 设置窗体属性  
            this.Text = "数据条件格式化示例";
            this.Size = new Size(800500);

            // 初始化 DataGridView  
            dataGridView1 = new DataGridView();
            dataGridView1.Dock = DockStyle.Fill;
            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.ReadOnly = true;
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

            // 添加到窗体  
            this.Controls.Add(dataGridView1);
        }

        private void LoadData()
        
{
            // 创建示例数据表  
            DataTable dataTable = new DataTable();

            // 添加列  
            dataTable.Columns.Add("项目名称", typeof(string));
            dataTable.Columns.Add("日期", typeof(DateTime));
            dataTable.Columns.Add("金额", typeof(decimal));
            dataTable.Columns.Add("状态", typeof(string));

            // 添加示例数据行  
            dataTable.Rows.Add("销售收入", DateTime.Now.AddDays(-5), 1500.50m, "已完成");
            dataTable.Rows.Add("设备购置", DateTime.Now.AddDays(-3), -2350.75m, "已支付");
            dataTable.Rows.Add("服务费用", DateTime.Now.AddDays(-2), 850.25m, "处理中");
            dataTable.Rows.Add("广告费用", DateTime.Now.AddDays(-1), -450.00m, "已支付");
            dataTable.Rows.Add("咨询收入", DateTime.Now, 2200.00m, "已完成");
            dataTable.Rows.Add("办公用品", DateTime.Now.AddDays(-4), -120.50m, "已支付");
            dataTable.Rows.Add("销售佣金", DateTime.Now.AddDays(-2), 950.75m, "处理中");
            dataTable.Rows.Add("年度奖金", DateTime.Now.AddDays(-1), 5000.00m, "已完成");

            // 将数据绑定到 DataGridView  
            dataGridView1.DataSource = dataTable;

            // 设置列格式  
            dataGridView1.Columns["日期"].DefaultCellStyle.Format = "yyyy-MM-dd";
            dataGridView1.Columns["金额"].DefaultCellStyle.Format = "N2"// 两位小数  

            // 调整列宽度  
            dataGridView1.Columns["项目名称"].FillWeight = 25;
            dataGridView1.Columns["日期"].FillWeight = 25;
            dataGridView1.Columns["金额"].FillWeight = 25;
            dataGridView1.Columns["状态"].FillWeight = 25;
        }

        private void ConfigureConditionalRendering()
        
{
            dataGridView1.CellFormatting += (sender, e) =>
            {
                // 根据单元格值设置样式  
                if (e.ColumnIndex == 2// 金额列  
                {
                    if (e.Value != null && e.Value != DBNull.Value)
                    {
                        decimal value = Convert.ToDecimal(e.Value);

                        // 负值显示为红色  
                        if (value < 0)
                        {
                            e.CellStyle.ForeColor = Color.Red;
                            e.CellStyle.BackColor = Color.LightPink;
                            // 为负值添加括号显示  
                            e.Value = string.Format("({0:N2})", Math.Abs(value));
                            e.FormattingApplied = true;
                        }
                        // 高值显示为绿色  
                        elseif (value > 1000)
                        {
                            e.CellStyle.ForeColor = Color.Green;
                            e.CellStyle.BackColor = Color.LightGreen;
                        }
                    }
                }

                // 根据状态列设置行样式  
                if (e.ColumnIndex == 3// 状态列  
                {
                    string status = e.Value?.ToString();

                    if (status == "已完成")
                    {
                        e.CellStyle.Font = new Font(dataGridView1.Font, FontStyle.Bold);
                    }
                    elseif (status == "处理中")
                    {
                        e.CellStyle.ForeColor = Color.Blue;
                    }
                }
            };

            // 添加行选择事件  
            dataGridView1.SelectionChanged += (sender, e) =>
            {
                if (dataGridView1.SelectedRows.Count > 0)
                {
                    // 在这里可以添加选择行后的操作  
                    // 例如:显示详细信息、更新统计等  
                }
            };

            // 添加摘要信息  
            AddSummaryPanel();
        }

        private void AddSummaryPanel()
        
{
            // 创建摘要面板  
            Panel summaryPanel = new Panel();
            summaryPanel.Dock = DockStyle.Bottom;
            summaryPanel.Height = 60;
            summaryPanel.BackColor = Color.LightGray;

            // 添加统计标签  
            Label summaryLabel = new Label();
            summaryLabel.AutoSize = false;
            summaryLabel.Dock = DockStyle.Fill;
            summaryLabel.TextAlign = ContentAlignment.MiddleCenter;

            // 计算统计信息  
            decimal total = 0;
            int positiveCount = 0;
            int negativeCount = 0;

            DataTable dt = (DataTable)dataGridView1.DataSource;
            foreach (DataRow row in dt.Rows)
            {
                decimal amount = Convert.ToDecimal(row["金额"]);
                total += amount;

                if (amount > 0)
                    positiveCount++;
                elseif (amount < 0)
                    negativeCount++;
            }

            // 设置统计文本  
            summaryLabel.Text = string.Format(
                "总计: {0:C2} | 收入项: {1} | 支出项: {2} | 总项数: {3}",
                total, positiveCount, negativeCount, dt.Rows.Count);

            // 将标签添加到面板  
            summaryPanel.Controls.Add(summaryLabel);

            // 调整DataGridView位置  
            dataGridView1.Dock = DockStyle.Fill;

            // 将面板添加到窗体  
            this.Controls.Add(summaryPanel);
        }


    }
}

高级渲染技巧

图标增强渲染

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 AppDataGrid
{
    public partial class Form6 : Form
    {
        DataGridView dataGridView1;

        public Form6()
        
{
            InitializeComponent();
            this.dataGridView1 = new System.Windows.Forms.DataGridView();
            dataGridView1.Dock = DockStyle.Fill;
            this.Controls.Add(dataGridView1);

            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dataGridView1.RowHeadersVisible = false;
            dataGridView1.AllowUserToResizeRows = false;
            dataGridView1.MultiSelect = false;
            dataGridView1.BackgroundColor = Color.White;
            dataGridView1.BorderStyle = BorderStyle.Fixed3D;
            dataGridView1.RowTemplate.Height = 28;

            // 添加列  
            var taskIdColumn = new DataGridViewTextBoxColumn
            {
                Name = "TaskId",
                HeaderText = "任务编号",
                DataPropertyName = "TaskId",
                Width = 100
            };

            var statusColumn = new DataGridViewTextBoxColumn
            {
                Name = "Status",
                HeaderText = "状态",
                DataPropertyName = "Status",
                Width = 120
            };

            var taskNameColumn = new DataGridViewTextBoxColumn
            {
                Name = "TaskName",
                HeaderText = "任务名称",
                DataPropertyName = "TaskName",
                Width = 200
            };

            var deadlineColumn = new DataGridViewTextBoxColumn
            {
                Name = "Deadline",
                HeaderText = "截止日期",
                DataPropertyName = "Deadline",
                Width = 140
            };

            var personInChargeColumn = new DataGridViewTextBoxColumn
            {
                Name = "PersonInCharge",
                HeaderText = "负责人",
                DataPropertyName = "PersonInCharge",
                Width = 120
            };

            var progressColumn = new DataGridViewTextBoxColumn
            {
                Name = "Progress",
                HeaderText = "进度",
                DataPropertyName = "Progress",
                Width = 80
            };

            // 添加列到DataGridView  
            dataGridView1.Columns.AddRange(new DataGridViewColumn[]
            {
                taskIdColumn, statusColumn, taskNameColumn, deadlineColumn, personInChargeColumn, progressColumn
            });
            LoadSampleData();
            dataGridView1.CellPainting += dataGridView1_CellPainting;
        }
        private void LoadSampleData()
        
{
            // 创建示例数据  
            var tasks = new List<TaskItem>
            {
                new TaskItem { TaskId = "T001", Status = "已完成", TaskName = "需求分析报告", Deadline = DateTime.Now.AddDays(-5), PersonInCharge = "张三", Progress = "100%" },
                new TaskItem { TaskId = "T002", Status = "进行中", TaskName = "系统架构设计", Deadline = DateTime.Now.AddDays(3), PersonInCharge = "李四", Progress = "60%" },
                new TaskItem { TaskId = "T003", Status = "进行中", TaskName = "数据库设计", Deadline = DateTime.Now.AddDays(2), PersonInCharge = "王五", Progress = "45%" },
                new TaskItem { TaskId = "T004", Status = "未开始", TaskName = "前端界面开发", Deadline = DateTime.Now.AddDays(10), PersonInCharge = "赵六", Progress = "0%" },
                new TaskItem { TaskId = "T005", Status = "已完成", TaskName = "项目计划书", Deadline = DateTime.Now.AddDays(-10), PersonInCharge = "张三", Progress = "100%" },
                new TaskItem { TaskId = "T006", Status = "未开始", TaskName = "接口文档编写", Deadline = DateTime.Now.AddDays(7), PersonInCharge = "李四", Progress = "0%" },
                new TaskItem { TaskId = "T007", Status = "进行中", TaskName = "后端API开发", Deadline = DateTime.Now.AddDays(5), PersonInCharge = "王五", Progress = "30%" }
            };

            // 绑定数据源  
            dataGridView1.DataSource = tasks;
        }

        private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        
{
            // 只处理数据单元格,忽略标题行/列  
            if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
            {
                // 如果是"状态"列  
                if (dataGridView1.Columns[e.ColumnIndex].Name == "Status")
                {
                    RenderCellWithIcon(e);
                }
            }
        }

        private void RenderCellWithIcon(DataGridViewCellPaintingEventArgs e)
        
{
            // 清除单元格默认内容  
            e.PaintBackground(e.CellBounds, true);


            // 获取状态图标  
            Image statusIcon = GetStatusIcon(e.Value);

            if (statusIcon != null)
            {
                // 计算图标位置(左侧)  
                Rectangle iconRect = new Rectangle(
                    e.CellBounds.X + 4,
                    e.CellBounds.Y + (e.CellBounds.Height - 16) / 2,
                    16,
                    16
                );

                // 绘制图标  
                e.Graphics.DrawImage(statusIcon, iconRect);

                // 计算文本位置(图标右侧)  
                Rectangle textRect = new Rectangle(
                    iconRect.Right + 4,
                    e.CellBounds.Y,
                    e.CellBounds.Width - iconRect.Width - 8,
                    e.CellBounds.Height
                );

                // 设置文本格式  
                StringFormat sf = new StringFormat();
                sf.Alignment = StringAlignment.Near;
                sf.LineAlignment = StringAlignment.Center;

                // 绘制文本  
                using (Brush textBrush = new SolidBrush(e.CellStyle.ForeColor))
                {
                    e.Graphics.DrawString(
                        e.Value?.ToString(),
                        e.CellStyle.Font,
                        textBrush,
                        textRect,
                        sf
                    );
                }
            }
            elseif (e.Value != null)
            {
                // 如果没有图标但有值,只绘制文本  
                Rectangle textRect = new Rectangle(
                    e.CellBounds.X + 4,
                    e.CellBounds.Y,
                    e.CellBounds.Width - 8,
                    e.CellBounds.Height
                );

                StringFormat sf = new StringFormat();
                sf.Alignment = StringAlignment.Near;
                sf.LineAlignment = StringAlignment.Center;

                using (Brush textBrush = new SolidBrush(e.CellStyle.ForeColor))
                {
                    e.Graphics.DrawString(
                        e.Value.ToString(),
                        e.CellStyle.Font,
                        textBrush,
                        textRect,
                        sf
                    );
                }
            }

            e.Handled = true;
        }

        private Image GetStatusIcon(object value)
        
{
            // 根据状态文本返回对应图标  
            switch (value?.ToString())
            {
                case"已完成":
                    return Image.FromFile("./images/complete.png");
                case"进行中":
                    return Image.FromFile("./images/processing.png");
                case"未开始":
                    return Image.FromFile("./images/pending.png");
                default:
                    return null;
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AppDataGrid
{
    // 任务项数据模型  
    publicclass TaskItem
    {

        publicstring TaskId { get; set; }
        publicstring Status { get; set; }
        publicstring TaskName { get; set; }
        public DateTime Deadline { get; set; }
        publicstring PersonInCharge { get; set; }
        publicstring Progress { get; set; }
    }
}

性能与最佳实践

  1. 使用双缓冲减少闪烁  
  2. 避免在渲染方法中进行复杂计算  
  3. 合理控制重绘区域  
  4. 使用抗锯齿渲染提升视觉效果  

注意事项

  • 自定义渲染可能影响默认行为  
  • 复杂渲染可能降低性能  
  • 保持代码简洁高效  

结语

在本文中,我们深入探讨了DataGridView控件的自定义单元格渲染机制。通过继承DataGridViewTextBoxCell类并重写Paint方法,我们实现了对单元格内容的个性化展示。这种自定义渲染方式为开发者提供了极大的灵活性,使得DataGridView控件能够满足各种复杂的界面需求。


该文章在 2025/6/10 12:06:45 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved