Adsense_top

2010年2月4日木曜日

C# DataGridViewTextBoxColumのMultiline入力枠を大きく

メール受信の方は、今回お休みして、DataGridViewTextBoxColumのMultiline入力用に改善してみました。

DataGridViewTextBoxColumnでは、WrapModeプロパティを設定する事により、複数行入力が可能になります。
また、AutoSizeRowModeを設定する事により、行(セル)の高さも調整されます。
ただ、入力時に表示される編集コントロールの高さは、編集コントロールが表示された、時点の行の高さであり、特に新規行など文字列1行分しか見えなくて入力に不便を感じる場合があります。

そこで、DataGridViewTextBoxColumを少しだけ改造してみました。
表示される編集コントロール(TextBox)の高さを設定できるように拡張してみました。
Visual StudioのデザイナでのTextBoxコントロールの Textプロパティの内容の入力時に表示される MultilineStringEditor ようにしようかとも思いましたが、結構大変そうなので簡単に出来る高さを広げるのみとしました。
そのため、DataGridViewのクライアント領域を超えて表示しない物になってしまいました。

クラスの構成は以下の通りです。
DataGridViewTextBoxColumn の派生クラスとして、DataGridViewTextBoxColumnEx。
DataGridViewTextBoxCell の派生クラスとして、DataGridViewTextBoxCellEx。
DataGridViewTextBoxEditingControlはそのまま使用します。
「Ex」と付けるほどの拡張はしていませんが、とりあえず以上のように命名しています。
まずは、DataGridViewTextBoxColumnExクラスから

public class DataGridViewTextBoxColumnEx
{
private int editingPanelHeight=65;

public DataGridViewTextBoxColumnEx() : base()
{
this.CellTemplate = new DataGridViewTextBoxCellEx();
}
// 今回の中心になる、TextBoxの高さを取得または設定するプロパティです。
[Category("配置")]
[Browsable(true)]
[DefaultValue(65)]
[Description("WrapMode プロパティが true の場合に表示される"
+ "編集コントロールの高さを指定します。")]
public int EditingPanelHeight
{
get
{
DataGridViewTextBoxCellEx cell =
(DataGridViewTextBoxCellEx)this.CellTemplate;
return cell.EditingPanelHeight;
}
set
{
if (this.editingPanelHeight == value)
return;
if(this.DataGridView != null)
{

if( value < this.DataGridView.RowTemplate.Height)
return;
}
else
{
if(value < 21)
return;
}

//CellTemplateの値を変更する
DataGridViewTextBoxCellEx cell =
(DataGridViewTextBoxCellEx)this.CellTemplate;
cell.EditingPanelHeight = value;
if (this.DataGridView == null)
return;
// 既に登録済みのセルの値を更新
int rowCount = this.DataGridView.RowCount;
for (int i = 0; i < rowCount; i++)
{
DataGridViewRow r = this.DataGridView.Rows.SharedRow(i);
DataGridViewTextBoxCellEx rCcell =
(DataGridViewTextBoxCellEx)r.Cells[this.Index];
rCell.EditingPanelHeight = value;
}
}
}

// EditingPanelHeight プロパティを追加しているので、
// Cloneメソッドをオーバーライド
public override object Clone()
{
DataGridViewTextBoxColumnEx col =
(DataGridViewTextBoxColumnEx)base.Clone();
col.editingPanelHeight = this.editingPanelHeight;
return col;
}
// CellTemplateをオーバーライド
public override DataGridViewCell CellTemplate
{
get { return base.CellTemplate; }
set
{
if (value != null &&
!value.GetType().IsAssignableFrom(
typeof(DataGridViewTextBoxCellEx)))
{
throw new InvalidCastException(
"Need DataGridViewTextBoxCellEx object");
}
base.CellTemplate = value;
}
}
}

大した事はしていませんが、大きく以下のような事を行っています。
コードを後述する DataGridViewTextBoxCellEx を CellTemplateに登録しています。
デザイナ用に属性を付けた形で EditingPanelHeight プロパティを追加し、それに伴い Clone() メソッドをオーバーライドしています。

次は、DataGridViewTextBoxCellEx です。
実際に 編集用のTextBox の高さの変更はこのクラスで行っています。

public class DataGridViewTextBoxCellEx
{
private int editingPanelHeight=65;
// Cloneメソッドをオーバーライド
public override object Clone()
{
DataGridViewTextBoxCellEx cell =
(DataGridViewTextBoxCellEx)base.Clone();
cell.EditingPanelHeight = this.EditingPanelHeight;
return cell;
}
// TextBoxの高さを取得または設定するプロパティです。
public int EditingPanelHeight
{
get { return editingPanelHeight; }
set { editingPanelHeight = value; }
}
// ホストされる編集コントロールの初期化部をオーバーライドします。
public override void InitializeEditingControl(
int rowIndex,
object initialFormattedValue,
DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(
rowIndex, initialFormattedValue, dataGridViewCellStyle);
if (dataGridViewCellStyle.WrapMode ==
DataGridViewTriState.True)
{
// 境界線をセット
this.DataGridView.EditingPanel.BorderStyle =
BorderStyle.FixedSingle;
DataGridViewTextBoxEditingControl ctl =
DataGridView.EditingControl as
DataGridViewTextBoxEditingControl;
// スクロールバーをセット
ctl.ScrollBars = ScrollBars.Vertical;
}
}
// 編集パネルの位置とサイズを設定部をオーバーライドします。
public override Rectangle PositionEditingPanel(
Rectangle cellBounds,
Rectangle cellClip,
DataGridViewCellStyle cellStyle,
bool singleVerticalBorderAdded,
bool singleHorizontalBorderAdded,
bool isFirstDisplayedColumn,
bool isFirstDisplayedRow)
{
// 複数行である場合
if (cellStyle.WrapMode  == DataGridViewTriState.True)
{
Rectangle rect = cellBounds;
rect.Height = editingPanelHeight;
// 編集パネルの高さを広げた結果、
// DataGridViewのクライアント領域の下部よりはみ出さないか確認
if(rect.Bottom> this.DataGridView.ClientRectangle.Bottom)
{
下部にはみ出す場合はセルの上側に表示する。
rect.Y =
rect.Top - editingPanelHeight + cellBounds.Height;
//  DataGridViewのクライアント領域の上部よりはみ出さないか確認
if (rect.Top < 0)
{
// 上側表示の結果上部にはみ出す場合は上部ギリギリに調節
rect.Y = 0;
}
cellClip= cellBounds;
}

// セルにおけるセルの内容の場所を左上にします。
// 入力開始位置がこれによりパネルの左上からになります
cellStyle.Alignment =
DataGridViewContentAlignment.TopLeft;
cellClip = cellBounds = rect;
}
return base.PositionEditingPanel(
cellBounds,
cellClip,
cellStyle,
singleVerticalBorderAdded,
singleHorizontalBorderAdded,
isFirstDisplayedColumn,
isFirstDisplayedRow);
}
}

このクラスの中で編集コントロール(TextBox)の高さの変更と、境界線・スクロールバーを設定しています。
WrapMode が true 以外の場合は EditingPanelHeight プロパティを設定しても、通常の表示がおこなわれます。


実際に DataGridView の「列の編集」から、「DataGridViewTextBoxColumnEx」を列に追加し、入力を行うと以下の図のようになります。


最初に書いた、DataGridViewのクライアント領域を超えて表示できない件は、編集パネル部の高さを、クライアント領域より高くしなければ、どうにか使えると思うのですが...、いわゆる運用の方で....。




0 件のコメント:

コメントを投稿