3
votes

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
Can you add code for CustomList?kmatyaszek
This would only style the first item id there is only one item in the ListBox...H.B.
...also that binding error is unexpected, though logically off it should work.H.B.
@H.B. It's fine if it just styles the first item only when there is one item in the list. The error I get though is what troubles me and my guess is that it can't find the parent because is part of ItemContainerStyle; which btw I thought it shouldn't matter.Aris
@Aris: I cannot even reproduce that error for me the binding works as expected.H.B.

2 Answers

5
votes

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

0
votes

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.