Where are the margins/padding set on a wpf ListView GridView?
Asked Answered
D

6

14

I've got a WPF ListView/GridView spec'd in XAML. The first column uses a CellTemplate to specify icons and the others use DisplayMemberBinding to populate themselves. The icons column is 20 wide, the icons 16 but they're getting truncated by margins/padding/something. I can't work out where it's set.

Here's the essentials (I've removed some columns because they're the same):

<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 just turns an ObjectType into an image so each type of item gets its own icon.

Domineca answered 29/8, 2009 at 14:42 Comment(0)
G
6

Use Snoop to figure out which element is responsible for imposing the extra spacing. Mouse over the space and hold down control and shift. The element will then be highlighted in the visual tree.

Guarnerius answered 29/8, 2009 at 15:40 Comment(0)
S
45

Many features of the GridView are hard-coded into the class. In particular the GridViewRowPresenter creates either a hard-coded TextBlock or ContentPresenter container for each of the cells and forces the margins to 6,0,6,0 whether you like it or not.

Normally I would discourage you from anything that involves hard-coding a negative margin to compensate as it's a hack layered on another hack. However, after disassembling the GridViewRowPresenter, there are no other options.

My first attempt was to override the implicit style for the container control that was created in the GridViewRowPresenter class, but that control is a TextBox or a ContentPresenter which has no template to override.

My second attempt was to disassemble the code and build a new GridViewRowPresenter. I'm afraid there are just too many incestuous 'internal' calls in the class to make this a workable solution.

A smarter architect would have provided a DependencyProperty that allowed the user of the class to override the container that was created for each cell. For some reason they allowed this with the headers but not the actual cell contents.

So we are left with the fact that the cells in a GridRowPresenter can neither be overridden, reverse engineered, nor templated. I'm sorry, but the negative margins is the best that can be done with this class.

We need a better ListView: the GridView is not suitable for a lookless interface though I appreciate what they original architects were trying to do by divorcing the ItemsPresenter from the presentation.

Schug answered 5/8, 2010 at 13:44 Comment(0)
M
10

by default, each cell has a hardcoded margin of 6,0. Probably that's your problem. You can override this behaviour by setting a margin of -6,0 in your celltemplate

Mordy answered 10/11, 2009 at 19:51 Comment(0)
G
6

Use Snoop to figure out which element is responsible for imposing the extra spacing. Mouse over the space and hold down control and shift. The element will then be highlighted in the visual tree.

Guarnerius answered 29/8, 2009 at 15:40 Comment(0)
T
2

I developed a solution based on Ian Griffiths's hack ( http://www.interact-sw.co.uk/iangblog/2007/05/30/wpf-listview-column-margins ). The control does the following:

  • sets hard-coded Margin for TextBlock or ContentPresenter created by GridViewRowPresenter to this control's Padding dependency property
  • propagates this control's HorizontalAlignment and VerticalAlignment to its containers
  • resets Margin/Padding for ListViewItem/GridViewRowPresenter containers.

So it gives you a kind of control of values which are hard-coded.

Code:

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

}

Sample usage in xaml (inside definition of GridViewColumn):

<GridViewColumn.CellTemplate>
    <DataTemplate>
        <yourxamlnamespacehere:ListViewCustomizableCellPresenter Padding="0"
                                                        VerticalAlignment="Center">
            <YourControlOrPanelHere />
        </yourxamlnamespacehere:ListViewCustomizableCellPresenter>
    </DataTemplate>
</GridViewColumn.CellTemplate>
Trey answered 17/1, 2013 at 15:53 Comment(0)
T
2

Since the margin is a hard coded constant, only solution is to use reflection to change it by hand.

In 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

It works fine on my project.

Trader answered 8/7, 2014 at 16:48 Comment(0)
G
0

The solution I came to is to inherit GridViewRowPresenter and override OnVisualChildrenChanged to set the margin to 0 when a children is added :

public class MyGridViewRowPresenter : GridViewRowPresenter
{
    protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
    {
        if (visualAdded is FrameworkElement frameworkElement)
            frameworkElement.Margin = new Thickness(0);
        base.OnVisualChildrenChanged(visualAdded, visualRemoved);
    }
}
Goree answered 20/10, 2021 at 15:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.