Click here to Skip to main content
15,867,330 members
Articles / Programming Languages / C#
Article

Auto sizing DataGrid

Rate me:
Please Sign up or sign in to vote.
4.43/5 (14 votes)
12 Nov 20034 min read 253.1K   4K   61   30
A DataGrid that is able to resize its last column.

Introduction

Most of the projects that I build with C# are either console based or class libraries. Lately I have been building some graphical applications too. I have some experience building graphical applications using the Java - Swing interface, so I expected the transition to C# would be easy to make. One of the things I found very interesting in Java is the use of layout managers, and the great ability to customize the views of controls on the form.

C# does not make any use of layout managers, but relies on absolute positioning. This ‘feature’ is also available in Java but is of course not preferred, the use of layout managers works much better for me. Also the second strength of Java, it’s customizability, is something that I am missing in .NET. Various things that were easy to implement in Java are a lot harder in C#. In this article, I will show how to build around a rather small problem of a specific Windows Forms control, the DataGrid.

I found that the DataGrid component lacks some properties I desperately want. The problem that will be tackled here is the size of the last column. When the size of the table that is being shown is smaller than the ClientSize of the DataGrid, the last column will not resize to fit the whole area. The image below shows the problem.

Image 1

The red arrow ‘A’ is pointing to the area I am after. I want the grid to automatically resize it’s last column, or all columns a little bit, so the DataGrid fills the indicated space. This can be done, but it’s not exactly elegant. Currently my implementation is only available for DataTables as the DataSource, porting should be pretty easy however. Now for the actual work..

The code

After some searching, I found that the best way to tackle the problem, was to build a customized DataGridTableStyle. I will call it AutoResizeDataGridTableStyle, what’s in a name! This class will perform the following things:

  1. Look pretty, the default style doesn’t.
  2. Detect changes in the DataGrid’s DataSource.
  3. Detect changes in the DataGrid’s Size.

Implementing this will not be hard, detecting the changes can be done using the events that the DataGrid spits out. This will make the AutoResizeDataGridTableStyle a bit ugly because we need to register the events. This means we can’t just add a default instance of AutoResizeDataGridTableStyle to the TableStyles collection of the DataGrid.

Looking pretty

The main reason for creating a DataGridTableStyle is to make the DataGrid look nice. We will add some prettiness to the constructor. The variable OFFSET_GRID will be explained further on.

C#
public class AutoResizeDataGridTableStyle: DataGridTableStyle
{
    private int OFFSET_GRID = 39;

