Friday, July 27, 2012

How to Customize the look and feel of WPF Tree view? [Part 2]

Styling the expend collapse icon

This part is not easy, we have to open the box and see for our self what’s inside? fear not!! we can open its internal structure using expression blend and then modify the required stuff, our goal in this section is to replace the default expand collapse icon with something more friendly, for instance a plus and minus icon would do for now I guess.
Lets open the project in expression blend navigate to our desired project and then open the desired window, in our case we have main window, a simple tree view control is added. navigate to the tree view just like the image shown here, then select one of the TreeViewItem , if there is no add a demo one. Then right click and select edit template, and select edit a copy.
TreeViewTemplate_thumb2
It will quickly extend the style and bring out the desired styles in a resource file. if you mention it. well here is the xaml looks like after I have edited the default template.
image_thumb5
Looks rusty! but you have to consider that I am a developer not a designer, designers will come out with awesome design to look it good. well our main concern is the know now. Bello I have listed the complete xaml for the edited TreeViewItem Template.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Canvas x:Key="FolderIcon" x:Shared="false" Width="16" Height="16" ClipToBounds="True">
        <Rectangle Fill="BlanchedAlmond" Canvas.Left="0" Canvas.Top="0" Height="15" Width="15">
        </Rectangle>
    </Canvas>
    <Style x:Key="TreeViewItemFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
    <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Width" Value="16"/>
        <Setter Property="Height" Value="16"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Height="16" Width="16" BorderBrush="Gray" BorderThickness="1" Background="Transparent">
                        <Canvas Name="ExpandPath">
                            <Rectangle x:Name="virticalbar" Canvas.Top="1" Canvas.Left="6.5" Width="1" Height="12" Fill="Gray"></Rectangle>
                            <Rectangle Canvas.Left="1" Canvas.Top="7" Width="12" Height="1" Fill="Gray"></Rectangle>
                        </Canvas>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                        </Trigger>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Visibility" TargetName="virticalbar" Value="Hidden"></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="Padding" Value="1,0,0,0"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition MinWidth="19" Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
                        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                            <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Margin="4,0,0,0"/>
                        </Border>
                        <ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="false">
                            <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
                        </Trigger>
                        <Trigger Property="HasItems" Value="false">
                            <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
                        </Trigger>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="true"/>
                                <Condition Property="IsSelectionActive" Value="false"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="VirtualizingStackPanel.IsVirtualizing" Value="true">
                <Setter Property="ItemsPanel">
                    <Setter.Value>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel/>
                        </ItemsPanelTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>  
</ResourceDictionary>


Style the selected item


Now its time to style the selected item, if you carefully notice that by default when you select any items in WPF tree view you would see that there is a blue background appear behind the selected item. There is a good chance that the client or users will not like it in customized business solutions. Again since we have the whole skeleton of the TreeViewItem we would simply modify the default style.

Bellow I have listed the xaml part of the above full style but with a simple modification in one line only, note that we have a trigger were IsSelected Property is been queried with value True, where we have changed the default value to our customized value “Silver”.

<ControlTemplate.Triggers>
    <Trigger Property="IsExpanded" Value="false">
        <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
    </Trigger>
    <Trigger Property="HasItems" Value="false">
        <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
    </Trigger>
    <Trigger Property="IsSelected" Value="true">
        <Setter Property="Background" TargetName="Bd" Value="Silver"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
    </Trigger>
    <MultiTrigger>
        <MultiTrigger.Conditions>
            <Condition Property="IsSelected" Value="true"/>
            <Condition Property="IsSelectionActive" Value="false"/>
        </MultiTrigger.Conditions>
        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    </MultiTrigger>
    <Trigger Property="IsEnabled" Value="false">
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
    </Trigger>
</ControlTemplate.Triggers>


The result is given bellow

Customize outer looks


Most easy part may be customize the outer look we can achieve this with the basic WPF knowledge's. All the container property such as Border Brush, Border thickness and Margin or Padding is available for modification. One interesting this is modification of the scroll bars, in this particular scenario you might want to again expression blend to customize the look and feel of the scroll content and scroll viewer scrollbars.

Summery


In this short article we have seen that how we can customize WPF tree view for our own way and they way we want it to be look like. The methods that has been used in this article is not prefect but one of the solution that can be implemented. Hopefully in future we can look more into it and customize even more to achieve our desired look and feel. If your have any feed back and suggestion please feel free to add in the comment section.

References


No comments:

Post a Comment