Source project address: https://github.com/Microsoft/…
The following is to convert the sample into a brief description, and give the actual operation results and key codes at the same time:

Alternating Appearance OfItems Subitem Color Alternating Rendering

WPF: (4) Sample Set of Styles and Templates

  • Setting Group Property Description Items for Collection View Sources
<local:Places x:Key="Places"/>

<!--Group the items by State.-->
<CollectionViewSource Source="{StaticResource Places}" x:Key="GroupedData">
    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="State"/>
    </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
  • Subitem Alternating Number Index Corresponding to Color Converter
<!--Returns a Brush for the header of a GroupItem.-->
<AlternationConverter x:Key="GroupHeaderBackgroundConverter">
    <SolidColorBrush>LightBlue</SolidColorBrush>
    <SolidColorBrush>LightSteelBlue</SolidColorBrush>
</AlternationConverter>

<!--Returns a Brush for a ListBoxItem.-->
<AlternationConverter x:Key="BackgroundConverter">
    <SolidColorBrush>Silver</SolidColorBrush>
    <SolidColorBrush>LightGray</SolidColorBrush>
    <SolidColorBrush>GhostWhite</SolidColorBrush>
</AlternationConverter>

The above is considered as a resource item.

  • ListBox sets relative bindings for grouping style, Title template, and data template, where background color is bound to the color converted by the index in the additional attribute ItemsControl. AlternationIndex in GroupItem.

Ps: The AlternationCount and ItemsControl. AlternationIndex properties allow you to specify the appearance of two or more alternate item containers. For example, you can specify alternating background colors for every two items in ItemsControl. ItemsControl. AlternationIndex is assigned to each container in ItemsControl. ItemsControl. AlternationIndex starts at 0, increases to 1 minus AlternationCount, and then restarts from 0.

<ListBox ItemsSource="{Binding Source={StaticResource GroupedData}}"
     DisplayMemberPath="CityName" AlternationCount="3" Name="lb">
    <ListBox.GroupStyle>
        <!--Set alternating backgrounds on the header of each group.-->
        <GroupStyle AlternationCount="2">
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <TextBlock FontWeight="Bold" 
                               Text="{Binding Path=Name}" 
                               Background="{Binding 
                                   RelativeSource={RelativeSource FindAncestor, 
                                   AncestorType={x:Type GroupItem}},
                                   Path=(ItemsControl.AlternationIndex),
                                   Converter={StaticResource 
                                              GroupHeaderBackgroundConverter}}"/>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </ListBox.GroupStyle>
  • Set the subitem Container style of ListBox, and bind the background color of the subitem to the color converted by its additional attribute ItemsControl. AlternationIndex
 <ListBox.ItemContainerStyle>
    <!--Set alternating backgrounds on the items in the ListBox.-->
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Background" 
                    Value="{Binding RelativeSource={RelativeSource Self},
                       Path=(ItemsControl.AlternationIndex),
                       Converter={StaticResource BackgroundConverter}}"/>
    </Style>
</ListBox.ItemContainerStyle>
</ListBox>
  • TreeView resources, including data template, third layer background color alternating item converter, third layer data template; second layer font alternating item converter, first and second layer data template resources
