読者です 読者をやめる 読者になる 読者になる

テキストボックスにクリアボタンをつける

Silverlight Advent Calendar 2011 に書こうと思っていたネタですが、手をあげるタイミングを逃したので、この年末に書きます。


さてさて、タイトルの内容ですが、最近は横にバツボタンがついていて、押すとテキストの内容が消えるテキストボックスをよく見かけますよね。Windows 8 や iPhone でよく見かけるあれです。

これを、Silverlight で実現して、 Windows 7 でも Vista でも消せるようにしようって話です。


で、作り方ですが、こういうのってカスタムコントロール作ってテンプレートに TextBox と Button おいて、コードでボタンが押された時に TextBox のテキストを消すように作ってしまいますが、そうすると DataForm を使ってたらめんどくさかったり、結構開発が進んだ後だったら全部置き換えが要ったりとするんで、めんどくさくなります。


ということで、今回は Trigger / Action を使ってテンプレートに仕込む方法を記載します。


通常、テキストボックスのテンプレートは以下のようになっています。長いのでテキスト入力可能になる部分だけ抜き出します。

<Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1">
  
  <ScrollViewer x:Name="ContentElement" BorderThickness="0" 
        IsTabStop="False" Padding="{TemplateBinding Padding}"/>

</Border>


これを以下のように変更します。

<Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1">
    
    <Grid Margin="{TemplateBinding Padding}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="28" />
        </Grid.ColumnDefinitions>
        <ScrollViewer x:Name="ContentElement" BorderThickness="0" 
            Grid.Column="0"
            IsTabStop="False"/>

        <Button Grid.Column="1">

            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:ChangePropertyAction 
                        TargetObject="{Binding RelativeSource={RelativeSource TemplatedParent} }" 
                        PropertyName="Text" Value=""/>
                </i:EventTrigger>
            </i:Interaction.Triggers>

        </Button>

    </Grid>

</Border>

もともとのテキスト入力部分の上に Grid を一枚被して、カラムを 2 つに設定。一つ目にもともとのテキストボックス入力部分をそのままおいて、二つ目にボタンをおきます。そのボタンに EventTrigger を Click に紐づけて、 Action でボタンが置かれているテンプレートの Text プロパティ、つまり自身の TextBox の Text プロパティに空文字を設定しているだけですね。

こうやって、App.xaml に登録しておくと一括で設定できるので便利ですね。まぁ、テンプレートの中に Behavior とか Trigger とかを仕込んで動作を定義するのはいかがなものかとも思わなくもないのですが、まぁ、カスタムコントロールのデフォルトテンプレートとかじゃないんで、ここでは気にしないようにしてます。こんな方法もあるよってことで。