views:

46

answers:

1

I have a TreeView control where nodes are dynamically built using a HierarchicalDataTemplate. In other words, no TreeViewItems are explicitly defined in the XAML. TreeViewItems are instead created automatically when the data are bound at runtime (I can see them in Silverlight Spy).

Is it possible to customize the expand/collapse symbols (paths) within the TreeView in this case? Clients hate the default triangles as being hard to see and use. I've found references to doing this kind of thing, but only where the TreeViewItems are set up explicitly, so that a Style can be set in the XAML of the page. Another way of asking this I guess is whether it's possible to define and apply a style for the TreeViewItem when they are not in the XAML markup (or added in code as TreeViewItem).

+1  A: 

Yes, you will need to change the TreeViewItem's style property. Here is one I'm using...

<Style x:Key="TreeViewContainerStyle" TargetType="controls:TreeViewItem">
    <Setter Property="Padding" Value="3"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="VerticalContentAlignment" Value="Top"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground"
            Value="Black" />
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Cursor" Value="Arrow"/>
    <Setter Property="Margin" Value="-5,0,0,0"/>
    <Setter Property="IsTabStop" Value="True"/>
    <Setter Property="TabNavigation" Value="Once"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:TreeViewItem">
                <Grid Background="{x:Null}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="25"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="25"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Header" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <SolidColorBrush Color="#FF999999"/>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ExpanderButton" Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="00:00:00" Value="#FF90B5D5"/>
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected"/>
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" Storyboard.TargetName="select" Storyboard.TargetProperty="Opacity" To=".75"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="SelectedInactive">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" Storyboard.TargetName="inactive" Storyboard.TargetProperty="Opacity" To=".2"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="HasItemsStates">
                            <VisualState x:Name="HasItems"/>
                            <VisualState x:Name="NoItems">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ExpanderButton" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="ExpansionStates">
                            <VisualState x:Name="Collapsed"/>
                            <VisualState x:Name="Expanded">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="ItemsHost" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>

                    <ToggleButton x:Name="ExpanderButton" IsTabStop="False" TabNavigation="Once" HorizontalAlignment="Stretch">
                        <ToggleButton.Template>
                            <ControlTemplate TargetType="ToggleButton">
                                <Grid x:Name="Root" Background="Transparent" Opacity=".6">
                                    <VisualStateManager.VisualStateGroups>
                                        <VisualStateGroup x:Name="CommonStates">
                                            <VisualState x:Name="Normal"/>
                                            <VisualState x:Name="MouseOver">
                                            <Storyboard>
                                                    <DoubleAnimation Duration="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1.7"/>
                                                </Storyboard>
                                            </VisualState>
                                            <VisualState x:Name="Disabled">
                                                <Storyboard>
                                                    <DoubleAnimation Duration="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1.7"/>
                                                </Storyboard>
                                            </VisualState>
                                        </VisualStateGroup>
                                        <VisualStateGroup x:Name="CheckStates">
                                            <VisualState x:Name="Unchecked"/>
                                            <VisualState x:Name="Checked">
                                                <Storyboard>
                                                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="MinusSign" Storyboard.TargetProperty="(UIElement.Opacity)">
                                                        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
                                                    </DoubleAnimationUsingKeyFrames>
                                                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="PlusSign" Storyboard.TargetProperty="(UIElement.Opacity)">
                                                        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
                                                    </DoubleAnimationUsingKeyFrames>

                                                </Storyboard>
                                            </VisualState>
                                        </VisualStateGroup>
                                    </VisualStateManager.VisualStateGroups>

                                    <Grid>

                                        <Rectangle x:Name="PlusSign" HorizontalAlignment="Center" VerticalAlignment="Top" Width="20" Height="20" Visibility="Visible" Opacity="100">
                                            <Rectangle.Fill>
                                                <ImageBrush Stretch="Fill" ImageSource="./icon_expand_hover.png"/>
                                            </Rectangle.Fill>

                                        </Rectangle>

                                        <Rectangle x:Name="MinusSign" HorizontalAlignment="Center" VerticalAlignment="Top" Width="20" Height="20" Visibility="Visible" Opacity="0">
                                            <Rectangle.Fill>
                                                <ImageBrush Stretch="Fill" ImageSource="./icon_collapse_hover.png"/>
                                            </Rectangle.Fill>
                                        </Rectangle>

                                    </Grid>

                                </Grid>
                            </ControlTemplate>
                        </ToggleButton.Template>
                    </ToggleButton>
                    <Rectangle x:Name="select" StrokeThickness="1" RadiusX="2" RadiusY="2" IsHitTestVisible="False" Opacity="0" Grid.Column="1" HorizontalAlignment="Stretch" Width="Auto" Margin="0,0,5,0">
                        <Rectangle.Stroke>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#00000000"/>
                                <GradientStop Color="#7F000000" Offset="1"/>
                                <GradientStop Color="#06000000" Offset="0.379"/>
                            </LinearGradientBrush>
                        </Rectangle.Stroke>
                        <Rectangle.Fill>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#00000000"/>
                                <GradientStop Color="#7F000000" Offset="1"/>
                                <GradientStop Color="#06000000" Offset="0.659"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                    <Rectangle x:Name="inactive" Fill="#FF999999" Stroke="#FF333333" StrokeThickness="1" RadiusX="2" RadiusY="2" IsHitTestVisible="False" Opacity="0" Grid.Column="1" HorizontalAlignment="Left" Width="6"/>
                    <Button x:Name="Header" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" IsTabStop="False" TabNavigation="Once" ClickMode="Hover" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" Grid.Column="1">
                        <Button.Template>
                            <ControlTemplate TargetType="Button">
                                <Grid Background="{TemplateBinding Background}">
                                    <VisualStateManager.VisualStateGroups>
                                        <VisualStateGroup x:Name="CommonStates">
                                            <VisualState x:Name="Normal"/>
                                            <VisualState x:Name="Pressed">
                                                <Storyboard>
                                                    <DoubleAnimation Duration="0" Storyboard.TargetName="hover" Storyboard.TargetProperty="Opacity" To=".5"/>
                                                </Storyboard>
                                            </VisualState>
                                            <VisualState x:Name="Disabled">
                                                <Storyboard>
                                                    <DoubleAnimation Duration="0" Storyboard.TargetName="content" Storyboard.TargetProperty="Opacity" To=".55"/>
                                                </Storyboard>
                                            </VisualState>
                                        </VisualStateGroup>
                                    </VisualStateManager.VisualStateGroups>
                                    <Rectangle x:Name="hover" Fill="#FFBADDE9" Stroke="#FF6DBDD1" StrokeThickness="1" RadiusX="2" RadiusY="2" IsHitTestVisible="False" Opacity="0"/>
                                    <ContentPresenter x:Name="content" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="Left" Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
                                </Grid>
                            </ControlTemplate>
                        </Button.Template>
                    </Button>
                    <Border   Visibility="Collapsed" x:Name="ItemsHost" Grid.Column="1" Grid.Row="1" CornerRadius="1,4,8,4" BorderThickness="1,1,1,1" Padding="5,0,0,0" Margin="-27,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <Border.Background>
                            <SolidColorBrush Color="AntiqueWhite" />
                        </Border.Background>
                        <Border.BorderBrush>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FF0D0A45" Offset="0"/>
                                <GradientStop Color="#FF0D0A45" Offset="1"/>
                                <GradientStop Color="#FF38435B" Offset="0.2"/>
                            </LinearGradientBrush>
                        </Border.BorderBrush>
                        <Grid>
                            <Rectangle Fill="{x:Null}" 
                                RadiusX="8" RadiusY="8" 
                                VerticalAlignment="Bottom"  
                                HorizontalAlignment="Right" 
                                Width="100" Height="40" 
                                Margin="0,0,3,3">
                                <Rectangle.Stroke>
                                    <LinearGradientBrush EndPoint="1,1" StartPoint="0.7,0.7">
                                        <GradientStop Color="#00FFFFFF" Offset="0"/>
                                        <GradientStop Color="#7FFFFFFF" Offset="1"/>
                                    </LinearGradientBrush>
                                </Rectangle.Stroke>
                            </Rectangle>
                            <ItemsPresenter   />
                        </Grid>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Notice the toggle button.


So then in the code behind you would do...

myDynamicTreeViewItem.Style = (Style)this.Resources["TreeViewContainerStyle"];
JGord
Thanks for the reply. In my case the TreeViewItems are not being added via code - they're created behind the scenes by use of the HierarchicalDataTemplate. So I don't have immediate access to the TreeViewItem to set its Style. If you're using the HierarchicalDataTemplate, how are you accessing the TreeViewItems created for the TreeView?
Bryan B