Wpf ListBox – 在 ContentPresenter *内部*更改默认选定项样式
Wpf ListBox – change default selected-item style *inside* the ContentPresenter
我有一个 ListBox,其中每个项目都是一个 StackPanel。 StackPanel 由一个图像及其下方的一个 TextBlock 组成:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10">
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding Path=ImageFilePath}"/>
</Image.Source>
</Image>
<TextBlock Text="Title" TextAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
看起来像这样:
当用户 select 一个项目时,我得到围绕 StackPanel 的默认蓝色矩形:
现在,我想为 selected-item 制作不同的边框,但我希望它 仅围绕图像 。
我知道如何制作控件模板并在 ContentPresenter 周围放置自定义边框,但这当然会围绕整个 StackPanel,而不仅仅是图像。
我不知道是否可以更改 ContentPresenter,是否是个好主意。如果有其他方法可以达到我想要的效果,也可以。
是的,ListBox 自己的 ContentPresenter 对您正在做的事情没有帮助。您想要 a) 消除 ListBox 自己的选择视觉效果,以及 b) 用 DataTemplate 中更适合您项目的内容替换它们。
默认选择视觉效果由 ListBoxItem
的默认模板应用。所以更换那个模板。在 ListBox
的资源中使用样式,将您自己的控件模板应用于 ListBoxItem
。没什么大不了的,只是展示内容,不提供选择背景。然后,您使用数据模板中的触发器处理选择视觉效果,您的图像和标签在其中定义,您可以将更改应用到一个而不是另一个。下面的例子对我有用。
请注意,对 Border 元素上的 HorizontalAlignment 进行了一些调整,使其紧贴其中的 Image 元素。另外,我写了一个快速测试视图模型,其项目 属性 被称为 Items
;我假设这不是您用来填充自己的 ListBox 的集合成员的名称。
<ListBox
Margin="8"
ItemsSource="{Binding Items}"
>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Border
x:Name="HighlightBorder"
BorderThickness="4"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10"
>
<Border.Style>
<Style TargetType="Border">
<!-- MUST set default BorderBrush via a style, if you set it at all.
As an attribute on the Border tag, it would override the effects of
the trigger below.
-->
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Border.Style>
<Image Source="{Binding ImageFilePath}" />
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter TargetName="HighlightBorder" Property="BorderBrush" Value="Orange" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我有一个 ListBox,其中每个项目都是一个 StackPanel。 StackPanel 由一个图像及其下方的一个 TextBlock 组成:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10">
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding Path=ImageFilePath}"/>
</Image.Source>
</Image>
<TextBlock Text="Title" TextAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
看起来像这样:
当用户 select 一个项目时,我得到围绕 StackPanel 的默认蓝色矩形:
现在,我想为 selected-item 制作不同的边框,但我希望它 仅围绕图像 。
我知道如何制作控件模板并在 ContentPresenter 周围放置自定义边框,但这当然会围绕整个 StackPanel,而不仅仅是图像。
我不知道是否可以更改 ContentPresenter,是否是个好主意。如果有其他方法可以达到我想要的效果,也可以。
是的,ListBox 自己的 ContentPresenter 对您正在做的事情没有帮助。您想要 a) 消除 ListBox 自己的选择视觉效果,以及 b) 用 DataTemplate 中更适合您项目的内容替换它们。
默认选择视觉效果由 ListBoxItem
的默认模板应用。所以更换那个模板。在 ListBox
的资源中使用样式,将您自己的控件模板应用于 ListBoxItem
。没什么大不了的,只是展示内容,不提供选择背景。然后,您使用数据模板中的触发器处理选择视觉效果,您的图像和标签在其中定义,您可以将更改应用到一个而不是另一个。下面的例子对我有用。
请注意,对 Border 元素上的 HorizontalAlignment 进行了一些调整,使其紧贴其中的 Image 元素。另外,我写了一个快速测试视图模型,其项目 属性 被称为 Items
;我假设这不是您用来填充自己的 ListBox 的集合成员的名称。
<ListBox
Margin="8"
ItemsSource="{Binding Items}"
>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Border
x:Name="HighlightBorder"
BorderThickness="4"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10"
>
<Border.Style>
<Style TargetType="Border">
<!-- MUST set default BorderBrush via a style, if you set it at all.
As an attribute on the Border tag, it would override the effects of
the trigger below.
-->
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Border.Style>
<Image Source="{Binding ImageFilePath}" />
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter TargetName="HighlightBorder" Property="BorderBrush" Value="Orange" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>