TreeView
の各アイテムを枠囲みしたり背景を色付にしようとすると、内部のテキストをぴったり納めるような枠のサイズになってデコボコしたり
、中身のサイズを固定するとサブアイテムのお尻が右に飛び出る
といまいち綺麗じゃありません。
TreeView.HorizontalContentAlignment=Stretchで解決できると思いきや、TreeViewはこのプロパティを華麗に無視。TreeViewItemのテンプレートを根こそぎ変更しないといけないらしい。1から書くと大変そうなのでネットにあったテンプレート
を改造。変更点は、
- テンプレートの最初にあるGridがTreeViewItemを表示する部分。HorizontalAlignment="Stretch"にして目一杯横に広がるようにする。
- そのGridの2カラム目が肝心の中身。ここのWidthをAutoから*に。
- 3カラム目は要らない子なので削除。
- 消した3カラム目の辻褄合わせに、下のほうにあるItemsPresenterのColumnSpan指定を削除。
<UserControl x:Class="TreeViewTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="300">
<UserControl.Resources>
<Style TargetType="TreeViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem" xmlns:s="clr-namespace:System;assembly=mscorlib">
<Grid HorizontalAlignment="Stretch">
<!--
<Grid>
-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="19" />
<ColumnDefinition Width="*"/>
<!-- Change to expand width of tree items to base TreeView size (expand to right edge)
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
-->
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<ToggleButton IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent},Path=IsExpanded,Mode=TwoWay}" ClickMode="Press" Name="Expander">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
<Setter Property="UIElement.Focusable">
<Setter.Value>
<s:Boolean>False</s:Boolean>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.Width">
<Setter.Value>
<s:Double>16</s:Double>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.Height">
<Setter.Value>
<s:Double>16</s:Double>
</Setter.Value>
</Setter>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Padding="5,5,5,5" Background="#00FFFFFF" Width="30" Height="30">
<Path Fill="#00FFFFFF" Stroke="#FF989898" Name="ExpandPath">
<Path.Data>
<!--※②マークを変えるにはここの値を変える-->
<PathGeometry Figures="M0,0L0,10L10,0z" />
</Path.Data>
<Path.RenderTransform>
<RotateTransform Angle="135" CenterX="3" CenterY="3" />
</Path.RenderTransform>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver">
<Setter TargetName="ExpandPath" Property="Shape.Stroke">
<Setter.Value>
<SolidColorBrush>#FF1BBBFA</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter TargetName="ExpandPath" Property="Shape.Fill">
<Setter.Value>
<SolidColorBrush>#00FFFFFF</SolidColorBrush>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="ToggleButton.IsChecked">
<Setter TargetName="ExpandPath" Property="UIElement.RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" CenterX="3" CenterY="3" />
</Setter.Value>
</Setter>
<Setter TargetName="ExpandPath" Property="Shape.Fill">
<Setter.Value>
<SolidColorBrush>#FF595959</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter TargetName="ExpandPath" Property="Shape.Stroke">
<Setter.Value>
<SolidColorBrush>#FF262626</SolidColorBrush>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="{TemplateBinding Control.Padding}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True" Grid.Column="1">
<ContentPresenter Content="{TemplateBinding HeaderedContentControl.Header}" ContentTemplate="{TemplateBinding HeaderedContentControl.HeaderTemplate}" ContentStringFormat="{TemplateBinding HeaderedItemsControl.HeaderStringFormat}" ContentSource="Header" Name="PART_Header" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
<!--
<ItemsPresenter Name="ItemsHost" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2"/>
-->
<ItemsPresenter Name="ItemsHost" Grid.Column="1" Grid.Row="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TreeViewItem.IsExpanded">
<Setter TargetName="ItemsHost" Property="UIElement.Visibility" Value="{x:Static Visibility.Collapsed}" />
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="ItemsControl.HasItems">
<Setter TargetName="Expander" Property="UIElement.Visibility" Value="{x:Static Visibility.Hidden}" />
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="TreeViewItem.IsSelected">
<Setter TargetName="Bd" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="TreeViewItem.IsSelected">
<Condition.Value>
<s:Boolean>True</s:Boolean>
</Condition.Value>
</Condition>
<Condition Property="Selector.IsSelectionActive">
<Condition.Value>
<s:Boolean>False</s:Boolean>
</Condition.Value>
</Condition>
</MultiTrigger.Conditions>
<Setter TargetName="Bd" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" />
</Setter.Value>
</Setter>
</MultiTrigger>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<!--※①マージンを変える場合はここ-->
<StackPanel IsItemsHost="True" Margin="20,0,0,0"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<TreeView Name="tree" ItemsSource="{Binding Items}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type TVItem}" ItemsSource="{Binding Items}">
<Border BorderBrush="Silver" BorderThickness="2" Margin="0.5" Padding="2">
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition MinHeight="32"/>
<RowDefinition MinHeight="20"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="{Binding Name}" FontSize="20" HorizontalAlignment="Left" VerticalAlignment="Center" />
<Label Grid.Row="1" Grid.Column="0" Content="{Binding Status}" FontSize="16" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<ProgressBar Grid.Row="1" Grid.Column="1" Minimum="0" Maximum="1" Value="{Binding Progress}" HorizontalAlignment="Stretch"/>
</Grid>
</Border>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</UserControl>
元データとなるCLRクラスはこんな感じです。
public partial class TreeViewTest : UserControl
{
public TreeViewTest()
{
InitializeComponent();
DataContext = new
{
Items = new TVItem[]
{
new TVItem()
{
Name = "Item 1",
Status = "Status 1",
Progress = 0.1
},
new TVItem()
{
Name = "Item 2",
Status = "Status 2",
Progress = 0.3,
Items = new TVItem[]
{
new TVItem()
{
Name = "Item 2-1",
Status = "Status 2-1",
Progress = 0.5
},
new TVItem()
{
Name = "Item 2-2",
Status = "Status 2-2",
Progress = 0.7
}
}
}
}
};
}
}
public class TVItem
{
public string Name { get; set; }
public string Status { get; set; }
public double Progress { get; set; }
public IEnumerable<TVItem> Items{ get; set; }
}
[参考]
[2013/02/24] コード修正
Comments