数日前のえムナウさんのエントリ「TextBoxを自分で描画する」を読みました。
TextBoxに入力もしくはデータバインドしたデータを、数値や日付データとして
フォーマットして表示するという機能は以前から必要としておりまして、これまでは
Textプロパティをoverrideするという無理やりな方式を採用していました。
できればTextプロパティはそのままで、表示するデータだけを変えるようにしたいと思っていたので
これはいい、と早速試してみたのですが、書いてあるとおりSetStyleやRecreateHandleを記述しても
どうしてもフォーカスがあるときと無いときでフォントの大きさが変わってしまいます。
色々調べた結果、WM_PAINTメッセージを捕まえてCreateGraphicsで作成したGraphicsオブジェクトに
文字列の描画を行う方式に落ち着きそうです。
namespace Umebayashi.Framework.Windows.Forms
{
public partial class UmeTextBox : TextBox
{
public UmeTextBox()
{
InitializeComponent();
}
private const int WM_PAINT = 0x000F;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_PAINT:
//フォーカスがある状態ではフォーマットしない
if (!Focused)
{
DrawText();
}
break;
default:
break;
}
}
private void DrawText()
{
TextFormatFlags tff = TextFormatFlags.VerticalCenter;
switch (this.TextAlign)
{
case HorizontalAlignment.Center:
tff |= TextFormatFlags.HorizontalCenter;
break;
case HorizontalAlignment.Left:
tff |= TextFormatFlags.Left;
break;
case HorizontalAlignment.Right:
tff |= TextFormatFlags.Right;
break;
}
if (this.Multiline)
{
tff |= TextFormatFlags.WordBreak;
}
using (Graphics g = CreateGraphics())
using (Brush backBrush = new SolidBrush(this.BackColor))
{
//BackColorで背景を塗りつぶす。
//これをしないとフォーマット前後の文字列がダブって表示される。
g.FillRectangle(backBrush, this.ClientRectangle);
DateTime dtVal;
decimal dcVal;
if (DateTime.TryParse(this.Text, out dtVal))
{
TextRenderer.DrawText(g, dtVal.ToString("yyyy/MM/dd"),
this.Font, this.ClientRectangle, this.ForeColor, tff);
}
else if (decimal.TryParse(this.Text, out dcVal))
{
TextRenderer.DrawText(g, dcVal.ToString("#,##0"),
this.Font, this.ClientRectangle, this.ForeColor, tff);
}
else
{
TextRenderer.DrawText(g, this.Text,
this.Font, this.ClientRectangle, this.ForeColor, tff);
}
}
}
}
}