ListBoxItemのTemplateを変更して選択できる領域を限定する

以前の投稿「ListBoxItemをクリッピングして選択できる領域を限定する」でコメントをいただき、ListBoxItemのTemplateを変更する方法でも実現可能であると教えていただきました。こちらの方法のほうがスマートなやり方だと思いますので、あらためてご紹介したいと思います。


XAML

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    x:Class="ListBoxItemSelectionPoint.ListBoxItemTemplate"
    x:Name="Window"
    Title="ListBoxItemTemplate"
    Width="300" Height="300" FontSize="20">
    <ListBox HorizontalContentAlignment="Center" BorderBrush="#00000000">
        <ListBox.Resources>
            <Style x:Key="ListItemFocusVisual">
              <Setter Property="Control.Template">
                <Setter.Value>
                  <ControlTemplate TargetType="{x:Type Control}">
                    <Ellipse Stroke="Black" StrokeDashArray="1 2"/>
                  </ControlTemplate>
                </Setter.Value>
              </Setter>
            </Style>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Background" Value="#FFBBBBBB"/>
                <Setter Property="Width" Value="250"/>
                <Setter Property="Height" Value="70"/>
                <Setter Property="Margin" Value="10,5,10,5"/>
                <Setter Property="FocusVisualStyle" Value="{DynamicResource ListItemFocusVisual}"/>
                <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Border CornerRadius="500" Background="{TemplateBinding Background}">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Background" Value="{StaticResource {x:Static SystemColors.HighlightBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
                </Setter>
            </Style>
        </ListBox.Resources>
        <System:String>リストアイテム1</System:String>
        <System:String>リストアイテム2</System:String>
        <System:String>リストアイテム3</System:String>
    </ListBox>
</Window>


単純にListBoxItemのTemplateをCornerRadiusを設定したBorderとしただけ(もちろんGridをはさんでEllipseでも構いません)なのですが、1つ注意しなければならないポイントがあります。それは、ContentPresenterなどのほかの要素が円の外側にはみ出た場合、円の外側も選択領域に含まれてしまうということです(実はこのことに気付かなかったため、ControlTemplateを使う方法では実現不可能だと判断していました)。


たとえば、上記のTemplate内のContentPresenterのHorizontalAlignmentとVerticalAlignmentのテンプレートバインディングを削除してみてください。こうすることで、ContentPresenterの位置は既定のTop、LeftになりBorderよりも外側にはみ出すことになります。そうすると、円の外側をクリックしてもアイテムを選択することができてしまうようになります。


なお、Clipプロパティを使用した場合にはフォーカス枠が隠れていましたが、今回の方法の場合フォーカス枠が見えてしまいますのでフォーカス枠も同じ円形に変更しています。