以下のようなRowの中にボタンが表示されているようなものを想像してください。
特定の条件の時だけボタンを表示する機能を考えます。
<Grid>
<DataGrid ItemsSource="{Binding UserList}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Age" Binding="{Binding Age}" Width="40"/>
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="ボタン" Width="50"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
簡単なように見えてStyleを書く場所によって挙動が違うので注意が必要です。
ざっくり3ヶ所ほど書く場所があります。
<Grid>
<DataGrid ItemsSource="{Binding UserList}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Age" Binding="{Binding Age}" Width="40"/>
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="ボタン" Width="50"/>
//ボタンのスタイルに書く
<Button.Style />
</DataTemplate>
//データテンプレートに書く
<DataTemplate.Triggers />
</DataGridTemplateColumn.CellTemplate>
//セルスタイルに書く
<DataGridTemplateColumn.CellStyle />
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
CellStyleに書く
私はセルの中身を消したいのだからCellStyleでVisibility=”Hidden”にすればいいと思いました。
実際にやってみるとこうなりました。
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="ボタン" Width="50" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding Visibility}" Value="Hidden" >
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
カラムの形跡はありますが、選択行として認識されていないです。
さらにカラのボタンカラム上ではクリックしてもRowの選択ができません。
CellStyleのVisibilityをHiddenにすると、Rowから見てセルは無いものとみなされるようです。
DataTemplate.Triggerに書く
ということでCellStyleはVisibilityを設定するとRowの構造に影響を与えるのでダメでした。
では一段下げてDataTemplateにStyleを付けたらどうでしょうか。
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="ボタン" Width="50" Visibility="Visible" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Visibility}" Value="Hidden" >
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
無事に通りましたね。
セルはきちんと存在していて、ボタンだけ非表示になりました。
しかし、この方法も問題があります。
それは表示中のものをHiddenに変えることはできても、もともと非表示の中身をVisibleに変えられないのです。
上のやり方だと、DataTemplateのVisibilityを弄っているので中身のButtonのVisibilityがHiddenだと、HiddenのボタンをVisibleにしてしまいます。
伝えにくいのですが、Setter Property=”Visibility” Value=”Hidden” と書いただけでは、DataTemplateの中身が見えるようになるのであって、決してButton visibility=”Visible”にしているわけではありません。
なので上記のやり方でButton visibility=”Visible”にしようとすると
<Button Name="ButtonName" Content="ボタン" Width="50" Visibility="Hidden" />
<Setter TargetName="ButtonName" Property="Visibility" Value="Visible" />
とターゲットを明示しなければなりません。
セル内の要素が1つであればよいのですが、複数あると手間が増えますね。
それに私はNameつけるのをなるべく避けたいのです。いちいち覚えてられないし、名前が被った時に面倒だからです。
他にもTriggerでVisibleにするという発想を転換して、TriggerでHiddenにする発想で組み立てても解決します。この辺りは条件次第ですね。
Button.Styleに書く
結局落ち着くところに落ち着いたんですが、セルやDataTemplateに書くとセル内の他の要素に影響するので、シンプルにButton.Styleに書くのがよいです。
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="ボタン" Width="50" >
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding Visibility}" Value="Hidden" >
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
なおButtonのVisibilityを先に規定したい場合、下記のようにはしないでください。
<Button Content="ボタン" Width="50" Visibility="Visible" >
xaml的には上位に書かれている条件の方が強いため、Button.styleでVisibilityを変更しているように思えても、実際にはVisibility=”Visible” が常に有効となり変更できなくなります。
もし書くのであれば下記のように行ってください。
<Button Content="ボタン" Width="50" >
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Visibility}" Value="Hidden" >
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Tips 選択中の時だけ表示したい
Rowを選択中にだけ表示したい場合がよくあります。
これも少し応用してやるだけで簡単に実現できます。
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType=DataGridRow}}" Value="True" >
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
DataGridにはIsSelectedプロパティが最初から存在しているので利用します。
単純にBinding Path=IsSelectedとしても認識されないので、RelativeSourceでDataGridRowまで遡ればIsSelectedプロパティを利用できます。
コメント