<Grid.Resources>
    <local:ListLeagueList x:Key="MyTreeViewData"/>
    
    <!--Returns alternating brushes.-->
    <AlternationConverter x:Key="TeamsBackgroundConverter">
        <SolidColorBrush>LimeGreen</SolidColorBrush>
        <SolidColorBrush>SpringGreen</SolidColorBrush>
        <SolidColorBrush>Chartreuse</SolidColorBrush>
    </AlternationConverter>
    
    <!--The DataTemplate used by TreeViewItems in the third level
        of the TreeView.-->
    <DataTemplate x:Key="Level3Data">
        <TextBlock Text="{Binding Path=Name}"
                   Background="{Binding RelativeSource={RelativeSource FindAncestor, 
                     AncestorType={x:Type TreeViewItem}},
                     Path=(ItemsControl.AlternationIndex),
                     Converter={StaticResource TeamsBackgroundConverter}}"/>
    </DataTemplate>
    
    <!--Returns altnernating FontStyles.-->
    <AlternationConverter x:Key="LeagueFontStyleConverter">
        <FontStyle >Italic</FontStyle>
        <FontStyle >Normal</FontStyle>
    </AlternationConverter>
    
    <!--The HierarchicalDataTemplate used by TreeViewItems
        in the second level of the TreeView.-->
    <HierarchicalDataTemplate x:Key="Level2Data"
                              ItemsSource="{Binding Path=Teams}"
                              ItemTemplate="{StaticResource Level3Data}"
                              AlternationCount="3">
        <TextBlock Text="{Binding Path=Name}"
                   FontStyle="{Binding RelativeSource={RelativeSource FindAncestor, 
                       AncestorType={x:Type TreeViewItem}},
                       Path=(ItemsControl.AlternationIndex),
                       Converter={StaticResource LeagueFontStyleConverter}}"/>
    </HierarchicalDataTemplate>
    
    <!--The HierarchicalDataTemplate used by TreeViewItems
        in the first level of the TreeView.-->
    <HierarchicalDataTemplate x:Key="Level1Data"
        ItemsSource="{Binding Path=Divisions}"
        ItemTemplate="{StaticResource Level2Data}"
        AlternationCount="2">
        <TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/>
    </HierarchicalDataTemplate>
    
    <Style TargetType="TreeViewItem">
        <Setter Property="IsExpanded" Value="True"/>
    </Style>
    
    </Grid.Resources>
  • Finally, TreeView data source binding, sub-item template binding, and subsequent hierarchical template binding automatically according to ItemTemplate
<TreeView ItemsSource="{Binding Source={StaticResource MyTreeViewData}}"
                          ItemTemplate="{StaticResource Level1Data}"/>

ContentControl Style Content Control Style

WPF: (4) Sample Set of Styles and Templates

  • Label’s Style and Template Resources
<Grid.Resources>
    <Style x:Key="ContentCtrl" TargetType="{x:Type ContentControl}">
        <Setter Property="Background" Value="Red"/>
        <Setter Property="Foreground" Value="Green"/>
        <Setter Property="FontSize" Value="20"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Grid>
                        <!--Keep the Ellipse a circle when ContentControl.Width
            is set.-->
                        <Ellipse Width="{TemplateBinding Width}"
                 Height="{TemplateBinding Width}"
                 Fill="{TemplateBinding Background}"/>
                        <ContentPresenter VerticalAlignment="Center"
                            HorizontalAlignment="Center"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <DataTemplate x:Key="Template1">
        <TextBlock Text="{Binding}" FontSize="12" FontWeight="Bold" TextWrapping="Wrap" />
    </DataTemplate>
    </Grid.Resources>
  • Interface XAML code, Lablel is the ContentTemplate of contentControl bound to the data template
<Label Margin="10, 10, 3, 3" Grid.Column="0" Grid.Row="2">
    <ContentControl Width="75" Style="{StaticResource ContentCtrl}" 
              Content="Hello"/>
</Label>
<!--Put the ContentControl in a Label just to keep the margin and
    Grid cruft out of the snippet.-->
    <Label Margin="10, 10, 3, 3" Grid.Column="0" Grid.Row="3"
       Background="LightBlue">
        <ContentControl Name="contCtrl" ContentTemplate="{StaticResource Template1}" 
      Content="This is the content of the content control."/>
    </Label>

Event Triggers Event Triggers Event Triggers

WPF: (4) Sample Set of Styles and Templates

<Style.Triggers>
    <EventTrigger RoutedEvent="MouseEnter">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation To="300" Duration="0:0:1.5" 
        AccelerationRatio="0.10" DecelerationRatio="0.25" 
        Storyboard.TargetProperty="(Canvas.Width)" />
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
    <EventTrigger RoutedEvent="MouseLeave">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="0:0:1.5" 
        AccelerationRatio="0.10" DecelerationRatio="0.25" 
        Storyboard.TargetProperty="(Canvas.Width)" />
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Style.Triggers>

