注意:ここで紹介している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としてビルドし、それを参照してお使いください。
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
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プログラミング研究 第29号」で紹介したものです。)