    public AutoResizeDataGridTableStyle(): base()
    {
        BackColor = Color.WhiteSmoke;
        AlternatingBackColor = Color.Lavender;
        ForeColor = Color.MidnightBlue;
        GridLineColor = Color.Gainsboro;
        HeaderBackColor = Color.MidnightBlue;
        HeaderForeColor = Color.WhiteSmoke;
        LinkColor = Color.Teal;
        SelectionBackColor = Color.CadetBlue;
        SelectionForeColor = Color.WhiteSmoke;
        ColumnHeadersVisible = true;
        RowHeadersVisible = true;
        HeaderFont = new Font("Microsoft Sans Serif", 8);
    }

OnDataSourceChanged

We need to detect changes in the DataSource of the DataGrid to be able to add DataGridColumnStyles to the DataGridTableStyle. The class does not support any advanced handling for these styles, it just builds normal DataGridTextBoxColumns. As you can see, this method only works for DataTables. If all this is gibberish to you, read the manual about DataGrid, it's not the best but it's a start.

C#
public void OnDataSourceChanged(object sender, EventArgs e)
{
    GridColumnStyles.Clear();
    if(DataGrid != null && DataGrid.DataSource != null &&
        DataGrid.DataSource is DataTable)
    {
        DataTable currentTable = (DataTable)DataGrid.DataSource;
        foreach(DataColumn column in currentTable.Columns)
        {
            DataGridColumnStyle style = new DataGridTextBoxColumn();
            style.HeaderText = column.ColumnName;
            style.MappingName = column.ColumnName;
            GridColumnStyles.Add(style);
        }
    }
    // Call the eventhandler for resize events
    OnDataGridResize(this,new EventArgs());
}

The method simply runs through each column in the DataTable, creates a new DataGridTextBoxColumn for it, and finally resizes the DataGrid’s columns.

OnDataGridResize

When the DataGrid changes it’s Size, the actual columns should resize with the DataGrid. This is accomplished by listening for the Resize event from the DataGrid. When the grid resizes, we will calculate the total column width and verify it’s difference to the ClientSize of the DataGrid.

This is where the main problem comes in. Calculating the total column width is possible, but you may have noticed the second arrow (B) on the image above, it points to the before-first column, a column which you cannot access in any way that I am aware of, a column that has width! This will make it next to impossible to calculate the entire table width correctly. We can make an educated guess, but screen resolutions will make this a bit hairy. An educated guess it is, and it is called OFFSET_GRID. I have actually tested this on my monitor with different resolutions, for me the value is always the same. For you? I don’t know, probably not!

First a method for calculating the total grid width:

C#
private int GetGridColumnWidth()
{
    // No columns, return error
    if(GridColumnStyles.Count == 0)
        return -1;
    // Easy 1
    int width = 0;
    foreach(DataGridColumnStyle columnStyle in GridColumnStyles)
    {
        width += columnStyle.Width;
    }

    return width + OFFSET_GRID;
}

Next the method that handles resizing events:

C#
public void OnDataGridResize(object sender, EventArgs e)
{
    // Parent?
    if(DataGrid != null)
    {
        // Get column width
        int columnWidth;
        if( (columnWidth = GetGridColumnWidth()) != -1)
        {
            // Get the client width
            int clientWidth = DataGrid.ClientSize.Width;
            // Are there columns? redundant check
            if(GridColumnStyles.Count > 0)
            {
                // whats the newWidth
                int newWidth = 
                    GridColumnStyles [GridColumnStyles.Count - 1].Width +
                    clientWidth - columnWidth;
                // is the new width valid?
                if(newWidth > PreferredColumnWidth)
                    GridColumnStyles[GridColumnStyles.Count - 1].Width = 
                                                                   newWidth;
                else
                    GridColumnStyles[GridColumnStyles.Count - 1].Width = 
                                                        PreferredColumnWidth;
            }
        }
        // Redraw
        DataGrid.Invalidate(true);
    }
}

Call it

Now we are almost at the end of this article, finally I will show how to hook up this class into a DataGrid, just a few lines of code.

C#
DataGrid gridView = new DataGrid();
AutoResizeDataGridTableStyle style = new AutoResizeDataGridTableStyle();
gridView.DataSourceChanged += new EventHandler(style.OnDataSourceChanged);
gridView.Resize += new EventHandler(style.OnDataGridResize);
style.MappingName = "MyTable";
gridView.TableStyles.Add(style);

Conclusion

After using C# for building WinForms applications, I’m afraid to say I liked Java better. The classes I have used lack the degree of customizability that I would like to see. Workarounds are available, but as the OFFSET_GRID item shows, it’s not always elegant.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer Code Counsel
Netherlands Netherlands
Wouter van Vugt is a Microsoft MVP with Office Open XML technologies and an independent consultant focusing on creating Office Business Applications (OBAs) with SharePoint, the Office 2007 system and related .NET technologies. Wouter is a frequent contributor to developer community sites such as OpenXmlDeveloper.org and MSDN and has published several white papers and articles as well a book available on line titled Open XML: the markup explained. Wouter is the founder of Code-Counsel, a Dutch company focusing on delivering cutting-edge technical content through a variety of channels. You can find out more about Wouter by reading his blog and visiting the Code-Counsel Web site.

Comments and Discussions

 
QuestionMore simple Pin
Abdo Abdelaziz28-Feb-22 21:11
Abdo Abdelaziz28-Feb-22 21:11 
QuestionI was eager to use this, but didnt work Pin
Kishore yasoju14-May-18 23:09
Kishore yasoju14-May-18 23:09 
GeneralCouldn't get it working Pin
TyronM22-Dec-05 1:22
TyronM22-Dec-05 1:22 
GeneralRe: Couldn't get it working Pin
Wouter van Vugt22-Dec-05 1:29
Wouter van Vugt22-Dec-05 1:29 
GeneralRe: Couldn't get it working Pin
TyronM22-Dec-05 2:09
TyronM22-Dec-05 2:09 
GeneralOFFSET_GRID Value!! Pin
pan_foka13-Dec-04 8:15
pan_foka13-Dec-04 8:15 
GeneralFair Attempt Pin
Marty Spallone9-Nov-04 4:24
Marty Spallone9-Nov-04 4:24 
GeneralRe: Fair Attempt Pin
Wouter van Vugt18-Nov-04 8:25
Wouter van Vugt18-Nov-04 8:25 
QuestionCan you show me an example? Pin
EL HACHIMI10-Jun-04 5:13
EL HACHIMI10-Jun-04 5:13 
AnswerRe: Can you show me an example? Pin
Anonymous11-Jun-04 8:00
Anonymous11-Jun-04 8:00 
GeneralEditing DataGrid selected columns Pin
arahi7-Apr-04 23:17
arahi7-Apr-04 23:17 
GeneralRe: Editing DataGrid selected columns Pin
Wouter van Vugt8-Apr-04 6:04
Wouter van Vugt8-Apr-04 6:04 
GeneralRe: Editing DataGrid selected columns Pin
arahi8-Apr-04 9:32
arahi8-Apr-04 9:32 
GeneralA better resizing routine is here Pin
Griffo20-Nov-03 4:15
Griffo20-Nov-03 4:15 
GeneralRe: A better resizing routine is here Pin
Wouter van Vugt20-Nov-03 4:35
Wouter van Vugt20-Nov-03 4:35 
GeneralReplacement for this article Pin
Wouter van Vugt19-Nov-03 9:39
Wouter van Vugt19-Nov-03 9:39 
GeneralYour "Offset" Column Pin
Arnd18-Nov-03 21:02
Arnd18-Nov-03 21:02 
GeneralRe: Your "Offset" Column Pin
Wouter van Vugt18-Nov-03 21:47
Wouter van Vugt18-Nov-03 21:47 
GeneralAnother solution Pin
A.Wegierski18-Nov-03 18:50
A.Wegierski18-Nov-03 18:50 
GeneralRe: Another solution Pin
Wouter van Vugt18-Nov-03 21:44
Wouter van Vugt18-Nov-03 21:44 
GeneralRe: Another solution Pin
A.Wegierski18-Nov-03 22:49
A.Wegierski18-Nov-03 22:49 
GeneralRe: Another solution Pin
Wouter van Vugt19-Nov-03 9:31
Wouter van Vugt19-Nov-03 9:31 
GeneralRe: Another solution Pin
A.Wegierski20-Nov-03 20:23
A.Wegierski20-Nov-03 20:23 
GeneralChange cursor on Datagrid Column Header or Caption Area Pin
Neeraj Jain18-Nov-03 12:17
Neeraj Jain18-Nov-03 12:17 
GeneralRe: Change cursor on Datagrid Column Header or Caption Area Pin
Wouter van Vugt18-Nov-03 21:41
Wouter van Vugt18-Nov-03 21:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.