Продолжить изменение вида сетки WPF - PullRequest
3 голосов
/ 13 марта 2010

Можно ли продолжить стили изменения в виде сетки, даже если нет элементов?

alt text

Как видите, после последнего элемента шаблон останавливается.

1 Ответ

2 голосов
/ 21 марта 2010

Да, WPF предоставляет довольно элегантный способ реализовать это, потому что его механизм шаблонов позволяет вам заполнить неиспользуемую область в GridView чем угодно.

Все, что вам нужно сделать, это изменить шаблон ListView, чтобы закрасить неиспользуемый раздел с помощью VisualBrush, который обычно состоит из двух GridViewItems, расположенных вертикально (в общем случае это будет AlternationCount GridViewItems).

Единственная сложность - выбрать, с какого цвета начать рисовать неиспользуемый участок ScrollViewer. Это рассчитывается как Items.Count по модулю AlternationCount. Решение состоит в том, чтобы создать простой Control, который выполняет этот расчет, и использовать его в нашем шаблоне ListView. Ради моего объяснения я назову элемент управления «ContinueAlternation».

Шаблон ListView, который в основном будет шаблоном по умолчанию с элементом управления local:ContinueAlternation, добавленным ниже ScrollViewer с использованием DockPanel, например:

<ControlTemplate TargetType="{x:Type ListView}">
  <Border BorderThickness="{TemplateBinding BorderThickness}"
          BorderBrush="{TemplateBinding BorderBrush}"
          Background="{TemplateBinding Background}"
          SnapsToDevicePixels="True">
    <DockPanel>
      <ScrollViewer DockPanel.Dock="Top"
                    Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}"
                    Padding="{TemplateBinding Padding}">
        <ItemsPresenter SnapsToDevicePixels="True" />
      </ScrollViewer>

      <local:ContinueAlternation
        ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
        AlternationCount="{TemplateBinding AlternationCount}"
        ItemsCount="{Binding Items.Count,
                          RelativeSource={RelativeSource TemplatedParent}}" />

    </DockPanel>
  </Border>
</ControlTemplate>

Элемент управления ContinueAlternation будет отображаться как Rectangle, закрашенный мозаичным VisualBrush, содержащим ItemsControl, который показывает фиктивные строки, следующим образом:

<ControlTemplate TargetType="{x:Type local:ContinueAlternation}">
  <Rectangle>
    <Rectangle.Fill>

      <VisualBrush TileMode="Tile" Stretch="None"
                   ViewPortUnits="Absolute"
                   ViewPort="{TemplateBinding ViewportSize}">

        <ItemsControl x:Name="PART_ItemsControl"
                      ItemsSource="{Binding}" />
      </VisualBrush>
    </Rectangle.Fill>
  </Rectangle>
</ControlTemplate>

Здесь DataContext будет массивом пустышки ListViewItem, сгенерированным в коде от заданных AlternationCount и ItemsCount:

public class ContinueAlternation
{
  public Style ItemsContainerStyle ... // Declare as DependencyProperty using propdp snippet
  public int AlternationCount ... // Declare as DependencyProperty using propdp snippet
  public int ItemsCount ... // Declare as DependencyProperty using propdp snippet

  protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
  {
    if(e.Property==ItemsContainerStyleProperty ||
       e.Property==AlternationCountProperty ||
       e.Property==ItemsCountProperty)
    {
      // Here is where we build the items for display
      DataContext =
        from index in Enumerable.Range(ItemsCount,
                                       ItemsCount + AlternationCount)
        select BuildItem( index % AlternationCount);
    }
  }
  ListViewItem BuildItem(int alternationIndex)
  {
    var item = new ListViewItem { Style = ItemsContainerStyle };
    ItemsControl.SetAlternationIndex(item, alternationIndex);
    return item;
  }

  protected override Size MeasureOverride(Size desiredSize)
  {
    var ic = (ItemsControl)GetTemplateChild("PART_ItemsControl");
    ic.Width = desiredSize.Width;
    Size result = base.MeasureOverride(desiredSize);
    ViewportSize = new Size(ic.DesiredSize);
    return result;
  }
  public Size ViewportSize ... // Declare as DependencyProperty using propdp snippet
}

Обратите внимание, что этот же код может быть записан с PropertyChangedCallback вместо OnPropertyChanged.

Вам также нужно что-то сделать, чтобы убедиться, что пустые строки имеют желаемую высоту. Самый простой способ сделать это - установить MinHeight или Content в вашем ItemsContainerStyle. В качестве альтернативы ContinueAlternation может установить высоту при построении каждого ListViewItem.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...