根据 ListBox 中的索引设置 ListBoxItem 的样式

Posted

技术标签:

【中文标题】根据 ListBox 中的索引设置 ListBoxItem 的样式【英文标题】:Styling a ListBoxItem depending on its index in the ListBox 【发布时间】:2012-07-12 19:36:16 【问题描述】:

如果 SomeProperty 值为 10,我想更改 ListBox 中第一项的边距,无需代码隐藏。 这是我目前所拥有的:

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

当我尝试这种方法时,我得到:

System.Windows.Data 错误:4:找不到与引用'RelativeSource FindAncestor,AncestorType='ListBox',AncestorLevel='1'' 的绑定源。 BindingExpression:Path=Items.Count;数据项=空;目标元素是 'ListBox' (Name='');目标属性是“NoTarget”(类型“对象”)

如果我只有第一个条件,它会正确应用边距。 我尝试的另一种方法是使用 ElementName:

这种方法不会给出任何错误,但它也不起作用。

任何帮助将不胜感激。

【问题讨论】:

可以为CustomList添加代码吗? 这只会设置第一个项目 id 的样式,ListBox 中只有一个项目... ...绑定错误也是出乎意料的,尽管从逻辑上讲它应该可以工作。 @H.B.如果它仅在列表中有一个项目时才设置第一个项目的样式,那很好。我得到的错误让我很困扰,我的猜测是它找不到父级,因为它是 ItemContainerStyle 的一部分;顺便说一句,我认为这无关紧要。 @Aris:我什至无法为我重现该错误,绑定按预期工作。 【参考方案1】:

AlternationIndex。 (您可以使用非常高的AlternationCount 来确保只有第一项具有索引0 并触发)。

这有点滥用,更简洁的方法是值转换器/多值转换器,通过listBox.Items.IndexOf(currentItem) 之类的方式获取索引。

【讨论】:

您可以将其绑定到项目计数,以便每个项目的 AlternationIndex 都是唯一的,而不是使用任意高的 AlternationCountAlternationCount="Binding Items.Count, RelativeSource=RelativeSource Self"【参考方案2】:

另一个解决方案是子类化列表框,并覆盖 PrepareContainerForItemOverride 方法。请参阅下面的示例(它适用于 WP7 中的 Silverlight,所以我没有 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;
    

然后我从 ListBoxEx.iContainerStyle 派生我的项目以获得不同项目的不同边距。

【讨论】:

以上是关于根据 ListBox 中的索引设置 ListBoxItem 的样式的主要内容,如果未能解决你的问题,请参考以下文章

C#中的listBox

如何根据 asp.net mvc4 中的模型列表填充 ListBox?

获取ListBox中的ListBoxItem

如何在 ListBox 中查找最小重复值的索引?

vb listbox控件中的某些项如何设置为默认选中?

winform中的listbox怎样添加双击事件