RunningCSharp

MS系開発者による、雑多な記事。記事は所属企業とは関係のない、個人の見解です。

WPF:TreeViewのExpanderをStyleの変更をせずに非表示にする

<Window x:Class="WpfApplication.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"
         xmlns:local="clr-namespace:WpfApplication"
         mc:Ignorable="d"
         Title="MainWindow" Height="350" Width="525">
     <Grid>
         <TreeView>
             <TreeView.Resources>
                 <Style TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
                     <Setter Property="IsExpanded" Value="True" />
                     <Setter Property="local:Att.IsHideExpander" Value="True" />
                 </Style>
             </TreeView.Resources>
             <TreeViewItem Header="parent">
                 <TreeViewItem Header="child" />
             </TreeViewItem>
             <TreeViewItem Header="parent">
                 <TreeViewItem Header="child" />
             </TreeViewItem>
             <TreeViewItem Header="parent">
                 <TreeViewItem Header="child">
                     <TreeViewItem Header="child"/>
                 </TreeViewItem>
             </TreeViewItem>
         </TreeView>
     </Grid>
 </Window>

f:id:ys-soniclab:20160622085426p:plain

上記のような画面で、ツリービューのエクスパンダーを非表示にしようと考えました。

ネットでは良くItemContainerStyleを変更する方法を見かけるのですが、 今回は他のStyleとの兼ね合いがあり、ItemContainerStyleを変更しない対応が必要でした。 そこで添付プロパティを使ってみたところ、うまくいきましたのでメモしておきます。

追加した添付プロパティ(とりあえずWpfApplication名前空間に作成)

    public class Att
    {
        public static bool GetIsHideExpander(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsHideExpanderProperty);
        }

        public static void SetIsHideExpander(DependencyObject obj, bool value)
        {
            obj.SetValue(IsHideExpanderProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsHideExpander.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsHideExpanderProperty =
            DependencyProperty.RegisterAttached("IsHideExpander", typeof(bool), typeof(Att), new PropertyMetadata(false, IsHideExpander_PropertyChanged));

        private static void IsHideExpander_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TreeViewItem treeViewItem = d as TreeViewItem;
            if (treeViewItem == null) return;
            treeViewItem.Loaded += TreeViewItem_Loaded;
        }

        private static void TreeViewItem_Loaded(object sender, RoutedEventArgs e)
        {
            TreeViewItem treeViewItem = sender as TreeViewItem;
            if (treeViewItem == null) return;

            treeViewItem.Loaded -= TreeViewItem_Loaded;

            ToggleButton tg = FindChild<ToggleButton>(treeViewItem);
            if (tg != null)
            {
                tg.Visibility = Visibility.Hidden;
            }
        }

        public static T FindChild<T>(DependencyObject parent) where T : DependencyObject
        {
            if (parent == null) return null;
            if (parent is T) return parent as T;

            T child = null;

            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                var c = VisualTreeHelper.GetChild(parent, i);
                child = FindChild<T>(c);
                if (child != null) break;
            }

            return child;
        }
    }

xamlはTreeView.Resourcesタグを修正

            <TreeView.Resources>
                 <Style TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
                     <Setter Property="IsExpanded" Value="True" />
                     <Setter Property="local:Att.IsHideExpander" Value="True" />
                 </Style>
             </TreeView.Resources>

上記コードを追加することで、エクスパンダーが非表示となります。

f:id:ys-soniclab:20160622085444p:plain