オルタナティブ・ブログ > IT's my business >

IT業界のコメントマニアが始めるブログ。いつまで続くのか?

(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;
    }
}

Xaml13

Comment(0)