c# - ¿Se puede aplicar la transparencia de forma diferente para cada elemento de ListView?

CorePress2024-01-24  8

Estoy intentando crear un control que muestre un mensaje de chat simple.

Se muestran hasta 10 mensajes. El mensaje más reciente siempre se agrega al final de ListView El mensaje más antiguo se encuentra en la parte superior de ListView.

Quiero oscurecer cada vez más los mensajes antiguos (Opacidad).

¿Tienes alguna idea sobre cómo hacer esto?



------------------------------------

Esto no se admite de manera inmediata, pero puedes lograr este comportamiento fácilmente para una cantidad fija de elementos usando un truco. Cada ItemsControl tiene un mecanismo de alternancia incorporado que generalmente se usa para cambiar el estilo o la apariencia de las filas dependiendoen un índice de alternancia.

En este caso utilizamos esta funcionalidad para obtener el índice de un ListViewItem y establecer la opacidad.

Establezca la propiedad AlternationCount en el tamaño fijo de su colección. Agregue un estilo de contenedor de elementos para establecer la opacidad de ListViewItem. Agregue un AlternationConverter con la opacidad de cada elemento. Vincule la propiedad adjunta AlternationIndex usando el convertidor.

De esta manera, el AlternationIndex se utiliza para aplicar el valor de opacidad correspondiente.

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

El resultado de una colección arbitraria de cadenas se ve así.

Si desea aplicar un algoritmo más sofisticado para la opacidad, cree un convertidor de valores personalizado.

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();
   }
}

En este caso, también necesitaría vincular la propiedad AlternationCount para obtener la colección size.

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

El resultado es similar, pero en este caso, la opacidad mínima es 0,3.

1

Tus ideas y ejemplos me ayudaron mucho. Aún no lo he aplicado, pero creo que definitivamente es una característica que quiero. Muchas gracias.

- Abeja melífera

28/03/2021 a las 10:01



------------------------------------

Ya respondido, pero daré otra idea para lograrlo.Haga esto sin código subyacente.

La idea es simplemente poner una cuadrícula de gradiente de opacidad sobre ListView. De arriba a abajo, se vuelve borroso desde la parte superior de Listview y luego se borra en la parte inferior de ListView. Asegúrese de establecer IsHitTestVisible en falso y cambie el color del pincel al fondo de ListView. y también Margen para la región de la barra de desplazamiento.

Lo probé y funciona. Pero la calidad es regular. porque el color de resaltado de Seleccionar elemento también obtiene opacidad y la superposición de cuadrícula podría cubrir la región de la barra de desplazamiento.

Pero para quienes quieran una manera fácil, dejaré este comentario. Sería una manera fácil si su aplicación no necesita 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>

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare