Introduction
The WinForms DataGridView
has a lot of smarts built into it so that it can easily deal with presenting a large grid in a small Form, but many times the developer would prefer to automatically expand the Form in order to show all (or most) of the grid rather than make the user do so manually. Such functionality is not built into the framework, and a quick online search will turn up many developers seeking a solution.
Something the user (and therefore the developer) will likely wish to avoid is having a Form expand to enormous proportions, so some ability to constrain the size of the Form is desired. The solution I present below has two methods to control the maximum size of the Form.
Similarly, when presenting a very small grid, having the Form contract to such a small size that other controls on the Form are not visible would not be desirable.
I wrote this method to support a WinForms application that needs to present a grid and a few buttons in a dialog. It appears to work well in this capacity though I'm unsure how well-suited it would be for use in a main Form. I have also not tried it with more than one DataGridView
on one Form.
Using the Code
Download the attached source code and include it in your project.
Before calling this method, please be sure you have all the properties of the DataGridView
set the way you like. For instance, if you are going to hide columns or enable row and column auto-resizing, you should do so before calling this method.
Similarly, be sure that the MinimumSize
and MaximumSize
properties of the Form are set the way you want before calling this method.
The method also accepts a Rectangle
to use as a constraint which limits the Form to an area of the user's screen(s). A constraint is similar to setting the MaximumSize
of the Form, but it also allows the Form to be moved. For the application I'm working on, I use System.Windows.Forms.Screen.FromControl ( Grid ).Bounds
as a constraint to ensure that the Form stays on one physical monitior; the user may then manually resize the Form beyond that size. A value of System.Drawing.Rectangle.Empty
acts as "no constraint".
If you do not constrain the Form with either MaximumSize
or a Constraint
rectangle, then the user may wind up with a very large Form that extends well beyond his physical monitor(s). Please be sure that that is the desired behaviour before you release such an application to your users.
There are some other options that can be specified and I'll discuss them as we go along. The options are bitmapped flags, of course.
Example:
PIEBALD.Lib.LibWin.ResizeFormToFitDataGridView
(
myGrid
,
System.Drawing.Rectangle.Empty
,
PIEBALD.Lib.LibWin.ResizeFormOption.HonorMinimumSize
|
PIEBALD.Lib.LibWin.ResizeFormOption.HonorMaximumSize
) ;
ResizeFormToFitDataGridView
The process of calculating the size required to show the whole grid is pretty simple.
Calculate the desired width
int width = lagniappe ;
width += form.Width - Grid.Width ;
width += Grid.RowHeadersWidth ;
for ( int i = 0 ; i < Grid.ColumnCount ; i++ )
{
if ( Grid.Columns [ i ].Visible )
{
width += Grid.Columns [ i ].Width ;
}
}
Calculate the desired height
int height = lagniappe ;
height += form.Height - Grid.Height ;
height += Grid.ColumnHeadersHeight ;
for ( int i = 0 ; i < Grid.RowCount ; i++ )
{
if ( Grid.Rows [ i ].Visible )
{
height += Grid.Rows [ i ].Height ;
}
}
lagniappe
is a constant that I add in order to avoid scroll bars in certain situations; you may need to adjust it, but the value 2 works on my system.
This gives us the total width and height required to show the whole grid, but it may be too small or too big, so...
Honor the MinimumSize of the Form when requested
HonorMinimumSize
is an option that can be specified.
if ( ( Options & ResizeFormOption.HonorMinimumSize ) == ResizeFormOption.HonorMinimumSize )
{
if ( width < form.MinimumSize.Width )
{
width = form.MinimumSize.Width ;
}
if ( height < form.MinimumSize.Height )
{
height = form.MinimumSize.Height ;
}
}
Honor the MaximumSize of the Form when requested
HonorMaximumSize
is an option that can be specified.
if ( ( Options & ResizeFormOption.HonorMaximumSize ) == ResizeFormOption.HonorMaximumSize )
{
if ( ( form.MaximumSize.Width > 0 ) && ( width > form.MaximumSize.Width ) )
{
width = form.MaximumSize.Width ;
}
if ( ( form.MaximumSize.Height > 0 ) && ( height > form.MaximumSize.Height ) )
{
height = form.MaximumSize.Height ;
}
}
maxsize
This size is saved as the maxsize
.
Apply Constraint when requested
Provide a Rectangle
other than Rectangle.Empty
to apply a constraint. No validation of the constraint will be performed; please be sure to provide a meaningful rectangle.
if ( Constraint != System.Drawing.Rectangle.Empty )
{
if ( width > Constraint.Width )
{
form.Left = Constraint.X ;
width = Constraint.Left + Constraint.Width - form.Left ;
}
else if ( width > Constraint.Left + Constraint.Width - form.Left )
{
form.Left -= width - ( Constraint.Left + Constraint.Width - form.Left ) ;
}
if ( height > Constraint.Height )
{
form.Top = Constraint.Y ;
height = Constraint.Y + Constraint.Height - form.Top ;
}
else if ( height > Constraint.Top + Constraint.Height - form.Top )
{
form.Top -= height - ( Constraint.Y + Constraint.Height - form.Top ) ;
}
}
minsize
This size is saved as the minsize
and we try to resize the Form to this size.
Handling ArgumentOutOfRangeExceptions
Throw
is an option that can be specified. Resizing the Form may throw an ArgumentOutOfRangeException
, and the caller may choose whether or not to swallow such an exception once it has been caught. If this option is not specified, and this type of exception is encountered, then the return value will be set to false
.
catch ( System.ArgumentOutOfRangeException err )
{
if ( ( Options & ResizeFormOption.Throw ) == ResizeFormOption.Throw )
{
err.Data [ "Top" ] = form.Top ;
err.Data [ "Left" ] = form.Left ;
err.Data [ "Width" ] = width ;
err.Data [ "Height" ] = height ;
throw ;
}
result = false ;
}
Freeze the Form when requested
Freeze
is an option that can be specified. This will set the MaximumSize
and MinimumSize
properties of the Form, and, if they are equal, it will set the FormBorderStyle
to fixed. This limits the ability of the user to manually resize the Form.
A Form that expands well beyond the user's physical monitor(s) and then becomes non-resizable would be considered user-hostile, so please don't Freeze
a Form unless you have also constrained it to a reasonable size. You have been warned.
if ( ( Options & ResizeFormOption.Freeze ) == ResizeFormOption.Freeze )
{
form.MaximumSize = maxsize ;
form.MinimumSize = minsize ;
if ( minsize == maxsize )
{
switch ( form.FormBorderStyle )
{
case System.Windows.Forms.FormBorderStyle.Sizable :
{
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle ;
break ;
}
case System.Windows.Forms.FormBorderStyle.SizableToolWindow :
{
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow ;
break ;
}
}
}
}
Conclusion
This method does what I need it to on my system, but I have also seen it behave a little oddly (nothing catastrophic) on a colleague's system and I haven't yet spent any time tracking down the cause -- I think it's due mainly to Windows themes, but I could be wrong.
I have performed only minimal testing and not thrown unusual values at it. Any feedback on how it behaves on your system(s) would be appreciated.
History
- 2016-01-03 First submitted