You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinForms DataGridView同一列如何实现货币与百分比双格式?

WinForms DataGridView同一列根据字段值设置不同显示格式

我在WinForms项目的DataGridView中有一个名为Discount Value的列,需要根据Discount Type字段的值,分别以印尼货币(Rp格式)和百分比格式显示数据。请问能否在DataGridView的同一列中设置不同的显示格式?

我尝试了以下代码,但输出未达到预期效果,问题出在CtechGroupedDataGridView_CellFormatting事件处理方法中:

namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            List<RegulerDiscountModel> regulerDiscountModelList = new List<RegulerDiscountModel>();

            RegulerDiscountModel regulerDiscountModel1 = new RegulerDiscountModel();
            regulerDiscountModel1.RegulerDiscountID = 1;
            regulerDiscountModel1.RegulerDiscountProductId = 1;
            regulerDiscountModel1.RegulerDiscountProductName = "Product 1";
            regulerDiscountModel1.RegulerDiscountName = "Disc1";
            regulerDiscountModel1.RegulerDiscountValue = 1000;
            regulerDiscountModel1.RegulerDiscountStrTypeId = "Rp";
            regulerDiscountModelList.Add(regulerDiscountModel1);

            RegulerDiscountModel regulerDiscountModel2 = new RegulerDiscountModel();
            regulerDiscountModel2.RegulerDiscountID = 1;
            regulerDiscountModel2.RegulerDiscountProductId = 1;
            regulerDiscountModel2.RegulerDiscountProductName = "Product 1";
            regulerDiscountModel2.RegulerDiscountName = "Disc2";
            regulerDiscountModel2.RegulerDiscountValue = 2000;
            regulerDiscountModel2.RegulerDiscountStrTypeId = "Rp";
            regulerDiscountModelList.Add(regulerDiscountModel2);

            RegulerDiscountModel regulerDiscountModel3 = new RegulerDiscountModel();
            regulerDiscountModel3.RegulerDiscountID = 1;
            regulerDiscountModel3.RegulerDiscountProductId = 1;
            regulerDiscountModel3.RegulerDiscountProductName = "Product 1";
            regulerDiscountModel3.RegulerDiscountName = "Disc3";
            regulerDiscountModel3.RegulerDiscountValue = 10.5;
            regulerDiscountModel3.RegulerDiscountStrTypeId = "%";
            regulerDiscountModelList.Add(regulerDiscountModel3);

            RegulerDiscountModel regulerDiscountModel4 = new RegulerDiscountModel();
            regulerDiscountModel4.RegulerDiscountID = 1;
            regulerDiscountModel4.RegulerDiscountProductId = 1;
            regulerDiscountModel4.RegulerDiscountProductName = "Product 1";
            regulerDiscountModel4.RegulerDiscountName = "Disc4";
            regulerDiscountModel4.RegulerDiscountValue = 20.1;
            regulerDiscountModel4.RegulerDiscountStrTypeId = "%";
            regulerDiscountModelList.Add(regulerDiscountModel4);

            CtechGroupedDataGridView.DataSource = regulerDiscountModelList;
            CtechGroupedDataGridView.CellFormatting += CtechGroupedDataGridView_CellFormatting;
        }

        private void CtechGroupedDataGridView_CellFormatting(object? sender, DataGridViewCellFormattingEventArgs e)
        {
            try
            {
                if (e.RowIndex >= 0 && e.RowIndex <= CtechGroupedDataGridView.Rows.Count - 1)
                {
                    DataGridViewRow row = CtechGroupedDataGridView.CurrentRow;
                    if (row != null)
                    {
                        // ID ProductId ProductName DiscountName DiscountValue DiscountType
                        // 0  1         2           3            4             5

                        if (row.Cells[4].Value != null && row.Cells[5].Value != null)
                        {
                            String? strDiscountValue = row.Cells[4].Value.ToString();
                            String? strDiscountType = row.Cells[5].Value.ToString();
                            if (!String.IsNullOrEmpty(strDiscountValue) && !String.IsNullOrEmpty(strDiscountType))
                            {
                                switch (strDiscountType)
                                {
                                    case "Rp":
                                        CtechGroupedDataGridView[4, e.RowIndex].Style.Format = "N0";
                                        break;

                                    case "%":
                                        CtechGroupedDataGridView[4, e.RowIndex].Style.Format = "P1";
                                        break;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

效果说明

  • 当前输出效果:所有Discount Value列显示原始数字,未应用任何格式(如1000、2000、10.5、20.1)
  • 点击DataGridView后效果:部分单元格格式错乱,百分比类型数值未正确处理
  • 期望输出效果:
    • Discount Type为Rp的行,Discount Value显示为Rp 1,000、Rp 2,000格式
    • Discount Type为%的行,Discount Value显示为10.5%、20.1%格式

自定义CtechGroupedDataGridView代码

namespace WinFormsApp1
{
    public partial class CtechGroupedDataGridView : DataGridView
    {
        public CtechGroupedDataGridView()
        {
            InitializeComponent();

            DoubleBuffered = true;
            GridColor = Color.LightGray;
            BackgroundColor = SystemColors.Control;
            BorderStyle = BorderStyle.None;
            SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            ColumnGroupEnabled = new int[] { 1, 2};

            ClearSelection();
        }

        protected override void OnDataBindingComplete(DataGridViewBindingCompleteEventArgs e)
        {
            base.OnDataBindingComplete(e);

            // Fit columns
            int columnsWidth = 0;
            foreach (DataGridViewColumn column in this.Columns)
            {
                if (column.Visible)
                {
                    columnsWidth += column.Width;
                }
            }

            if (columnsWidth < this.Width)
            {
                for (int i = 0; i < this.Columns.Count; i++)
                {
                    this.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                }
                this.Columns[this.Columns.Count - 1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
            }
            else
            {
                for (int i = 0; i < this.Columns.Count; i++)
                {
                    this.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                }
            }

            for (int i = 0; i < this.Columns.Count; i++)
            {
                int column = this.Columns[i].Width;
                this.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
                this.Columns[i].Width = column;
                this.Columns[i].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
            }

            ClearSelection();
        }


        protected override void OnCellFormatting(DataGridViewCellFormattingEventArgs args)
        {
            // Call home to base
            base.OnCellFormatting(args);

            // First row always displays
            if (args.RowIndex == 0)
            {
                return;
            }

            if (IsRepeatedCellValue(args.RowIndex, args.ColumnIndex))
            {
                args.Value = string.Empty;
                args.FormattingApplied = true;
            }
        }

        private bool IsRepeatedCellValue(int rowIndex, int colIndex)
        {
            if (ColumnGroupEnabled.Contains(colIndex))
            {
                DataGridViewCell currCell = Rows[rowIndex].Cells[colIndex];
                DataGridViewCell prevCell = Rows[rowIndex - 1].Cells[colIndex];

                if (currCell.Value != null && prevCell.Value != null)
                {
                    if ((currCell.Value == prevCell.Value) || (currCell.Value.ToString() == prevCell.Value.ToString()))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public int[] ColumnGroupEnabled { get; set; }


        protected override void OnCellPainting(DataGridViewCellPaintingEventArgs args)
        {
            base.OnCellPainting(args);

            // Keep first and last row to visible
            if (args.RowIndex >= 0 && args.RowIndex < RowCount - 1)
            {
                args.AdvancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None;
            }

            // Ignore column and row headers and first row
            if (args.RowIndex < 1 || args.ColumnIndex < 0)
            {
                return;
            }

            if (IsRepeatedCellValue(args.RowIndex, args.ColumnIndex))
            {
                args.AdvancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None;
            }
            else
            {
                args.AdvancedBorderStyle.Top = AdvancedCellBorderStyle.Top;
            }
        }
    }
}

RegulerDiscountModel代码

public class RegulerDiscountModel
{
    public RegulerDiscountModel()
    {
    }

    [DisplayName("ID")]
    public int RegulerDiscountID
    {
        get; set;
    }

    [DisplayName("Product Id")]
    public int RegulerDiscountProductId
    {
        get; set;
    }

    [DisplayName("Product Name")]
    public String? RegulerDiscountProductName
    {
        get; set;
    }

    [DisplayName("Discount Name")]
    public String? RegulerDiscountName
    {
        get; set;
    }

    [DisplayName("Discount Value")]
    public double RegulerDiscountValue
    {
        get; set;
    }

    [DisplayName("Discount Type")]
    public String? RegulerDiscountStrTypeId
    {
        get; set;
    }
}

问题分析与修复方案

你的代码核心问题在于CellFormatting事件中的错误逻辑:

  1. 使用CurrentRow获取行,导致始终处理选中行而非正在格式化的行
  2. 直接设置单元格Style.Format的时机错误,未利用事件参数完成格式化

修复后的CtechGroupedDataGridView_CellFormatting方法:

private void CtechGroupedDataGridView_CellFormatting(object? sender, DataGridViewCellFormattingEventArgs e)
{
    try
    {
        // 仅处理Discount Value列(索引4)
        if (e.ColumnIndex == 4 && e.RowIndex >= 0 && e.RowIndex < CtechGroupedDataGridView.Rows.Count)
        {
            DataGridViewRow row = CtechGroupedDataGridView.Rows[e.RowIndex];
            var discountType = row.Cells[5].Value?.ToString();
            if (discountType == null) return;

            if (double.TryParse(e.Value?.ToString(), out double discountValue))
            {
                switch (discountType)
                {
                    case "Rp":
                        // 格式化为带Rp前缀的千分位数字
                        e.Value = $"Rp {discountValue:N0}";
                        e.FormattingApplied = true;
                        break;
                    case "%":
                        // 格式化为保留1位小数的百分比
                        e.Value = $"{discountValue:P1}";
                        e.FormattingApplied = true;
                        break;
                }
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

关键修复点

  • 通过e.ColumnIndex精准定位目标列,避免无意义的处理
  • 使用Rows[e.RowIndex]获取当前正在格式化的行,而非选中行
  • 直接设置e.Value为格式化后的字符串,并标记FormattingApplied = true,告知DataGridView已完成格式化
  • 增加数值解析容错逻辑,避免类型转换异常

内容的提问来源于stack exchange,提问作者Ihdina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:54:57