wpf mvvm styles itemscontrol

wpf - ¿Cómo usar AlternationIndex en ItemsControls?



mvvm styles (5)

He visto algunos artículos que muestran cómo usar AlternationIndex con ListBox es o ListView s, pero he pasado algunas horas tratando de obtener colores de fondo alternativos en la clase básica de ItemsControl y nada parece funcionar. Todas las muestras de ListBox que vi utilizan ListBoxItem como tipo de destino para el estilo que establece el fondo basado en AlternationIndex , como este de 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>

Quiero usar ItemsControl porque no quiero la funcionalidad de selección y creo que volver a ItemsControl un ListBox para ocultarlo podría no ser la mejor opción.

Esta es una de las cosas que estaba intentando:

<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>

El problema que vi fue que el árbol visual tiene una lista de ContentPresenter que tiene ItemsControl.AlternationIndex alternan entre 0 y 1, pero la Grid en cada ContentPresenter tiene ItemsControl.AlternationIndex establecido en 0.

Probablemente hay algo obvio que me falta ...


ItemContainerStyle se aplica a los elementos generados por ItemsControl: ContentPresenter. El ContentPresenter a su vez contendrá todo lo que ponga en su ItemTemplate. En el caso de un ListBox, ItemContainerStyle se aplica al ListBoxItem generado.

AlternationCount se basa, según lo que publicó, solo disponible en estos elementos generados. No puede usar ItemContainerStyle para establecer el fondo de la Grilla, porque la Grilla es desconocida para ese Estilo.

Lo siguiente sería ideal, pero desafortunadamente ContentPresenter no tiene ninguna propiedad de fondo. Sin embargo, funcionaría para un ListBox (con 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>

Así que terminas escribiendo un estilo para la grilla que se une al AlternationIndex de tu ParentPresenter padre.

<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>


No sé cómo alguna de las respuestas anteriores son legítimas. No pude hacer que ninguno de ellos funcionara (aunque no probé el de Jacobi). De todos modos, encontré el camino hacia la iluminación aquí: http://www.dotnetcurry.com/wpf/1211/wpf-items-control-advanced-topic , que me llevó a agregar lo siguiente en el código subyacente xaml.cs:

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

y esto en la propia 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>

Esto fue tan difícil de encontrar una solución de trabajo que estoy enojado.


O, como encontré en otra publicación, y me funciona muy bien ... Simplemente puede usar un enlace ...

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

NB: recuerde agregar AlterationCount = "100" en su ItemsControl


Si no desea utilizar el enfoque de DataTemplate , puede crear un control personalizado que use un ContentControl como contenedor de elementos, lo que le permite especificar un color de fondo.

Clase:

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; } }

Diccionario de recursos:

<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>


hm .. Después de aproximadamente 2 horas jugando, finalmente encontré la solución que simplemente funciona:

<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>

Espero que esta respuesta ayude a otros a ahorrar algo de tiempo.