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

DataGridの列ヘッダテキストの配置方法のみを変更する

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

例えば、Windowsアプリケーションで、DataGridコントロールの列ヘッダのテキストだけ中央に配置されるようにしたくても、「DataGridの列のテキストの配置方法を変更する」で紹介されているように、DataGridColumnStyleのAlignmentプロパティを変更する方法では、ヘッダとデータの両方のテキストの配置が変更されてしまいます。

.NET Frameworkにはこの問題を解決する方法が用意されていません。ですので、普通の方法では、今のところ、どうしようもありません。(.NET Framework 1.1現在。)

何か方法がないものかと考えたところ、発想を逆転させ、ヘッダの配置を変えるのではなく、逆にデータの配置を変えるという方法を思いつきました。セルの表示方法は、DataGridColumnStyleのPaintメソッドをオーバーライドすることにより変更することができますので、Alignmentプロパティには列ヘッダの配置を指定し、Paintメソッドでセル内の文字列をAlignmentプロパティとは別の配置方法で描画するということができます。

この考え方にしたがって、セル内の文字列の配置方法を変更できるDataGridColumnStyleの派生クラスを作成すると、例えば次のようになります。

注意:VB.NETのコードでは、PropertyDescriptorを無視しています。これは、この部分のC#のコードを完全にVB.NETに変換する方法が分からないためです(分かる方がいらっしゃれば、ご報告ください)。もしVB.NETを使っており、PropertyDescriptorが必要ならば、C#のコードをDLLとしてビルドし、それを参照してお使いください。
VB.NET
コードを隠すコードを選択
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Data
Imports System.ComponentModel

