Где поля/отступы, установленные в wpf ListView GridView?

У меня есть WPF ListView/GridView spec'd в XAML. Первый столбец использует CellTemplate для указания значков, а остальные используют DisplayMemberBinding для заполнения. Столбец значков 20 ширины, значки 16, но они усекаются полями/дополнением/чем-то. Я не могу решить, где он установлен.

Здесь основные (я удалил несколько столбцов, потому что они одинаковые):

<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 просто превращает ObjectType в изображение, чтобы каждый тип элемента получал свой собственный значок.

Ответ 1

Используйте Snoop, чтобы выяснить, какой элемент отвечает за наложение дополнительного интервала. Мышь над пространством и удерживайте управление и смену. Затем элемент будет выделен в визуальном дереве.

Ответ 2

Многие функции GridView жестко закодированы в классе. В частности, GridViewRowPresenter создает либо жестко закодированный контейнер TextBlock, либо ContentPresenter для каждой из ячеек и заставляет поля 6,0,6,0 вам нравится или нет.

Обычно я бы отговаривал вас от всего, что связано с жестким кодированием, с отрицательной маржой, чтобы компенсировать, поскольку он взломал на другой хак. Однако после разборки GridViewRowPresenter других вариантов нет.

Моя первая попытка состояла в том, чтобы переопределить неявный стиль для управления контейнером, который был создан в классе GridViewRowPresenter, но этот элемент управления является TextBox или ContentPresenter, у которого нет шаблона для переопределения.

Моя вторая попытка состояла в том, чтобы разобрать код и построить новый GridViewRowPresenter. Я боюсь, что в этом классе слишком много кровосмесительных "внутренних" вызовов, чтобы сделать это работоспособным решением.

Более умный архитектор предоставил DependencyProperty, который позволил бы пользователю класса переопределить контейнер, который был создан для каждой ячейки. По какой-то причине они допускали это с заголовками, но не с фактическим содержимым ячейки.

Таким образом, мы остаемся с тем, что ячейки в GridRowPresenter не могут быть переопределены, реверсированы и не шаблонизированы. Извините, но отрицательные поля - это лучшее, что можно сделать с этим классом.

Нам нужен лучший ListView: GridView не подходит для бесшумного интерфейса, хотя я ценю то, что пытались сделать оригинальные архитекторы, разводя ItemsPresenter из презентации.

Ответ 3

по умолчанию каждая ячейка имеет жестко заданный запас в 6,0. Наверное, твоя проблема. Вы можете переопределить это поведение, установив маркер -6,0 в свой файл celltemplate

Ответ 4

Я разработал решение, основанное на хаке Ian Griffiths (http://www.interact-sw.co.uk/iangblog/2007/05/30/wpf-listview-column-margins). Элемент управления выполняет следующие действия:

  • задает жестко закодированную маржу для TextBlock или ContentPresenter, созданных GridViewRowPresenter для этого элемента управления. Свойство зависимости от заполнения.
  • передает этот элемент управления HorizontalAlignment и VerticalAlignment в свои контейнеры.
  • сбрасывает поля Margin/Padding для контейнеров ListViewItem/GridViewRowPresenter.

Таким образом, он дает вам контроль над значениями, которые жестко закодированы.

код:

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

}

Пример использования в xaml (внутри определения GridViewColumn):

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

Ответ 5

Поскольку маржа является жестко закодированной константой, единственным решением является использование Reflexion для ее изменения вручную.

В VB:

    ' Hack : 
    ' Changes the default margin for the GridView 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

Он отлично работает в моем проекте.