Page 1 of 1

Trouble binding to an ItemsControl from a template.

Posted: 07 Aug 2019, 03:04
by asusralis
Hello! I'm trying to add separators for all my ItemsControls. This is what I have so far:
<Style TargetType="ItemsControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ItemsControl">
                    <StackPanel>
                        <Rectangle
                            x:Name="Separator"
                            Height="1"
                            Margin="10,5"
                            Fill="White" />
                        <ItemsPresenter />
                    </StackPanel>
                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}, Path=AlternationIndex}" Value="0">
                            <Setter TargetName="Separator" Property="Visibility" Value="Collapsed" />
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
It seems I can't find the ItemsControl because the separator never shows. What am I doing wrong?

Re: Trouble binding to an ItemsControl from a template.

Posted: 07 Aug 2019, 12:54
by sfernandez
Where exactly do you want that "Separator" to show? In between each item?

Re: Trouble binding to an ItemsControl from a template.

Posted: 07 Aug 2019, 16:41
by asusralis
Yes, exactly - I want the rectangle to show between each element in the ItemsSource, but not at the top of the first element or the bottom of the last. I found a similar question for this, but I can't seem to do it through the style. If there's an easier way I'd love to try it, but using the AlternationIndex seemed the less intrusive to me.

Re: Trouble binding to an ItemsControl from a template.

Posted: 07 Aug 2019, 17:31
by sfernandez
You have to define the ItemTemplate used to render each of the items in the list so you can specify the "Separator" for each item, not in the ItemsControl template which will appear only once:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.Resources>
        <GradientStopCollection x:Key="list">
            <GradientStop Offset="0" Color="Red"/>
            <GradientStop Offset="0.2" Color="Yellow"/>
            <GradientStop Offset="0.4" Color="Green"/>
            <GradientStop Offset="0.6" Color="Cyan"/>
            <GradientStop Offset="0.8" Color="Blue"/>
            <GradientStop Offset="1" Color="Magenta"/>
        </GradientStopCollection>
        <DataTemplate x:Key="itemTemplate">
            <StackPanel>
                <Rectangle x:Name="separator" Height="4" Fill="White"/>
                <Grid>
                    <Rectangle Height="50">
                        <Rectangle.Fill>
                            <SolidColorBrush Color="{Binding Color}"/>
                        </Rectangle.Fill>
                    </Rectangle>
                    <TextBlock Text="{Binding Offset}" Foreground="Gray" TextAlignment="Center" VerticalAlignment="Center"/>
                </Grid>
            </StackPanel>
            <DataTemplate.Triggers>
                <DataTrigger
                    Binding="{Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource Self}}"
                    Value="0">
                    <Setter TargetName="separator" Property="Visibility" Value="Collapsed"/>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </Grid.Resources>
    <Border Background="Gray">
        <ItemsControl x:Name="items"
            ItemsSource="{StaticResource list}"
            ItemTemplate="{StaticResource itemTemplate}"
            AlternationCount="{Binding ItemsSource.Count, RelativeSource={RelativeSource Self}}"
            Width="200" VerticalAlignment="Center"/>
    </Border>
</Grid>

Re: Trouble binding to an ItemsControl from a template.

Posted: 08 Aug 2019, 21:53
by asusralis
I wanted it where all the DataTemplates have a separator in the ItemsControl. I use a selector for multiple DataTemplates, so if I understand correctly I'd have to put a separator in all of them? Is there any way to automatically have a separator for an ItemsControl without changing the DataTemplate?

Something like this:
<ListBox.ItemContainerStyle>                
    <Style TargetType="ListBoxItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <StackPanel>
                        <Separator x:Name="Separator"/>
                        <ContentPresenter/>
                    </StackPanel>
                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
                            <Setter Property="Visibility" TargetName="Separator" Value="Collapsed"/>
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ListBox.ItemContainerStyle>

Re: Trouble binding to an ItemsControl from a template.

Posted: 09 Aug 2019, 11:23
by sfernandez
For a basic ItemsControl the container type is a ContentPresenter so there is no other way to customize item representation than DataTemplates.

But if you are using a ListBox then the container is a ListBoxItem, a control that has its own ControlTemplate, so you can create a single Style for all your lists:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.Resources>
        <GradientStopCollection x:Key="list">
            <GradientStop Offset="0" Color="Red"/>
            <GradientStop Offset="0.2" Color="Yellow"/>
            <GradientStop Offset="0.4" Color="Green"/>
            <GradientStop Offset="0.6" Color="Cyan"/>
            <GradientStop Offset="0.8" Color="Blue"/>
            <GradientStop Offset="1" Color="Magenta"/>
        </GradientStopCollection>
        <ControlTemplate x:Key="listItemTemplate" TargetType="ListBoxItem">
            <DockPanel>
                <Rectangle DockPanel.Dock="Top" x:Name="separator" Height="4" Fill="White"/>
                <ContentPresenter DockPanel.Dock="Bottom"/>
            </DockPanel>
            <ControlTemplate.Triggers>
                <DataTrigger
                    Binding="{Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource Self}}"
                    Value="0">
                    <Setter TargetName="separator" Property="Visibility" Value="Collapsed"/>
                </DataTrigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <Style x:Key="listItemStyle" TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
            <Setter Property="Template" Value="{StaticResource listItemTemplate}"/>
        </Style>
        <DataTemplate x:Key="itemTemplate">
            <Grid>
                <Rectangle Height="50">
                    <Rectangle.Fill>
                        <SolidColorBrush Color="{Binding Color}"/>
                    </Rectangle.Fill>
                </Rectangle>
                <TextBlock Text="{Binding Offset}" Foreground="Gray" TextAlignment="Center" VerticalAlignment="Center"/>
            </Grid>
        </DataTemplate>
    </Grid.Resources>
    <Border Background="Gray">
        <ListBox
            ItemsSource="{StaticResource list}"
            ItemTemplate="{StaticResource itemTemplate}"
            ItemContainerStyle="{StaticResource listItemStyle}"
            AlternationCount="{Binding ItemsSource.Count, RelativeSource={RelativeSource Self}}"
            Width="200" VerticalAlignment="Center"/>
    </Border>
</Grid>

Re: Trouble binding to an ItemsControl from a template.

Posted: 09 Aug 2019, 22:44
by asusralis
Oh, I'm sorry to hear that :( Thanks for the information!