Styling a ListBoxItem depending on its index in th

2019-07-11 19:34发布

I want to change the margin of the first item in the ListBox if SomeProperty value is 10, without code-behind. This is what I have so far:

<ListBox  x:Class="Windows.CustomList"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:Windows"
                 mc:Ignorable="d" x:Name="MyList"
                 d:DesignHeight="300" d:DesignWidth="300">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=SomeProperty}" Value="10"/>
                        <Condition Binding="{Binding Path=Items.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}" Value="1" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Margin">
                        <Setter.Value>
                            <Thickness Left="500"/>
                        </Setter.Value>
                    </Setter>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <local:ListBoxItemCustomTemplate/>
        </DataTemplate>
    </ListBox.ItemTemplate>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

When I try this approach I get:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='ListBox', AncestorLevel='1''. BindingExpression:Path=Items.Count; DataItem=null; target element is 'ListBox' (Name=''); target property is 'NoTarget' (type 'Object')

If I have only the first condition, it applies the margin properly. Another way I tried was by using the ElementName:

This approach doesn't give any error but it's not working either.

Any help would be much appreciated.

2条回答
Luminary・发光体
2楼-- · 2019-07-11 19:37

See AlternationIndex. (You can use a very high AlternationCount to ensure that only the first item has index 0 and trigger on that).

This is a bit abusive, a cleaner method would be a value converter / multi value converter, that gets the index via something like listBox.Items.IndexOf(currentItem).

查看更多
我想做一个坏孩纸
3楼-- · 2019-07-11 19:38

Another solution would be subclassing list box, and overriding PrepareContainerForItemOverride method. See my example below (it's for the Silverlight in WP7, so I had no AlternationIndex)..

public class ListBoxEx: ListBox
{
    public interface iContainerStyle
    {
        Thickness containerMargin { get; }
        Thickness containerPadding { get; }
    };

    protected override void PrepareContainerForItemOverride( DependencyObject element, Object item )
    {
        base.PrepareContainerForItemOverride( element, item );

        var style = item as iContainerStyle;
        if( null == style )
            return;

        var container = element as ListBoxItem;
        if( null == container )
            return;
        container.Margin = style.containerMargin;
        container.Padding = style.containerPadding;
    }
}

Then I derive my items from ListBoxEx.iContainerStyle to get different margins for different items.

查看更多
登录 后发表回答