TreeViewItemとかListViewItemとかをDataTemplateに使うのはいくない
前もはまった気がするんだけど今日もはまってしまったのでメモです。
これで起きる不具合
- 思ったようにマウスのフォーカスが合いません
- 当然思ったようにRoutedEventも発火しません
- もちろん思ったようなコマンドが飛びません
そして妥協のコードビハインドが増えます。
くやしい!
じゃあどうするのさ
こうします。
ItemTemplateのかきかた
<TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Items}" DataType="vm:ViewModel"> <ContentPresenter Content="{Binding }"> <!-- <i:Interaction.Triggers>とか使いたければここに書く --> </ContentPresenter> </HierarchicalDataTemplate> </TreeView.ItemTemplate>
ContentPresenterを要素にしておくのがポイントです。Contentを設定しないとスタックオーバーフローで落ちます。
外見の設定
お次はItemContainerStyleを設定します。BasedOnを忘れるとスタイルが適用されずに残念なことになります。
<TreeView.ItemContainerStyle> <Style TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}"> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/> <Setter Property="Header" Value="{Binding Header}"/> </Style> </TreeView.ItemContainerStyle>
こうするとTreeViewItemの選択状態をバインドすることができます。やったね!
で、ContentPresenterって何者だ
ボタンやパネルといったContentを持つことができるコントロールがContentを表示するときに使う概念的なもののようです。私はまだあまりお世話になっていませんが、TemplateBindingという「ここに要素を配置する」という目印を打つようなマークアップ拡張と組み合わせて使うことが多いようです。テンプレートを使ってコントロール摩改造していくときにはお世話になりそうですね。
使用例:連載 WPF/Silverlight UIフレームワーク入門:第4回 “見た目”を決めるコントロール・テンプレート (2/3) - @ITより
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button"> <Border Background="{TemplateBinding Background}" CornerRadius="30" Padding="10"> <ContentPresenter Content="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center"/> </Border> </ControlTemplate>