Search code examples
c#winformsdatagridviewdatagridviewcolumncolumnsorting

How to remove sorting glyph in datagridview without removing Sorting facility


How can i remove sorting glyph from column headers in DataGridView without removing its sorting functionality.

I am working on windows form application in C#, i want to generate report from a datagridview, where datagridview column width will assign in report column, where as the DataGridView column include the with of sorting glyph, that is unnecessary space in my case, i want to exclude it from ColumnHeader.


Solution

  • This is actually quite easy to do using custom cell painting.

    All you need to do is handle the DataGridView CellPainting event:

    dataGridView1.CellPainting += new DataGridViewCellPaintingEventHandler(dataGridView1_CellPainting);
    

    And in the handler do something like this:

    void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
    {
        if (e.RowIndex == -1)
        {
            e.Paint(e.CellBounds, DataGridViewPaintParts.All &~DataGridViewPaintParts.ContentBackground);
    
            e.Handled = true;
        }
    }
    

    The code above is very simple - just check if the current cell is in a header row (has a -1 index) then paint everything except the ContentBackground.

    I've only checked this on my Windows 7 machine and it looks fine, it appears that the content background is only used for the sort glyph - you will want to test it on the target environment to make sure you don't need to do any more involved custom painting to keep the ContentBackground without the glyph.


    The width of the header cell will still include the space for the glyph. I would generally accept that since changing this becomes a bit messy, but if you must have the width fit the text then something like the following will work.

    First set the width in the DataBindingComplete event of the DataGridView:

    void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
    {        
        if (dataGridView1.AutoSizeColumnsMode == DataGridViewAutoSizeColumnsMode.AllCells)
        {
            // Loop over all the columns
            foreach (DataGridViewColumn c in dataGridView1.Columns)
            {
                // Work out the size of the header text
                Size s = TextRenderer.MeasureText(c.HeaderText, dataGridView1.Font);
    
                // Change the autosize mode to allow us to see if the header cell has the 
                // longest text
                c.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
                if (s.Width + 10 > c.Width)
                {
                    // If the header cell is longest we set the column width
                    c.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
                    c.Width = s.Width + 10;
                }
                else
                {
                    // If the header cell is not longest, reset the autosize mode
                    c.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                }
            }
        }
    }
    

    Once you have done that you then need to still allow the column to autosize when the cell text is longer than the header.

    For that I used the CellValueChanged event:

    void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        DataGridViewColumn c = dataGridView1.Columns[e.ColumnIndex];
    
        if (c.AutoSizeMode == DataGridViewAutoSizeColumnMode.None)
        {
            Size s = TextRenderer.MeasureText(dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString(), dataGridView1.Font);
            if (s.Width > c.Width)
            {
                c.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
            }
        }
    
    }