(XAML#13)「ComboBox と MaxLength」
Windows フォームの ComboBox は、デフォルトで DropDownStyle プロパティが DropDown になっており、Items プロパティに設定されている文字列を選んだり、自由にテキストを入力できます。一方、WPF の ComboBox は Windows フォームの場合の DropDownList スタイルであり、デフォルトではテキストを編集できません。もともと、ComboBox の選択肢として使われる Items はテキストだけでなく、ComboBoxItem 型をはじめ、さまざまなオブジェクトを使えます。
もちろん、Windows フォームのようにテキストの選択肢から選んだり、ユーザーが入力できるようにしたいこともあります。このときには IsEditable プロパティを True に設定するだけです。入力されたテキストは Text プロパティで確認できますし、入力されたテキストが Items に設定された選択肢に該当していれば、SelectedIndex が 0 以上になります(該当しない場合は -1)。
しかし、IsEditable を True にして編集可能にした場合でも、Windows フォーム版 ComboBox の MaxLength プロパティに相当する「入力文字数を制限するプロパティ」がありません。実は、これを設定するのは少しだけ手間がかかります。
ComboBox をはじめ、ほとんどの WPF のコントロールはコントロールテンプレートという“枠組み”を持っています。この枠組みは Template というプロパティで保持されています。Template プロパティに自作のコントロールテンプレート(ControlTemplate オブジェクトに、自分の好きなものを配置したもの)を割り当てると、デフォルトとは異なる独自のスタイルのコントロールを使えるようになります。
ComboBox のテンプレートの例は、MSDN の「ComboBox のスタイルとテンプレート」にあります(実際に使われているものと同一ではありません)。このページの冒頭にある「ComboBox のパーツ」として挙げられている PART_EditableTextBox がテキスト入力に使われる TextBox コントロールです(PART_Popup はドロップダウンを表示するための Popup コントロール)。この TextBox コントロールの MaxLength プロパティを設定すれば、ComboBox でも文字数を制限できます。
ComboBox の Loaded イベントで、テンプレートから「PART_EditableTextBox」を探して MaxLegnth プロパティを設定する例を以下に示します。
[XAML]
<ComboBox IsEditable="True" Loaded="ComboBox_Loaded">
<ComboBoxItem Content="One"/>
<ComboBoxItem Content="Two"/>
<ComboBoxItem Content="Three"/>
</ComboBox>
[コード]
private void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
var cbox = sender as ComboBox;
if (cbox != null && cbox.Tag != null)
{
var tbox = cbox.Template.FindName("PART_EditableTextBox", cbox) as TextBox;
int len;
if (tbox != null)
tbox.MaxLength = 10;
}
}
このようにプログラムすると、制限したい文字数が異なるものについて個別にイベントハンドラーを定義しなければなりません。ComboBox の Tag プロパティを使って制限文字数を判別でき、スタイルを使って(多少)適用しやすくした例を次に示します。
[XAML]
<Window.Resources>
<Style x:Key="ComboBoxMaxLengthStyle" TargetType="{x:Type ComboBox}">
<EventSetter Event="Loaded" Handler="ComboBox_Loaded" />
</Style>
</Window.Resources>
<StackPanel>
<ComboBox x:Name="cbox1" IsEditable="True" Style="{StaticResource ComboBoxMaxLengthStyle}" Tag="10">
<ComboBoxItem Content="one"/>
<ComboBoxItem Content="two"/>
<ComboBoxItem Content="three"/>
</ComboBox>
</StackPanel>
[コード]
private void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
var cbox = sender as ComboBox;
if (cbox != null && cbox.Tag != null)
{
var tbox = cbox.Template.FindName("PART_EditableTextBox", cbox) as TextBox;
int len;
if (tbox != null && int.TryParse(cbox.Tag.ToString(), out len))
tbox.MaxLength = len;
}
}