## Finding Elements InTemplates Finding Elements in Templates##

WPF: (4) Sample Set of Styles and Templates

  • Content control template lookup element
private void ControlTemplateFindElement(object sender, RoutedEventArgs e)
{
    // Finding the grid that is generated by the ControlTemplate of the Button
    var gridInTemplate = (Grid) myButton1.Template.FindName("grid", myButton1);

    // Do something to the ControlTemplate-generated grid
    MessageBox.Show("The actual width of the grid in the ControlTemplate: "
                    + gridInTemplate.GetValue(ActualWidthProperty));
}
  • Finding Elements in Template Controls
private void DataTemplateFindElement(object sender, RoutedEventArgs e)
{
    // Getting the currently selected ListBoxItem
    // Note that the ListBox must have
    // IsSynchronizedWithCurrentItem set to True for this to work
    var myListBoxItem =
        (ListBoxItem) (myListBox.ItemContainerGenerator.ContainerFromItem(myListBox.Items.CurrentItem));

    // Getting the ContentPresenter of myListBoxItem
    var myContentPresenter = FindVisualChild<ContentPresenter>(myListBoxItem);

    // Finding textBlock from the DataTemplate that is set on that ContentPresenter
    var myDataTemplate = myContentPresenter.ContentTemplate;
    var myTextBlock = (TextBlock) myDataTemplate.FindName("textBlock", myContentPresenter);

    // Do something to the DataTemplate-generated TextBlock
    MessageBox.Show("The text of the TextBlock of the selected list item: "
                    + myTextBlock.Text);
}
private TChildItem FindVisualChild<TChildItem>(DependencyObject obj)
    where TChildItem : DependencyObject
{
    for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        var child = VisualTreeHelper.GetChild(obj, i);
        if (child is TChildItem)
            return (TChildItem) child;
        var childOfChild = FindVisualChild<TChildItem>(child);
        if (childOfChild != null)
            return childOfChild;
    }
    return null;
}

The code for finding parent elements can be simplified as follows:

static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
{
    while (source != null && source.GetType() != typeof(T))
        source = VisualTreeHelper.GetParent(source);

    return source;
}

IntroToStyling AndTemplating introduces styles and templates

WPF: (4) Sample Set of Styles and Templates

  • ListBox style
<!--Horizontal ListBox Control Template-->
    <Style TargetType="ListBox">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBox">
                    <Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}">
                        <ScrollViewer HorizontalScrollBarVisibility="Auto" >
                            <StackPanel Orientation="Horizontal" 
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center"
                       IsItemsHost="True"/>
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
  • ListBox Item template
<Style TargetType="ListBoxItem">
    <Setter Property="Opacity" Value="0.5" />
    <Setter Property="MaxHeight" Value="75" />
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Trigger.Setters>
                <Setter Property="Opacity" Value="1.0" />
            </Trigger.Setters>
        </Trigger>
        <EventTrigger RoutedEvent="Mouse.MouseEnter">
            <EventTrigger.Actions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation
          Duration="0:0:0.2"
          Storyboard.TargetProperty="MaxHeight"
          To="90"  />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger.Actions>
        </EventTrigger>
        <EventTrigger RoutedEvent="Mouse.MouseLeave">
            <EventTrigger.Actions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation
          Duration="0:0:1"
          Storyboard.TargetProperty="MaxHeight"  />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger.Actions>
        </EventTrigger>
    </Style.Triggers>
</Style>
  • ListBox template
<!--DataTemplate to display Photos as images
    instead of text strings of Paths-->
    <DataTemplate DataType="{x:Type local:Photo}">
        <Border Margin="3">
            <Image Source="{Binding Source}"/>
        </Border>
    </DataTemplate>
  • ListBox binding code

Ps: It is not recommended to set the width. The width of the source code makes it inconvenient for the scrollbar to display as the window changes.

<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
               Background="Silver"  Margin="10" SelectedIndex="0"/>