是否可以对 ListView 的每个项目应用不同的透明度?

Can transparency be applied differently for each item of ListView?

我正在尝试创建一个显示简单聊天消息的控件。

最多显示 10 条消息。 最新消息始终添加到 ListView 的末尾 最早的消息位于 ListView.

的顶部

我想让旧消息越来越模糊(Opacity)。

你对如何做到这一点有什么想法吗?

不支持 out-of-the-box,但您可以使用技巧轻松实现此行为 固定数量的项目。每个 ItemsControl 都有一个 built-in 交替机制,通常用于根据交替索引更改行的样式或外观。

在这种情况下,我们利用此功能获取 ListViewItem 的索引并设置 Opacity.

  • AlternationCount 属性 设置为 collection.
  • 固定大小
  • 添加项目容器样式以设置 ListViewItemOpacity
  • 为每个项目添加一个 AlternationConverter 和不透明度。
  • 使用转换器绑定附件 属性 AlternationIndex

这样,AlternationIndex 用于应用相应的不透明度值。

<ListView ItemsSource="{Binding YourItemsSource}"
          AlternationCount="10">
   <ListView.ItemContainerStyle>
      <Style TargetType="{x:Type ListViewItem}">
         <Style.Resources>
            <AlternationConverter x:Key="AlternationIndexToOpacityConverter">
               <system:Double>0.1</system:Double>
               <system:Double>0.2</system:Double>
               <system:Double>0.3</system:Double>
               <system:Double>0.4</system:Double>
               <system:Double>0.5</system:Double>
               <system:Double>0.6</system:Double>
               <system:Double>0.7</system:Double>
               <system:Double>0.8</system:Double>
               <system:Double>0.9</system:Double>
               <system:Double>1.0</system:Double>
            </AlternationConverter>
         </Style.Resources>
         <Setter Property="Opacity" Value="{Binding (ItemsControl.AlternationIndex), RelativeSource={RelativeSource Self}, Converter={StaticResource AlternationIndexToOpacityConverter}}"/>
      </Style>
   </ListView.ItemContainerStyle>
</ListView>

string 的任意 collection 的结果如下所示。

如果您想对不透明度应用更复杂的算法,请创建一个自定义值转换器。

public class AlternationIndexToOpacityConverter : IMultiValueConverter
{
   public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
   {
      if (values == null || values.Length != 2)
         return DependencyProperty.UnsetValue;

      if (!(values[0] is int alternationCount) || !(values[1] is int alternationIndex))
         return DependencyProperty.UnsetValue;

      var proportion = (double) alternationIndex / (alternationCount - 1);
      return 0.3 + proportion * 0.7;
   }

   public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
   {
      throw new InvalidOperationException();
   }
}

在这种情况下,您还需要绑定 AlternationCount 属性,以获得 collection 大小。

<ListView ItemsSource="{Binding YourItemsSource}"
          AlternationCount="10">
   <ListView.ItemContainerStyle>
      <Style TargetType="{x:Type ListViewItem}">
         <Style.Resources>
            <local:AlternationIndexToOpacityConverter x:Key="AlternationIndexToOpacityConverter"/>
         </Style.Resources>
         <Setter Property="Opacity">
            <Setter.Value>
               <MultiBinding Converter="{StaticResource AlternationIndexToOpacityConverter}">
                  <Binding Path="AlternationCount" RelativeSource="{RelativeSource AncestorType={x:Type ListView}}"/>
                  <Binding Path="(ItemsControl.AlternationIndex)" RelativeSource="{RelativeSource Self}"/>
               </MultiBinding>
            </Setter.Value>
         </Setter>
      </Style>
   </ListView.ItemContainerStyle>
</ListView>

结果看起来相似,但在本例中,最小不透明度为 0.3

已经回答了,但我会给出另一个想法来实现这个没有背后的代码。

这个想法只是在 ListView 上放置一个不透明度渐变网格。从上到下,从Listview的顶部模糊,然后在ListView的底部清晰。确保设置 IsHitTestVisible 为 false,并将画笔颜色更改为 ListView 的背景。以及 ScrollBar 区域的保证金。

我测试了它,它有效。但质量马马虎虎。因为 Select 项目高亮颜色也变得不透明,并且网格覆盖可以覆盖滚动条区域。

但对于谁想要简单的方法,我会留下这个评论。如果您的应用程序不需要 ScrollBar.

,这将是简单的方法
<Grid IsHitTestVisible="False" Margin="0 0 18 0">
  <Grid.Background>
    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
      <GradientStop Color="#bbffffff" Offset="0.1"/>
      <GradientStop Color="#77ffffff" Offset="0.3"/>
      <GradientStop Color="#00ffffff" Offset="1.0"/>
    </LinearGradientBrush>
  </Grid.Background>
</Grid>