概要

WPF の XamComboEditor で、入力文字を英数字(A–Z, 0–9)のみに制限し、小文字は大文字へ正規化したうえで最大 5 文字まで入力できるようにする方法を説明します。

XamComboEditor 単体の機能だけではすべてをカバーできない場合、内部の TextBox に入力制御を一任する構成にするのが有効です(貼り付けにも同じルールを適用できます)。

対象コントロール

  • Infragistics WPF — XamComboEditor

問題

XamComboEditor を編集可能(IsEditable = True)にした場合、既定の状態では入力文字種(英数字のみ等)や文字数(5文字まで等)をコントロール単体のプロパティだけで完結して制御することはできません。

また、貼り付け時にも同様の制限(正規化・上限)を適用したいケースがあります。

解説

XamComboEditor には入力制限に関する設定が一部ありますが、要件(英数字のみ、最大5文字、貼り付け時も同様、など)をすべてプロパティだけで網羅できないことがあります。

その場合は、XamComboEditor の編集欄として利用される WPF 標準の TextBox を取得し、入力制御を TextBox 側へ集約する方法が現実的です。

実現したい要件

  1. 入力可能文字:英大文字 A–Z と数字 0–9 のみ
    • 小文字 a–z は自動的に大文字へ変換して表示
    • 上記以外の文字(スペース、記号、全角など)は入力結果に反映しない(入力時・貼り付け時とも)
  2. 文字数:最大 5 文字まで(超えた分は切り捨て)
  3. 適用範囲:キーボード入力、貼り付け、ドラッグ&ドロップ等の貼り付け相当操作

実装上のポイント

  • XamComboEditor は編集モードに入るまで内部 TextBox が VisualTree 上に存在しない場合があるため、初期化は Loaded ではなく EditModeStarted を起点にします。
  • 取得した TextBox に対して、CharacterCasing / MaxLength / TextChanged / PastingHandler を設定し、入力中・貼り付け時の両方で同じルールを適用します。

サンプルコード

実装の全体像は、次の 3 点です。

  1. 編集モード開始時に、XamComboEditor 内部の TextBox を取得する
  2. 入力中は TextChanged で英数字以外を除去し、大文字へ正規化する
  3. 貼り付け時はペーストイベントでクリップボード文字列を同じルールで加工し、残り文字数に応じて切り詰める

以下は、上記 1〜3 に対応する要点スニペットです。

1. 編集モード開始時に内部 TextBox を取得する(初期化)

XAML(編集モード開始イベントで初期化)

<igEditors:XamComboEditor x:Name="xamComboEditor"
							 IsEditable="True"
							 EditModeStarted="XamComboEditor_EditModeStarted"/>

C#(EditModeStarted で内部 TextBox を取得し、TextBox 側に制御を集約)

private const int MaxLength = 5; // 最大 5 文字
private bool _textBoxInitialized;

private void XamComboEditor_EditModeStarted(object sender, RoutedEventArgs e)
{
	// EditModeStarted は複数回呼ばれるため、初期化は 1 回だけ行う
	if (_textBoxInitialized) return;

	// XamComboEditor 内部の TextBox を VisualTree から取得
	var textBox = FindVisualChild<TextBox>(xamComboEditor);
	if (textBox == null) return;

	// 以降の入力制御は TextBox に寄せる
	textBox.CharacterCasing = CharacterCasing.Upper; // 小文字 → 大文字
	textBox.MaxLength = MaxLength;                   // 最大文字数
	textBox.TextChanged += TextBox_TextChanged;      // 入力中のフィルタ
	DataObject.AddPastingHandler(textBox, TextBox_Pasting); // 貼り付け制御

	_textBoxInitialized = true;
}

2. 入力中の正規化(英数字のみ・英字は大文字化)

private static bool IsAllowedChar(char c)
{
	// 許可するのは半角の英字・数字のみ
	return (c >= 'a' && c <= 'z')
		|| (c >= 'A' && c <= 'Z')
		|| (c >= '0' && c <= '9');
}

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
	var textBox = (TextBox)sender;
	string current = textBox.Text;

	// 英数字以外を除去し、英字は大文字へ正規化
	string filtered = new string(current.Where(IsAllowedChar).ToArray()).ToUpper();

	if (filtered != current)
	{
		// 入力途中の操作感を損ねないよう、キャレット位置は可能な範囲で維持
		int caretIndex = textBox.CaretIndex;
		textBox.Text = filtered;
		textBox.CaretIndex = Math.Min(caretIndex, filtered.Length);
	}
}

3. 貼り付け制御(同じルールを適用し、最大 5 文字に収める)

private void TextBox_Pasting(object sender, DataObjectPastingEventArgs e)
{
	var textBox = (TextBox)sender;

	// クリップボード文字列を取得
	string clipText = e.DataObject.GetData(DataFormats.UnicodeText) as string ?? string.Empty;

	// 貼り付け文字列にも 2. と同じルール(英数字のみ + 大文字化)を適用
	string filtered = new string(clipText.Where(IsAllowedChar).ToArray()).ToUpper();

	if (string.IsNullOrEmpty(filtered))
	{
		// 有効文字が 1 文字もない場合は貼り付けをキャンセル
		e.CancelCommand();
		return;
	}

	// 選択範囲は置換されるため、その分は差し引いて「残り入力可能文字数」を計算
	int remaining = MaxLength - (textBox.Text.Length - textBox.SelectionLength);
	if (remaining <= 0)
	{
		// すでに上限に達している場合は貼り付けをキャンセル
		e.CancelCommand();
		return;
	}

	// 残り文字数に収まるように切り詰めた内容で貼り付けさせる
	string toInsert = filtered.Substring(0, Math.Min(filtered.Length, remaining));
	var newDataObject = new DataObject();
	newDataObject.SetData(DataFormats.UnicodeText, toInsert);
	e.DataObject = newDataObject;
}

まとめ

  • XamComboEditor 単体の機能だけでは複雑な入力制御(英数字のみ、最大5文字、貼り付けにも適用 など)を網羅できない場合があります。
  • その場合は、内部の TextBox を取得し、TextBox 側に入力制御を集約する構成が有効です。
Tagged:

製品について

Ultimate UI for WPF