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

  • As everyone scrambles to protect customers and consumers from the Heartbleed virus, there will be a variety of mitigating solutions offered up to address this pesky bug. There are a variety of points within the data path where solutions could be put into place to mitigate this (and similar) vulnerabilities and customers must choose the most strategic point in the network at which to deploy their selected mitigation. Read this white paper to learn the ins and outs of mitigating the risk of Heartbleed and the …

  • Adaptation and evolution are fundamental requirements of survival -- not only in nature, but also in business. Our world has changed dramatically in a short amount of time. Many businesses are fueling and capitalizing on this change, while others are desperately clinging to a bygone era. Who is left standing in the years and decades ahead should come as no surprise. This edition of Unleashing IT highlights the companies that are embracing new circumstances, new methods, and new opportunities. By downloading …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds