Autosize a DataGridView to Fit

This article describes how you can resize a dbgrid to always fit the form after a resize so that you never have a horizontal scrollbar.

Description

What the code does is first recalculate all columns' width (if you have visible columns). But, at the end, you could have rounding errors and still have a scrollar if the last column is 1 or more pixels too wide. So, at the end you calculate the exact width needed for the last column.

Let me describe some importand code fragments.

int fixedWidth = SystemInformation.VerticalScrollBarWidth +
   dataGrid.RowHeadersWidth + 2;
int mul = 100 * (dataGrid.Width - fixedWidth) /
   (prevWidth - fixedWidth);

First, check the fixed width of the datagrid. This is the width of the scrollbar and the width of the row headers. You include the row headers because resizing these is very ugly. Now, what about this multiplying by 100? You are going to multiply/divide the width of the columms with a number containing a decimal point (for example, if you make the form 50 percent, you will multiply by 0.5). But, working with float numbers is very slow and not needed with a little imagination). So, you take an integer and multiply by 100 to get 2 decimal fractions.

The correction of adding 2 pixels to the fixedWidth is important. This is dependent on the BorderStyle of the grid. You need the 2 pixel if it is set to FixedStyle. You don't need it when it is set to None, and you have to increase it if set to Fixed3D, of course.

Then, you step trough all visible columns to calculate the new width. Of course, you take into account that there is a MinimumWidth property.

columnWidth = (dataGrid.Columns[i].Width * mul + 50)
   / 100;
dataGrid.Columns[i].Width =
   Math.Max(columnWidth,
   dataGrid.Columns[i].MinimumWidth);

What about thie + 50? Well, remember that we emulate a floating point with integer. So, by adding 50 before dividing by 100, you round it. If you do not, we truncate, and with every resize each column will be a little smaller and smaller.

The last thing to do is check the exact width of the last column. This is nececary because you could have little rounding errors, or be limited by the MinimumWidth of some columns. Then, you end up with either a scrollbar or a blank space after the last column, both of which is very ugly.

Complete Code

public void ResizeGrid(DataGridView dataGrid, ref int prevWidth)
{
   if (prevWidth == 0)
      prevWidth = dataGrid.Width;
   if (prevWidth == dataGrid.Width)
      return;

   int fixedWidth = SystemInformation.VerticalScrollBarWidth +
      dataGrid.RowHeadersWidth + 2;
   int mul = 100 * (dataGrid.Width - fixedWidth) /
      (prevWidth - fixedWidth);
   int columnWidth;
   int total = 0;
   DataGridViewColumn lastVisibleCol = null;

   for (int i = 0; i < dataGrid.ColumnCount; i++)
      if (dataGrid.Columns[i].Visible) {
         columnWidth = (dataGrid.Columns[i].Width * mul + 50) / 100;
         dataGrid.Columns[i].Width =
            Math.Max(columnWidth, dataGrid.Columns[i].MinimumWidth);
         total += dataGrid.Columns[i].Width;
         lastVisibleCol = dataGrid.Columns[i];
      }
   if (lastVisibleCol == null)
      return;
   columnWidth = dataGrid.Width - total +
      lastVisibleCol.Width - fixedWidth;
   lastVisibleCol.Width =
      Math.Max(columnWidth, lastVisibleCol.MinimumWidth);
   prevWidth = dataGrid.Width;
}

Test Application

This is how to use it. Note that you have two variables in your form, to remember the WindowState and the last width.

You do not recalculate in the Resize event because there will be so many recalculations (especially when the user resizes very slowly) that you will get out of proportion due to rounding errors. So, you use ResizeEnd to calculate one time after resizing. But, you also need to recalculate when the user maximizes or restores the form. That you do in the Resize event.

This is the complete code:

namespace ResizeGridDemo
{
   public partial class main: Form
   {
      int prevWidth;
      FormWindowState prevWindowState;

      public main()
      {
         InitializeComponent();
         prevWidth = Width;
         prevWindowState = WindowState;
      }

      private void main_ResizeEnd(object sender, EventArgs e)
      {
         ResizeGrid(dataGrid, ref prevWidth);
      }

      private void main_Resize(object sender, EventArgs e)
      {
         if (WindowState != prevWindowState && WindowState !=
             FormWindowState.Minimized) {
            prevWindowState = WindowState;
            ResizeGrid(dataGrid, ref prevWidth);
         }
      }
   }
}

Summary

Rather that put all this code in a form, it could be in a subclass of DataGridView, or even in a new component derived from it.

Note: I use VS beta 2. Things can be different in the .NET 1.1 version.

If you use this code in a project, you only need it one time; for example, in a static class. Each form must have the prevSize variable, and if the form can be maximized, it also needs the prevWindowState variable.



Downloads

Comments

  • Developer

    Posted by Mark Helwig on 07/16/2013 03:44pm

    This was great. Thanks.

    Reply
  • vb6 Function to resize grid

    Posted by utopians123 on 01/19/2007 10:41am

    Could this be implemented using vb6 with just a public function

    • vb6

      Posted by wmestdagh on 01/19/2007 12:25pm

      Hi, yes of course, you can easy translate it to vb. rgds, Wilfried

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: May 6, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT While you likely have very good reasons for remaining on WinXP after end of support -- an estimated 20-30% of worldwide devices still are -- the bottom line is your security risk is now significant. In the absence of security patches, attackers will certainly turn their attention to this new opportunity. Join Lumension Vice President Paul Zimski in this one-hour webcast to discuss risk and, more importantly, 5 pragmatic risk mitigation techniques …

  • Live Event Date: April 22, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Database professionals — whether developers or DBAs — can often save valuable time by learning to get the most from their new or existing productivity tools. Whether you're responsible for managing database projects, performing database health checks and reporting, analyzing code, or measuring software engineering metrics, it's likely you're not taking advantage of some of the lesser-known features of Toad from Dell. Attend this live …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds