New to Telerik UI for WinForms? Download free 30-day trial

How to Skip Rounding Decimal Values in GridView

Environment

Product Version Product Author
2022.2.622 RadGridView for WinForms Desislava Yordanova

Description

The GridViewDecimalColumn offers DecimalPlaces property which allows you to specify how many decimal places will be displayed in the cell. If you set 2 decimal places to be shown but the cells contain values with more decimal places, it is expected to be rounded to the decimal places. This is desired behavior. Consider the following setup:


DataTable dt = new DataTable();
dt.Columns.Add("Price", typeof(decimal));
dt.Rows.Add(12.4678m);
dt.Rows.Add(234.581m);
dt.Rows.Add(3.566m);
dt.Rows.Add(35.459m);
this.radGridView1.DataSource = dt;

GridViewDecimalColumn decimalColumn = this.radGridView1.Columns["Price"] as GridViewDecimalColumn;
decimalColumn.DecimalPlaces = 2;
decimalColumn.FormatString = "{0:N2}";

It is expected the numeric values to be rounded up to 2 decimal places:

skip-decimal-rounding-in-gridview 001

This article demonstrates a sample approach how to skip the rounding and trim the numeric values to display 2 decimal places.

Solution

It is necessary to handle the CellFormatting event and manipulate the text for the cells in order to trim the numeric value. In addition to this, a custom GridSpinEditor is required to skip the rounding:

skip-decimal-rounding-in-gridview 001

The end-user still can enter more decimal places than the specified value but the number will be trimmed without rounding:


public RadForm1()
{
    InitializeComponent();

    this.radGridView1.CellFormatting += radGridView1_CellFormatting;
    this.radGridView1.EditorRequired += RadGridView1_EditorRequired;

    DataTable dt = new DataTable();
    dt.Columns.Add("Price", typeof(decimal));
    dt.Rows.Add(12.4678m);
    dt.Rows.Add(234.581m);
    dt.Rows.Add(3.566m);
    dt.Rows.Add(35.459m);
    this.radGridView1.DataSource = dt;

    GridViewDecimalColumn decimalColumn = this.radGridView1.Columns["Price"] as GridViewDecimalColumn;
    decimalColumn.DecimalPlaces = 2;
    decimalColumn.FormatString = "{0:N2}";

    this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
}

private void radGridView1_CellFormatting(object sender, CellFormattingEventArgs e)
{
    if (e.Column.HeaderText == "Price" && e.Row is GridViewDataRowInfo && e.CellElement.Value != null)
    {
        e.CellElement.Text = TrimValue(e.CellElement.Value,((GridViewDecimalColumn)e.Column).DecimalPlaces);
    }
}

public static string TrimValue(object input, int decimalPlaces)
{
    string internalValue = input + "";
    int decimalPointIndex = internalValue.IndexOf(".");
    if (decimalPointIndex > -1)
    { 
        StringBuilder sb = new StringBuilder();
        sb.Append(internalValue.Substring(0, decimalPointIndex));
        sb.Append(internalValue.Substring(decimalPointIndex, decimalPlaces + 1));
        return sb.ToString();
    }
    return internalValue;
}

private void RadGridView1_EditorRequired(object sender, EditorRequiredEventArgs e)
{
    if (e.EditorType == typeof(GridSpinEditor))
    {
        e.Editor = new CustomSpinEditor();
    }
}

public class CustomSpinEditor : GridSpinEditor
{
    protected override RadElement CreateEditorElement()
    {
        return new CustomSpinEditorElement();
    }

    public override object Value
    {
        get { return base.Value; }
        set
        {
            string internalValue = value + "";
            int decimalPointIndex = internalValue.IndexOf(".");
            if (decimalPointIndex > -1)
            {
                decimal trimmedValue = 0;
                GridCellElement cell = this.OwnerElement as GridCellElement;
                if (cell != null && decimal.TryParse(TrimValue(value, ((GridViewDecimalColumn)cell.ColumnInfo).DecimalPlaces), out trimmedValue))
                {
                    base.Value = trimmedValue;
                }

            }
            base.Value = value;
        }
    }

    public class CustomSpinEditorElement : RadSpinEditorElement
    {
        protected override string GetNumberText(decimal num)
        {
            return TrimValue(num, this.DecimalPlaces);
        }

        protected override void ValidateCore()
        {
            decimal trimmedValue = 0;
            string trimmedText = GetNumberText(this.internalValue);
            decimal newValue = 0;
            if (decimal.TryParse(trimmedText, out trimmedValue))
            {
                newValue = trimmedValue;
            }

            if (newValue != this.internalValue)
            {
                this.internalValue = newValue;
                this.TextBoxItem.Text = GetText(this.internalValue, this.Hexadecimal, this.ThousandsSeparator, this.DecimalPlaces);
            }
        }

        private string GetText(decimal num, bool hex, bool thousands, int decimalPlaces)
        {
            if (hex)
            {

                return string.Format("{0:X}", (long)num);
            }

            return num.ToString((thousands ? "N" : "F") + decimalPlaces.ToString(CultureInfo.CurrentCulture), CultureInfo.CurrentCulture);
        }
    }
}

It is just a sample approach and it may not cover all possible cases. Feel free to modify and extend it in a way that suits your requirements best.