2009-08-29 9 views
10

Tengo una WPF ListView/GridView especificada en XAML. La primera columna usa CellTemplate para especificar iconos y los demás usan DisplayMemberBinding para completarse. La columna de iconos tiene 20 de ancho, los íconos 16 pero están truncados por márgenes/relleno/algo. No puedo averiguar dónde está establecido.¿Dónde están establecidos los márgenes/relleno en un wpf ListView GridView?

Aquí es lo esencial (He quitado algunas columnas porque son lo mismo):

<ListView.ItemContainerStyle> 
    <Style TargetType="{x:Type ListViewItem}"> 
     <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" /> 
     <Setter Property="FontWeight" Value="Normal" /> 
     <Style.Triggers> 
      <Trigger Property="IsSelected" Value="True"> 
       <Setter Property="FontWeight" Value="Bold" /> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 
</ListView.ItemContainerStyle> 

<ListView.Resources> 
    <DataTemplate x:Key="image"> 
     <Image Width="16" Height="16" Margin="0,0,0,0" 
          HorizontalAlignment="Center" 
          Source="{Binding Path=ObjectType, 
              Converter={StaticResource imageConverter} }" /> 
    </DataTemplate> 
</ListView.Resources> 

<ListView.View> 
    <GridView> 
     <GridViewColumn Width="20" 
         CellTemplate="{StaticResource image}"/> 
     <GridViewColumn Width="120" Header="Name" 
         DisplayMemberBinding="{Binding Path=Name}"/> 
    </GridView> 
</ListView.View> 

ImageConverter simplemente convierte un ObjectType en una imagen para que cada tipo de artículo obtiene su propio icono.

Respuesta

6

Usa Snoop para averiguar qué elemento es responsable de imponer el espaciado adicional. Pase el mouse sobre el espacio y mantenga presionado el control y cambie. El elemento se resaltará en el árbol visual.

+0

Agradable, gracias. – serialhobbyist

8

por defecto, cada celda tiene un margen de codificación de 6,0. Probablemente ese es tu problema. Puede anular este comportamiento estableciendo un margen de -6,0 en su CellTemplate

37

Muchas funciones del GridView están codificadas en la clase. En particular, GridViewRowPresenter crea un contenedor codificado con TextBlock o ContentPresenter para cada una de las celdas y fuerza los márgenes a 6,0,6,0, le guste o no.

Normalmente yo haría lo desanime de todo lo que implica la codificación dura un margen negativo para compensar, ya que es un corte en capas en otro truco. Sin embargo, después de desmontar GridViewRowPresenter, no hay otras opciones.

Mi primer intento fue anular el estilo implícito para el control de contenedor que se creó en la clase GridViewRowPresenter, pero ese control es un TextBox o un ContentPresenter que no tiene una plantilla que sobrescribir.

Mi segundo intento fue desarmar el código y crear un nuevo GridViewRowPresenter. Me temo que hay demasiadas llamadas "internas" incestuosas en la clase para hacer de esto una solución factible.

Un arquitecto más inteligente habría proporcionado una DependencyProperty que permitió que el usuario de la clase para anular el recipiente que se ha creado para cada celda. Por algún motivo, permitieron esto con los encabezados, pero no con los contenidos reales de la celda.

Así que nos quedamos con el hecho de que las células en un GridRowPresenter pueden ni ser anulados, ingeniería inversa, ni con plantilla. Lo siento, pero los márgenes negativos son lo mejor que se puede hacer con esta clase.

Necesitamos un mejor ListView: el GridView no es adecuado para una interfaz sin sentido aunque aprecio lo que intentaban hacer los arquitectos originales al divorciar el ItemsPresenter de la presentación.

0

he desarrollado una solución basada en el truco de Ian Griffiths (http://www.interact-sw.co.uk/iangblog/2007/05/30/wpf-listview-column-margins). El control hace lo siguiente:

  • conjuntos Margen modificable para TextBlock o ContentPresenter creado por GridViewRowPresenter a propiedad de dependencia de relleno de este control
  • propaga HorizontalAlignment de este control y VerticalAlignment a sus contenedores
  • restablece Margen/Relleno para los contenedores ListViewItem/GridViewRowPresenter.

Así que le da un tipo de control de los valores que están codificados.

Código: uso

using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Media; 

namespace Put.Your.Namespace.Here 
{ 
    /// <summary> 
    /// Class allows for reseting hard coded ListViewItem margins and paddings 
    /// </summary> 
    public class ListViewCustomizableCellPresenter : Decorator 
    { 
     protected override void OnVisualParentChanged(DependencyObject oldParent) 
     { 
     base.OnVisualParentChanged(oldParent); 

     var cp = VisualTreeHelper.GetParent(this) as FrameworkElement; 
     if (cp != null) 
     { 
      cp.Margin = Padding; 
      cp.VerticalAlignment = VerticalAlignment; 
      cp.HorizontalAlignment = HorizontalAlignment; 
     } 

     ResetGridViewRowPresenterMargin(); 
     ResetListViewItemPadding(); 
     } 

     private T FindInVisualTreeUp<T>() where T : class 
     { 
     DependencyObject result = this; 
     do 
     { 
      result = VisualTreeHelper.GetParent(result); 
     } 
     while (result != null && !(result is T)); 
     return result as T; 
     } 

     private void ResetGridViewRowPresenterMargin() 
     { 
     var gvrp = FindInVisualTreeUp<GridViewRowPresenter>(); 
     if (gvrp != null) 
      gvrp.Margin = new Thickness(0); 
     } 

     private void ResetListViewItemPadding() 
     { 
     var lvi = FindInVisualTreeUp<ListViewItem>(); 
     if (lvi != null) 
      lvi.Padding = new Thickness(0); 
     } 

     /// <summary> 
     /// Padding dependency property registration 
     /// </summary> 
     public static readonly DependencyProperty PaddingProperty = 
     DependencyProperty.Register("Padding", typeof(Thickness), typeof(ListViewCustomizableCellPresenter), new PropertyMetadata(default(Thickness))); 

     /// <summary> 
     /// Padding dependency property 
     /// </summary> 
     public Thickness Padding 
     { 
     get { return (Thickness)GetValue(PaddingProperty); } 
     set { SetValue(PaddingProperty, value); } 
     } 
    } 

} 

de muestra en xaml (dentro definición de GridViewColumn):

<GridViewColumn.CellTemplate> 
    <DataTemplate> 
     <yourxamlnamespacehere:ListViewCustomizableCellPresenter Padding="0" 
                 VerticalAlignment="Center"> 
      <YourControlOrPanelHere /> 
     </yourxamlnamespacehere:ListViewCustomizableCellPresenter> 
    </DataTemplate> 
</GridViewColumn.CellTemplate> 
1

Puesto que el margen está un disco codificado constante, única solución es utilizar la reflexión para cambiarlo por mano.

En VB:

' Hack : 
    ' Changes the default margin for the GridView's Column. 
    Dim GridViewCellMarginProperty = GetType(GridViewRowPresenter).GetField("_defalutCellMargin", BindingFlags.NonPublic Or BindingFlags.Static Or BindingFlags.GetField) 
    If (GridViewCellMarginProperty IsNot Nothing) Then 
     GridViewCellMarginProperty.SetValue(Nothing, New Thickness(2, 0, 2, 0)) 
    End If 

Funciona bien en mi proyecto.

Cuestiones relacionadas