Question

Silverlight does not support Alternating Item Templates in an ItemsControl. I have a few ideas in mind as to how to accomplish this, but to avoid polluting the potential answers, I'll leave them out.

The idea is the same as a normal ItemTemplate in that it won't depend on anything in the bound data context to function. I would like the functionality to remain in the View (assuming MVVM)

If you had to design a method of providing alternating templates (and I mean a full data template) for an ItemsControl, how would you accomplish this?

Was it helpful?

Solution

Extend ItemsControl and in the PrepareContainerForItemOverride override you can apply alternating templates.

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        if (!object.ReferenceEquals(element, item))
        {
            ContentPresenter presenter = element as ContentPresenter;
            ContentControl control = null;
            if (presenter == null)
            {
                control = element as ContentControl;
                if (control == null)
                {
                    return;
                }
            }
            DataTemplate itemTemplate = null;
            if ((this.ItemTemplate != null) && (this.DisplayMemberPath != null))
            {
                throw new InvalidOperationException("Cannot set ItemTemplate and DisplayMemberPath simultaneously");
            }
            if (!(item is UIElement))
            {
                if (this.ItemTemplate != null)
                {
                    if(this.AlternateItemTemplate != null && ((alternationIndex % 2)) == 1)
                        itemTemplate = this.AlternateItemTemplate;
                    else
                    itemTemplate = this.ItemTemplate;
                    alternationIndex++;
                }
            }
            if (presenter != null)
            {
                if (itemTemplate != null)
                {
                    presenter.Content = item;
                    presenter.ContentTemplate = itemTemplate;
                }
                else
                {
                    presenter.SetBinding(ContentControl.ContentProperty, new Binding(this.DisplayMemberPath));
                }
            }
            else
            {
                control.Content = item;
                control.ContentTemplate = itemTemplate;
            }
        }
    }

The way I'm using alternationIndex is not very accurate and would need to be changed, but otherwise this should work.

OTHER TIPS

I got stuck on the same problem recently. I eventually decided that attached properties are the way to go, and ended up with functionality that works somewhat like this:

<Grid x:Name="LayoutRoot" Background="White">
    <ListBox x:Name="ListItems">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Border>
                    <Border.Style>
                        <Style TargetType="Border">
                            <Setter Property="Background" Value="White" />
                        </Style>
                    </Border.Style>
                    <local:ItemsControlAlternation.AlternateStyle>
                        <Style TargetType="Border">
                            <Setter Property="Background" Value="LightBlue" />
                        </Style>
                    </local:ItemsControlAlternation.AlternateStyle>
                    <ContentPresenter Content="{Binding}" />
                </Border>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

I posted about it here: http://www.philsversion.com/2010/11/22/alternating-row-styles-in-silverlight/

Phil

P.s. Sorry for the blatant self promotion :)

I would put a Bool property in the Item ViewModel class and write DataTrigger on the ItemTemplate to give a different look. In the collection we can loop through and set that bool appropriately

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top