DataGridTextColumnを更に拡張する。

DataGridTextColumnで右詰めにしたい時が多々ある。で拡張したDataGridTextColumnを更に拡張する。
拡張1:最大文字数を設定できるようにする。
→MaxLengthという添付プロパティを実装する。

/// <summary>
/// 入力可能な最大文字数を取得/設定します。
/// </summary>
public int MaxLength {
get {return (int)GetValue(MaxLengthProperty);}
set {SetValue(MaxLengthProperty, value);}
}

/// <summary>入力可能な最大文字数</summary>
public static readonly DependencyProperty MaxLengthProperty =
DependencyProperty.Register("MaxLength", typeof(int),
typeof(DataGridTextExColumn), new UIPropertyMetadata(0));
上記記事内のGenerateEditingElementメソッド内で、このMaxLengthを設定する。

/// <summary>
/// 列の Binding プロパティ値にバインドされた TextBox コントロールを取得します。
/// </summary>
/// <remarks>
/// 値が入る前なので、ここで値の編集とかはできない。
/// </remarks>
/// <param name="cell">生成された要素を格納するセル。</param>
/// <param name="dataItem">目的のセルを格納している行によって表されるデータ項目。</param>
/// <returns>列の Binding プロパティ値にバインドされた新しい TextBox コントロール</returns>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) {
var textBox = (TextBox)base.GenerateEditingElement(cell, dataItem);

//文字寄せを指定します。
textBox.TextAlignment = this.GetTextAlignment();
textBox.VerticalAlignment = this.VerticalAlignment;
textBox.MaxLength = this.MaxLength;
return textBox;
}


拡張2:改行コードを入力できるようにする。
通常は、エンターキー押下でセル編集が確定してしまうので、させないようにする必要がある。
まずは、添付プロパティ実装

/// <summary>
/// 複数行入力を可能にするかどうかを取得/設定します。
/// </summary>
public bool MultiLine {
get {return (bool)GetValue(MultiLineProperty);}
set {SetValue(MultiLineProperty, value);}
}

/// <summary>複数行入力?</summary>
public static readonly DependencyProperty MultiLineProperty =
DependencyProperty.Register("MultiLine", typeof(bool),
typeof(DataGridTextExColumn), new UIPropertyMetadata(false));

次に、GenerateEditingElementメソッドの実装を変更する。

/// <summary>
/// 列の Binding プロパティ値にバインドされた TextBox コントロールを取得します。
/// </summary>
/// <remarks>
/// 値が入る前なので、ここで値の編集とかはできない。
/// </remarks>
/// <param name="cell">生成された要素を格納するセル。</param>
/// <param name="dataItem">目的のセルを格納している行によって表されるデータ項目。</param>
/// <returns>列の Binding プロパティ値にバインドされた新しい TextBox コントロール</returns>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) {
var textBox = (TextBox)base.GenerateEditingElement(cell, dataItem);

//文字寄せを指定します。
textBox.TextAlignment = this.GetTextAlignment();
textBox.VerticalAlignment = this.VerticalAlignment;
textBox.MaxLength = this.MaxLength;

if (this.MultiLine) {
textBox.AcceptsReturn = false;
textBox.PreviewKeyDown += new KeyEventHandler(TextBox_PreviewKeyDown);
textBox.Unloaded += new RoutedEventHandler(TextBox_Unloaded);

//エンターキー押下によるフォーカス移動から除外
FocusMoveBehavior.SetExcluded(textBox, true);
}

return textBox;
}
PreviewKeyDown(キーダウン直前イベント)実装が重要かな

/// <summary>
/// 編集用TextBox キーダウン前イベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e) {

if (Keyboard.IsKeyDown(Key.Enter) || Keyboard.IsKeyDown(Key.Return)) {
var val = ModifierKeys.Alt & e.KeyboardDevice.Modifiers;

if (val > 0) {
//①Alt+Enterで改行を挿入しましょう。
var textBox = sender as TextBox;
var caret = textBox.CaretIndex;
textBox.Text = textBox.Text.Insert(caret, Environment.NewLine);
textBox.CaretIndex = caret + 1;

//②行の高さを調整しましょう。
var cellsPresenter = textBox.FindAncestor<DataGridCellsPresenter>();

if (cellsPresenter != null) {
//改行コードの数をカウントします。
var lineCnt = Utils.GetMatchStringCount(
textBox.Text, Environment.NewLine) + 1;

//標準で設定されている行の高さを取得します。
//DataGridRowに対する高さ(Height)が未設定の場合のみ、
//DataGridのRowHeightプロパティを取得します。
var dataGridRow = cellsPresenter.FindAncestor<DataGridRow>();
var height = dataGridRow.Height;

if (double.IsNaN(height)) {
var ownerDataGrid = dataGridRow.FindAncestor<DataGrid>();
height = ownerDataGrid.RowHeight;

if (double.IsNaN(height)) {
height = 22D;//みつからなければ、強制的に22で
}
}

cellsPresenter.Height = (double)(lineCnt * height);
}

e.Handled = true;//これにて処理は終了
}
}

return;
}

①で、Alt+Enter押下で改行コードを現在のカレット位置に挿入する
②で、行の高さを調整している。態々DataGridCellsPresenterというクラスを検索して、そいつに高さを設定しているのは、そうしないと期待どおりにならないから。
 高さの基準をDataGridRow→DataGridの順に探している。
Unloadedイベント時の処理は後始末。

/// <summary>
/// 編集用TextBoxアンロードイベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void TextBox_Unloaded(object sender, RoutedEventArgs e) {
var textBox = sender as TextBox;

textBox.PreviewKeyDown -= new KeyEventHandler(TextBox_PreviewKeyDown);
textBox.Unloaded -= new RoutedEventHandler(TextBox_Unloaded);
BindingOperations.ClearBinding(textBox,
FocusMoveBehavior.ExcludedProperty);

return;
}

GetMatchStringCountメソッドは、特定文字列の数を検索するユーティリティなメソッド。

/// <summary>
/// 指定された文字列から、指定の文字列が何文字含まれているかを返します。<br/>
/// </summary>
/// <remarks>
/// 指定された文字列内に、指定の文字列が何文字含まれているかを返します。<br/>
/// 大文字小文字を区別するかどうかは、引数で指定できます。<br/>
/// 文字列の検索は、正規表現で実装されています。<br/>
/// </remarks>
/// <param name="source">文字列</param>
/// <param name="search">指定の文字列</param>
/// <param name="ignoreCase">true:大文字小文字を無視して検索します。</param>
/// <returns>文字数</returns>
public static int GetMatchStringCount(string source, string search, bool ignoreCase = false) {
string resultString = string.Empty;

//using System.Text.RegularExpressions;が必要。
Regex reg = null;

if (ignoreCase) {
reg = new Regex(search, RegexOptions.IgnoreCase);
} else {
reg = new Regex(search);
}

var m = reg.Match(source);
var counter = TawamureClosure.CountUp();

while (m.Success) {
counter();
m = m.NextMatch();
}

return counter();
}

実際に動作させるとこんな感じ。
20120812_1
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m