Namespace Dobon.Samples.Forms
    ''' <summary>
    ''' セルのテキスト配置を列ヘッダと別に設定できる
    ''' DataGridTextBoxColumnクラス
    ''' </summary>
    Public Class DataGridTextAlignColumn
        Inherits DataGridTextBoxColumn
        'テキストをセルに描画する際のマージン
        'これがないと、描画位置が上になりすぎる
        Private _margin As New Point(1, 2)

        Private _textAlign As HorizontalAlignment = _
            HorizontalAlignment.Left
        ''' <summary>
        ''' セルのテキスト配置方法
        ''' </summary>
        Public Property TextAlign() As HorizontalAlignment
            Get
                Return _textAlign
            End Get
            Set(ByVal Value As HorizontalAlignment)
                _textAlign = Value
            End Set
        End Property

        Protected Overloads Overrides Sub Edit( _
                ByVal [source] As CurrencyManager, _
                ByVal rowNum As Integer, _
                ByVal bounds As Rectangle, _
                ByVal [readOnly] As Boolean, _
                ByVal instantText As String, _
                ByVal cellIsVisible As Boolean)
            MyBase.Edit([source], rowNum, bounds, [readOnly], _
                instantText, cellIsVisible)
            'TextBoxのテキスト配置を変更する
            Me.TextBox.TextAlign = TextAlign
        End Sub

        Protected Overloads Overrides Sub Paint( _
                ByVal g As Graphics, _
                ByVal bounds As Rectangle, _
                ByVal [source] As CurrencyManager, _
                ByVal rowNum As Integer, _
                ByVal backBrush As Brush, _
                ByVal foreBrush As Brush, _
                ByVal alignToRight As Boolean)
            Dim [text] As String = _
                GetText(GetColumnValueAtRow([source], rowNum))

            Dim sf As New StringFormat
            '配置方法により、描画方法を変更する
            Select Case TextAlign
                Case HorizontalAlignment.Left
                    sf.Alignment = StringAlignment.Near
                Case HorizontalAlignment.Center
                    sf.Alignment = StringAlignment.Center
                Case HorizontalAlignment.Right
                    sf.Alignment = StringAlignment.Far
            End Select

            sf.FormatFlags = StringFormatFlags.NoWrap
            If alignToRight Then
                sf.FormatFlags = sf.FormatFlags Or _
                    StringFormatFlags.DirectionRightToLeft
            End If

            '背景を塗りつぶす
            g.FillRectangle(backBrush, bounds)

            Dim rectf As New RectangleF( _
                bounds.X, bounds.Y, bounds.Width, bounds.Height)
            rectf.Inflate(-_margin.X, -_margin.Y)

            '文字列を描画する
            g.DrawString([text], _
                DataGridTableStyle.DataGrid.Font, _
                foreBrush, rectf, sf)

            sf.Dispose()
        End Sub

        '表示する文字列を返す
        'DataGridTextBoxColumnのGetTextがprivateのため
        Private Function GetText(ByVal val As Object) As String
            If TypeOf val Is DBNull Then '
                Return NullText
            End If

            If Not (Format Is Nothing) AndAlso Format.Length <> 0 _
                    AndAlso TypeOf val Is IFormattable Then
                Try
                    Return CType(val, _
                        IFormattable).ToString(Format, FormatInfo)
                Catch
                End Try
            End If

            If Not (val Is Nothing) Then
                Return val.ToString()
            Else
                Return ""
            End If
        End Function
    End Class
End Namespace
C#
コードを隠すコードを選択
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Data;
using System.ComponentModel;

namespace Dobon.Samples.Forms
{
    /// <summary>
    /// セルのテキスト配置を列ヘッダと別に設定できる
    /// DataGridTextBoxColumnクラス
    /// </summary>
    public class DataGridTextAlignColumn : DataGridTextBoxColumn
    {
        //テキストをセルに描画する際のマージン
        //これがないと、描画位置が上になりすぎる
        Point _margin = new Point(1, 2);

        //TypeConverterを取得しておく
        //DataGridTextBoxColumnのtypeConverterがprivateのため
        private TypeConverter _typeConverter = null; 
        public override PropertyDescriptor PropertyDescriptor
        {
            set
            {
                base.PropertyDescriptor = value;
                if (PropertyDescriptor != null &&
                    PropertyDescriptor.PropertyType != typeof(object))
                {
                    _typeConverter =
                        System.ComponentModel.TypeDescriptor.GetConverter(
                        PropertyDescriptor.PropertyType);
                }
            }
        }

        HorizontalAlignment _textAlign = HorizontalAlignment.Left;
        /// <summary>
        /// セルのテキスト配置方法
        /// </summary>
        public HorizontalAlignment TextAlign
        {
            get
            {
                return _textAlign;
            }
            set
            {
                _textAlign = value;
            }
        }

        protected override void Edit(
            CurrencyManager source,
            int rowNum,
            Rectangle bounds,
            bool readOnly,
            string instantText,
            bool cellIsVisible)
        {
            base.Edit(source, rowNum, bounds, readOnly,
                instantText, cellIsVisible);
            //TextBoxのテキスト配置を変更する
            this.TextBox.TextAlign = TextAlign;
        }

        protected override void Paint(
            Graphics g,
            Rectangle bounds,
            CurrencyManager source,
            int rowNum,
            Brush backBrush,
            Brush foreBrush,
            bool alignToRight)
        {
            string text =
                GetText(GetColumnValueAtRow(source, rowNum));

            StringFormat sf = new StringFormat();
            //配置方法により、描画方法を変更する
            switch (TextAlign)
            {
                case HorizontalAlignment.Left:
                    sf.Alignment = StringAlignment.Near;
                    break;
                case HorizontalAlignment.Center:
                    sf.Alignment = StringAlignment.Center;
                    break;
                case HorizontalAlignment.Right:
                    sf.Alignment = StringAlignment.Far;
                    break;
            }

            sf.FormatFlags = StringFormatFlags.NoWrap;
            if (alignToRight)
                sf.FormatFlags |=
                    StringFormatFlags.DirectionRightToLeft;

            //背景を塗りつぶす
            g.FillRectangle(backBrush, bounds);

            RectangleF rectf = new RectangleF(
                bounds.X, bounds.Y, bounds.Width, bounds.Height);
            rectf.Inflate(-_margin.X, -_margin.Y);

            //文字列を描画する
            g.DrawString(text, this.DataGridTableStyle.DataGrid.Font,
                foreBrush, rectf, sf);

            sf.Dispose();
        }

        //表示する文字列を返す
        //DataGridTextBoxColumnのGetTextがprivateのため
        private string GetText(object val)
        {
            if ((val as DBNull) != null)
                return NullText;

            if (Format != null && Format.Length != 0 &&
                val as IFormattable != null)
            {
                try
                {
                    return ((IFormattable) val).ToString(
                        Format, FormatInfo);
                }
                catch
                {
                }
            }

            if (_typeConverter != null &&
                _typeConverter.CanConvertTo(typeof(string)))
            {
                return (string) _typeConverter.ConvertTo(
                    val, typeof(string)); 
            }

            return (val != null ? val.ToString() : "");
        }
    }
}

このDataGridTextBoxColumnクラスを使用するには、使用したい列の列スタイルにDataGridTextBoxColumnオブジェクトを設定し、DataGridTextBoxColumnのAlignmentプロパティに列ヘッダテキストの配置を指定し、TextAlignプロパティにセル内の文字列の配置を指定します。列スタイルを設定する詳しい方法は、こちらをご覧ください。

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

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