DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

DataGridの列の幅を文字列の幅に合わせて自動的に調節する

注意:ここで紹介しているDataGridは、System.Windows.Forms名前空間のDataGrid(Windowsフォーム)です。System.Web.UI.WebControls名前空間のDataGrid(Webフォーム)ではありません。

DataGridの列の幅を、その列にあるすべてのセルとヘッダの文字列の最大幅となるように自動調節するには、DataGridの列のすべてのセルの文字列(及びヘッダのHeaderText)の長さをGraphics.MeasureStringメソッドで調べ、一番長いものに列のWidthを設定するという方法になるでしょう。

この方法を使った簡単なコードを以下に紹介します。ここでは、DataGridのDataSourceにDataTableが設定されているものとします。

VB.NET
コードを隠すコードを選択
''' <summary>
''' DataGridの列の幅をTextの幅に合わせて変更する
''' </summary>
''' <param name="grid">対象とするDataGrid</param>
''' <param name="column">列の番号</param>
Public Shared Sub AutoSizeColumnWidth( _
    ByVal grid As DataGrid, ByVal column As Integer)
    'DataGridのGraphicsを取得
    Dim g As Graphics = Graphics.FromHwnd(grid.Handle)

    'すべてのセルを調べて、一番広い幅を取得
    Dim sf As New StringFormat(StringFormat.GenericTypographic)
    Dim dt As DataTable = CType(grid.DataSource, DataTable)
    Dim rowsCount As Integer = dt.Rows.Count
    Dim maxWidth As Single = 0
    Dim i As Integer
    For i = 0 To rowsCount - 1
        Dim [text] As String = grid(i, column).ToString()
        maxWidth = Math.Max(g.MeasureString( _
            [text], grid.Font, grid.Width, sf).Width, maxWidth)
    Next i

    'ヘッダの幅も考慮
    Dim cs As DataGridColumnStyle = _
        grid.TableStyles(dt.TableName).GridColumnStyles(column)
    maxWidth = Math.Max(g.MeasureString( _
        cs.HeaderText, grid.Font, grid.Width, sf).Width, maxWidth)

    '破棄
    g.Dispose()

    '幅の変更
    cs.Width = CInt(maxWidth) + 8
End Sub
C#
コードを隠すコードを選択
/// <summary>
/// DataGridの列の幅をTextの幅に合わせて変更する
/// </summary>
/// <param name="grid">対象とするDataGrid</param>
/// <param name="column">列の番号</param>
public static void AutoSizeColumnWidth(DataGrid grid, int column)
{
    //DataGridのGraphicsを取得
    Graphics g = Graphics.FromHwnd(grid.Handle);

    //すべてのセルを調べて、一番広い幅を取得
    StringFormat sf =
        new StringFormat(StringFormat.GenericTypographic);
    DataTable dt = ((DataTable) grid.DataSource);
    int rowsCount = dt.Rows.Count;
    float maxWidth = 0;
    for (int i = 0; i < rowsCount; i++)
    {
        string text = grid[i, column].ToString();
        maxWidth = Math.Max(g.MeasureString(
            text, grid.Font, grid.Width, sf).Width, maxWidth);
    }

    //ヘッダの幅も考慮
    DataGridColumnStyle cs =
        grid.TableStyles[dt.TableName].GridColumnStyles[column];
    maxWidth = Math.Max(g.MeasureString(
        cs.HeaderText, grid.Font, grid.Width, sf).Width, maxWidth);
    
    //破棄
    g.Dispose();

    //幅の変更
    cs.Width = (int) maxWidth + 8;
}

この方法は「Windows Forms FAQ - 5.52 How can I autosize a column in my datagrid?」や「microsoft.public.dotnet.languages.vb - Re: how-to autosize the width of a column in a DataGrid」でも紹介されていますので、参考にしてください。

しかしこの方法には欠点があります。それは、セル内に表示される文字列をToStringで取得している点です。実際に表示される文字列はToStringで取得できる文字列と同じになるとは限りません。しかし残念ながら、実際に表示される文字列を取得するのはとても難しいです。例えばDataGridTextBoxColumnが設定されている場合は、DataGridTextBoxColumnのGetTextメソッドで取得できますが、このメソッドがprivateのため、通常はアクセスできません。

よって実際に表示される文字列を取得するには、「隠蔽されている非パブリックメンバを呼び出す」のようにリフレクションを使ってGetTextメソッドにアクセスするか、自分で列スタイルを作成するかなどの方法になりそうです。(自分でGetTextと同じことをするコードを書く方法もありますが、全く同じになる保障はありません。)

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。