Где установлены поля / отступы в wpf ListView GridView? - PullRequest
10 голосов
/ 29 августа 2009

У меня есть спецификация WPF ListView / GridView в 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 в изображение, чтобы у каждого типа элемента была своя иконка.

Ответы [ 5 ]

37 голосов
/ 05 августа 2010

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

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

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

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

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

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

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

8 голосов
/ 10 ноября 2009

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

6 голосов
/ 29 августа 2009

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

2 голосов
/ 17 января 2013

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

  • устанавливает жестко запрограммированное поле Margin для TextBlock или ContentPresenter, созданного GridViewRowPresenter, для свойства зависимости Padding этого элемента управления
  • распространяет горизонтальное выравнивание и вертикальное выравнивание этого элемента управления в свои контейнеры
  • сбрасывает 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>
1 голос
/ 08 июля 2014

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

В 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

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

...