Подтвердить что ты не робот

Как использовать AlternationIndex в ItemsControls?

Я видел некоторые статьи, которые показывают, как использовать AlternationIndex с ListBox es или ListView s, но я потратил несколько часов, пытаясь получить чередующиеся цвета фона в базовом классе ItemsControl, и ничего не кажется работать. Все образцы ListBox, которые я видел, использовали ListBoxItem как целевой тип для стиля, который устанавливает фон на основе AlternationIndex - как этот из MSDN:

<Grid>
    <Grid.Resources>
        <Style x:Key="alternatingWithTriggers" TargetType="{x:Type ListBoxItem}">
            <Setter Property="Background" Value="Blue"/>
            <Setter Property="Foreground" Value="White"/>
            <Style.Triggers>
                <Trigger Property="ListBox.AlternationIndex" Value="1">
                    <Setter Property="Background" Value="CornflowerBlue"/>
                    <Setter Property="Foreground" Value="Black"/>
                </Trigger>
                <Trigger Property="ListBox.AlternationIndex" Value="2">
                    <Setter Property="Background" Value="LightBlue"/>
                    <Setter Property="Foreground" Value="Navy"/>
                </Trigger>
            </Style.Triggers>
        </Style>

    </Grid.Resources>
    <ListBox AlternationCount="3" ItemsSource="{StaticResource data}" 
             ItemContainerStyle="{StaticResource alternatingWithTriggers}">
    </ListBox>
</Grid>

Я хочу использовать ItemsControl, потому что мне не нужны функции выбора, и я думаю, что рестайлинг ListBox, чтобы скрыть его, может быть не лучшим выбором.

Это одна из вещей, которые я пытался:

<DataTemplate DataType="{x:Type vm:ObservableCollectionItem}">
    <Grid>
        <!-- some content here -->
    </Grid>
</DataTemplate>

<!-- ... -->

<ItemsControl
    ItemsSource="{Binding ObservableCollectionItems}"
    AlternationCount="2"
>
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Style.Triggers>
                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                    <Setter Property="Grid.Background" Value="Red"></Setter>
                </Trigger>
                <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                    <Setter Property="Grid.Background" Value="Blue"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

Проблема, которую я видел, заключалась в том, что в визуальном дереве есть список ContentPresenter, у которого ItemsControl.AlternationIndex чередуются между 0 и 1, но Grid в каждом ContentPresenter имеет ItemsControl.AlternationIndex, установленный в 0.

Возможно, что-то очевидное, чего я не вижу...

4b9b3361

Ответ 1

Элемент ItemContainerStyle применяется к элементам, сгенерированным элементом ItemsControl: ContentPresenter. ContentPresenter, в свою очередь, будет содержать все, что вы помещаете в свой ItemTemplate. В случае с ListBox ItemContainerStyle применяется к сгенерированному элементу ListBoxItem.

AlternationCount основан на том, что вы опубликовали, только на этих сгенерированных элементах. Вы не можете использовать ItemContainerStyle для установки фона Grid, потому что Grid не знает этого стиля.

Следующее было бы идеальным, но, к сожалению, ContentPresenter не имеет свойства фона. Однако это будет работать с ListBox (с ListBoxItems).

<ItemsControl
    ItemsSource="{Binding ObservableCollectionItems}"
    AlternationCount="2">
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Style.Triggers>
                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                    <Setter Property="Background" Value="Red"></Setter>
                </Trigger>
                <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                    <Setter Property="Background" Value="Blue"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

Итак, вы в конечном итоге написали стиль для сетки, которая привязывается к AlternationIndex вашего родителя ContentPresenter.

<DataTemplate DataType="{x:Type vm:ObservableCollectionItem}">
    <Grid>
        <Grid.Style>
            <Style TargetType="Grid">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="0">
                        <Setter Property="Background" Value="Red"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="1">
                        <Setter Property="Background" Value="Blue"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Style>
    </Grid>
</DataTemplate>

Ответ 2

hm.. Примерно через 2 часа я наконец нашел решение, которое просто работает:

       <ItemsControl ItemsSource="{Binding}" AlternationCount="2">
              <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Background="Transparent" x:Name="__PART_GRID"></Grid>
                        <DataTemplate.Triggers>
                            <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                                <Setter TargetName="__PART_GRID" Property="Background" Value="Red"/>
                            </Trigger>
                            <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                                <Setter TargetName="__PART_GRID" Property="Background" Value="Blue"/>
                            </Trigger>
                        </DataTemplate.Triggers>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
         </ItemsControl>

Я надеюсь, что этот ответ поможет другим сэкономить время.

Ответ 3

Или, как я нашел в другом посте, и он отлично работает для меня... Вы можете просто использовать привязку...

{Binding
    RelativeSource={RelativeSource Mode=TemplatedParent}, 
    Path=(ItemsControl.AlternationIndex)}

NB: не забудьте добавить AlterationCount = "100" в свой ItemsControl

Ответ 4

Если вы не хотите использовать подход DataTemplate, вы можете создать настраиваемый элемент управления, который использует ContentControl в качестве контейнера элементов, поэтому вы можете указать цвет фона.

Класс:

public class ItemsControlAlternating : ItemsControl
{
    static ItemsControlAlternating()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ItemsControlAlternating),
                 new FrameworkPropertyMetadata(typeof(ItemsControlAlternating)));
    }

    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ContentControl();
    }

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is ContentControl;
    }
}

Словарь ресурсов:

<Style TargetType="{x:Type c:ItemsControlAlternating}">
   <Setter Property="AlternationCount" Value="2"/>
   <Setter Property="Template">
       <Setter.Value>
           <ControlTemplate TargetType="{x:Type c:ItemsControlAlternating}">
               <ItemsPresenter/>
           </ControlTemplate>
       </Setter.Value>
   </Setter>
   <Setter Property="ItemContainerStyle">
       <Setter.Value>
           <Style TargetType="{x:Type ContentControl}">
               <Setter Property="Template">
                   <Setter.Value>
                       <ControlTemplate TargetType="{x:Type ContentControl}">
                           <Border Background="{TemplateBinding Background}">
                               <ContentPresenter/>
                           </Border>
                       </ControlTemplate>
                   </Setter.Value>
               </Setter>
               <Style.Triggers>
                   <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                       <Setter Property="Background" Value="Gray"/>
                   </Trigger>
                   <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                       <Setter Property="Background" Value="White"/>
                   </Trigger>
               </Style.Triggers>
           </Style>
       </Setter.Value>
   </Setter>
</Style>

Ответ 5

Я не знаю, как любой из предыдущих ответов является законным. Я не мог заставить никого из них работать (хотя Джейкоби не пытался). В любом случае, я нашел путь к просветлению здесь: http://www.dotnetcurry.com/wpf/1211/wpf-items-control-advanced-topic, что привело меня к добавлению следующего в код xaml.cs:

public sealed class CustomItemsControl : ItemsControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ContentControl();
    }
}

и это в самой xaml

    <local:CustomItemsControl AlternationCount="2" 
          ItemsSource="{Binding Cells, Mode=OneWay}">
        <local:CustomItemsControl.ItemContainerStyle>
            <Style TargetType="ContentControl">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ContentControl">
                            <Border Background="{TemplateBinding Background}">
                                <ContentPresenter/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>

                <Style.Triggers>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="WhiteSmoke"/>
                    </Trigger>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="LightGray"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </local:CustomItemsControl.ItemContainerStyle>
    </local:CustomItemsControl>

Это было так чертовски сложно найти рабочее решение, что я на самом деле сержусь