在 wpf 列表框中的 select 个图像上显示图标

Display icon over select images in wpf listbox

我查看了一些相关的答案 (, and Images only showing in last ListBoxItem),但似乎无法让他们的答案在我的示例中起作用。

我的应用程序 wpf 堆栈相对复杂。

我在另一个 window 中有一个 UserControl。在 UserControl 中,我有一个带有嵌套元素的列表框 ListBox.ItemTemplate > DataTemplate > Border > Grid > StackPanel

在 StackPanel 中是一个 TextBlock,后跟一个图像和一个 StackPanel.ToolTip

我想在图像上放置一个图标,所以我通过将图像放在网格中并添加通过控件模板访问的 ViewBox 进一步混淆了图像(如上面链接中所建议的),以便 ViewBox 以图像为中心。这是网格:

<Grid>
    <Image RenderOptions.BitmapScalingMode="HighQuality"
Height="{Binding ElementName=_this, Path=ThumbSize.Height}"
>
        <gif:ImageBehavior.AnimatedSource>
            <MultiBinding Converter="{c:ImageConverter}">
                <Binding Path="ThumbLocation" />
                <Binding Path="FullName" />
            </MultiBinding>
        </gif:ImageBehavior.AnimatedSource>
    </Image>
    <Control Template="{StaticResource PlaySymbol}" Visibility="{Binding PlayVisible}" />
</Grid>

ViewBox 的 ControlTemplate 在顶部 UserControl.Resources

<ControlTemplate x:Key="PlaySymbol" TargetType="{x:Type Control}">
    <Viewbox Stretch="Uniform" 
                    RenderTransformOrigin="0.5,0.5" 
                    Opacity="0.75"
                x:Shared="False"
                    >
        <Viewbox.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
            </TransformGroup>
        </Viewbox.RenderTransform>
        <ContentControl Content="{StaticResource appbar_control_play}" />
    </Viewbox>
</ControlTemplate>

appbar_control_play 位于 Icons.xaml 文件的 Resources 目录中。

<Canvas x:Key="appbar_control_play" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
    <Path Width="20.5832" Height="31.6667" Canvas.Left="30.0833" Canvas.Top="22.1667" Stretch="Fill" Fill="{DynamicResource BlackBrush}" Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z "/>
</Canvas>

目标是只在电影中显示 'play' 的图标。我已将 PlayVisible 设置为 return 电影的适当可见性,而不是其他文件。然而,它只显示最后一部电影。我听说控件只能有一个父项就是这种情况。我试过在 ViewBox 上设置 x:Shared="False",但没有用。

该应用程序有效,但我最近决定将电影添加到列表中并希望在其缩略图上显示播放图标,而不是其他项目。乍一看似乎很简单,但我还没有弄清楚需要什么。

任何帮助将不胜感激,否则我觉得我可能不得不求助于将图标覆盖在电影的实际缩略图上。

不确定您这边发生了什么,但以下方法有效:

<Window x:Class="abc.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:system="clr-namespace:System;assembly=System.Runtime"
        mc:Ignorable="d"
        Title="Window1">
    <Grid>
        <ListBox>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <DataTemplate.Resources>
                        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
                    </DataTemplate.Resources>

                    <Border Width="64" Height="64" BorderBrush="Red" BorderThickness="1">
                        <Grid>
                            <TextBlock Text="{Binding}"
                                       HorizontalAlignment="Center"
                                       VerticalAlignment="Center" />

                            <Rectangle Fill="DeepSkyBlue"
                                       HorizontalAlignment="Right"
                                       VerticalAlignment="Bottom"
                                       Margin="2"
                                       Width="16"
                                       Height="16"
                                       Visibility="{Binding Converter={StaticResource BooleanToVisibilityConverter}}"
                                       x:Name="Button" />
                        </Grid>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <system:Boolean>True</system:Boolean>
            <system:Boolean>False</system:Boolean>
            <system:Boolean>True</system:Boolean>
            <system:Boolean>False</system:Boolean>
            <system:Boolean>True</system:Boolean>
            <system:Boolean>False</system:Boolean>
        </ListBox>
    </Grid>
</Window>

看起来问题与 Viewbox 无关,而是它引用的图像资源 appbar_control_play

无需通过 Control 添加 Viewbox。只需将它直接添加到 DataTemplate.

如果您希望显示内容,通常更喜欢 ContentControl 而不是模板 Control

x:Shared 属性仅在不属于模板但在 ResourceDictionary 中定义的 UIElement 上是必需的。例如,当您将 Viewbox 定义为资源时,您必须将 x:Shared 属性设置为 false。否则在可视化树中只允许出现一次

  1. 如果图像资源是一个图像文件,一个正确的DataTemplate可以如下所示:
<DataTemplate>
  <StackPanel>
    <Grid>
      <Image Source="path to image" />
      <Image Source="path to overlay icon"
             Stretch="UniformToFill"
             Width="50"
             Height="50" />
    </Grid>
  </StackPanel>
</DataTemplate>
  1. 如果图标是 XAML 资源,如 Geometry 或 Segoe MDL2 Assets 字体图标,DataTemplate 应如下所示:

App.xaml

<Application.Resources>
  <Viewbox x:Key="PlayIcon" x:Shared="False">
    <TextBlock FontFamily="Segoe MDL2 Assets"
               Text="&#xE768;" />
  </Viewbox>

  <Viewbox x:Key="appbar_control_play"
           x:Shared="False">
    <Path Width="20.5832"
          Height="31.6667"
          Stretch="Fill"
          Fill="{Binding RelativeSource={RelativeSource AncestroType=ContentControl}, Path=For4ground}"
          Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z " />
  </Viewbox>
</Application.Resources>

MyControl.xaml

<ListBox.ItemTemplate>
  <DataTemplate>
    <StackPanel>
      <Grid>
        <Image Source="path to image" />
        <ContentControl Content="{StaticResource appbar_control_play}"
                        Width="50"
                        Height="50"
                        Foreground="Pink" />
      </Grid>
    </StackPanel>
  </DataTemplate>
</ListBox.ItemTemplate>