はじめに
本文書は筆者がWPFで開発する中でGridのIsMouseOverを使おうとしたときの困りごとについてまとめます。
困りごとの例
Gridに3つボタンを並べて、1つのボタンはGridにマウスオーバーされたときに表示するようにしたい状況を考えます。
そのために、WPFプロジェクトをVisualStudioで作ると生成されるMainWindow.xamlを以下のように編集しました。
<Window x:Class="MouseOverSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="DisplayedOnMouseOverButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type Grid}}, Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- 以下2つのボタンは常に表示される -->
<Button Grid.Column="0"
Height="20" Width="40"
Content="ボタン1"/>
<Button Grid.Column="1"
Height="20" Width="40"
Content="ボタン2"/>
<!-- 以下のボタンはグリッドがマウスオーバーされたときのみ表示する -->
<Button Grid.Column="2"
Height="20" Width="40"
Style="{StaticResource DisplayedOnMouseOverButtonStyle}"
Content="ボタン3"/>
</Grid>
</Window>
GridのColumnを3つに分けて、それぞれのColumnにボタンを1つずつ配置しています。
ただ、3つ目のボタンだけはスタイルを指定しています。指定しているスタイルは、ボタンが配置されているGridのIsMouseOverがTrueの時のみ表示されるといったものです。以下がスタイルの部分です。
<Style x:Key="DisplayedOnMouseOverButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type Grid}}, Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
上記のMainWindow.xamlをビルドして、実行してみると以下のような極めて簡素なUIができます。
そして、肝心の3つ目のボタンですが、想定通りに動作しません。
具体的には、以下のように[ボタン1]と[ボタン2]にマウスオーバーした時には表示されますが、そのほかの何もコントロールが配置されていない部分のGrid領域にマウスオーバーしても表示されないです。
困りごとの解決法
解決法としてはGridに任意の背景色を設定してあげることです。
そうすることでGrid内でコントロールが配置されていない空の領域にマウスオーバーした際にもIsMouseOverがTrueを返すようになり、想定通りに動作するようになります。
前章で記載したMainWindow.xamlにおいては、以下のようにGridに対して、背景色を設定します。なお、見た目を変えないようにTransparent(透明)を設定しています。
<Window x:Class="MouseOverSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
...
</Window.Resources>
<!-- Gridに背景色を設定 -->
<Grid Background="Transparent">
...
</Grid>
</Window>
上記の変更で想定通りに動作するようになります。
以下が動作イメージです。
まとめ
筆者が困ったGridのIsMouseOverを使うときの注意点をまとめました。
なお、Grid以外にもStackPanelやWrapPanelであっても同じように背景色を設定してあげないと想定外の動作をするので、覚えておきたいですね。