2012年5月3日木曜日

wpf : TabItemのヘッダにClickイベントを登録

前の投稿の続きです。 前の投稿では「TabItemのヘッダで使えるマウスイベントはPreviewが付くトンネルイベントだけ」ということを書きました。 それだけ使えれば十分だとは思いますが、今回はなぜか、TabItemのヘッダにClickイベントを登録する方法を試してみました。

やり方は簡単で、TabItemのTemplateにButtonを登録するだけです。 ヘッダーに関するTemplateはTabItem.Template(ControlTemplate)とTabItem.HeaderTemplate(DataTemplate)の2種類あります。 TabItem.Templateの方には枠線などタブの外観を設定します。 TabItem.HeaderTemplateは、DataTemplate型とあるとおり、関連付けられたデータのGUI表現を設定します。 例えば「アイコンとテキストで表現するデータ」があった場合、それをどういう構成にするかの設定がDataTemplateです。 まず、タブの外観がTabItem.Templateを元に作られ、その中にHeaderTemplateを元に作ったデータが収められます。 わざわざ2つに分かれているのは、DataTemplateをメニューやリストボックスなど様々なコントロールで共有できるようにするためでしょう。

ここまでの内容で「なんかHeaderTemplateは関係なさそうだなぁ」ってのがわかります。 枠をクリックしたときにイベントが発行されないと不自然になりますからね。

試しに次のスタイルをTabControlのItemContainerStyleに設定してDataTemplateの範囲を赤く表示させてみたら、

<Style x:Key="style2" TargetType="TabItem">
    <Setter Property="HeaderTemplate">
        <Setter.Value>
            <DataTemplate>
                <TextBlock
                        Text="{Binding}"
                        Background="Red"
                />
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

こうなりました。

TabItem.Headerの赤い部分がHeaderTemplate、そのまわりの枠がTabItem.Templateです。 けっこう枠が大きいのが分かります。 やはり枠をクリックしたときにイベントが発行されないのはマズそうですね。

というわけでTabItem.Templateを書き換えることにします。 次のスタイルをTabControlのItemContainerStyleに設定。

<ControlTemplate x:Key="templateTabItemButton5" TargetType="Button">
    <Border
            BorderThickness="1"
            BorderBrush="Gray"
            Padding="2"
    >
        <ContentPresenter/>
    </Border>
</ControlTemplate>
<Style x:Key="style5" TargetType="TabItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="TabItem">
                <Button
                        Content="{
                                Binding Path=Header,
                                RelativeSource={
                                        RelativeSource TemplatedParent
                                }
                        }"
                        Template="{StaticResource templateTabItemButton5}"
                        Click="クリックイベントハンドラ"
                />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

styleの番号は飛んでますが、色々やった結果なので気にしないでください。

ポイントはTabItem.Templateの直下にButtonを書くことです。 Button.Templateを書き換えればボタンのデフォルトの見た目を一切表示せずにClickイベントだけ活用できます。 Button.TemplateにはContentPresenterを置きましょう。 直接TextBlockなどを書くとTabItem.HeaderTemplateが無視されてしまいます。

で、実際に↑のスタイルを使うとこうなります。

寂しいですね。

Templateをいじるときは全部自前でデザインしなければなりません。 もともとそういうつもりなら、ClickイベントのためにButtonを組み込むのはほんのひと手間ですね。 そうでないなら、前の投稿で書いたとおりPreviewイベントだけで何とかした方が建設的っぽいです。

ここまで書いてなんですが、結局、自分が作るツールではこのネタは使わなそうな気がします。 なんか、無駄なことに労力を割いたような気もするけど、2つのTemplateの使い分けがわかったからいいかな...?