Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Yes, WPF provides a rather elegant way to implement this because its templating mechanism allows you to fill the unused area in a <code>GridView</code> with whatever you like.</p> <p>All you need to do is modify the <code>ListView</code> template to paint the unused section of the with a <code>VisualBrush</code> that typically consists of two <code>GridViewItems</code> stacked vertically (in the general case it will be <code>AlternationCount</code> <code>GridViewItems</code>).</p> <p>The only complexity is choosing which color to start with when painting the unused section of the <code>ScrollViewer</code>. This is calculated as <code>Items.Count</code> modulo <code>AlternationCount</code>. The solution is to create a simple <code>Control</code> that does this calculation and use it in our <code>ListView</code> template. For the sake of my explanation I will call the control "ContinueAlternation".</p> <p>The <code>ListView</code> template which would be mostly the default template with a <code>local:ContinueAlternation</code> control added below the <code>ScrollViewer</code> using a <code>DockPanel</code>, like this:</p> <pre><code>&lt;ControlTemplate TargetType="{x:Type ListView}"&gt; &lt;Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True"&gt; &lt;DockPanel&gt; &lt;ScrollViewer DockPanel.Dock="Top" Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}" Padding="{TemplateBinding Padding}"&gt; &lt;ItemsPresenter SnapsToDevicePixels="True" /&gt; &lt;/ScrollViewer&gt; &lt;local:ContinueAlternation ItemContainerStyle="{TemplateBinding ItemContainerStyle}" AlternationCount="{TemplateBinding AlternationCount}" ItemsCount="{Binding Items.Count, RelativeSource={RelativeSource TemplatedParent}}" /&gt; &lt;/DockPanel&gt; &lt;/Border&gt; &lt;/ControlTemplate&gt; </code></pre> <p>The <code>ContinueAlternation</code> control will be displayed as a <code>Rectangle</code> painted with a tiled <code>VisualBrush</code> containing an <code>ItemsControl</code> that shows dummy rows, as follows:</p> <pre><code>&lt;ControlTemplate TargetType="{x:Type local:ContinueAlternation}"&gt; &lt;Rectangle&gt; &lt;Rectangle.Fill&gt; &lt;VisualBrush TileMode="Tile" Stretch="None" ViewPortUnits="Absolute" ViewPort="{TemplateBinding ViewportSize}"&gt; &lt;ItemsControl x:Name="PART_ItemsControl" ItemsSource="{Binding}" /&gt; &lt;/VisualBrush&gt; &lt;/Rectangle.Fill&gt; &lt;/Rectangle&gt; &lt;/ControlTemplate&gt; </code></pre> <p>The <code>DataContext</code> here will be an array of dummy <code>ListViewItem</code> generated in code-behind from the given <code>AlternationCount</code> and <code>ItemsCount</code>:</p> <pre><code>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 } </code></pre> <p>Note that this same code could be written with <code>PropertyChangedCallback</code> instead of <code>OnPropertyChanged</code>.</p> <p>You also need to do something to make sure the blank rows are the desired height. The easiest way to do this is to set either <code>MinHeight</code> or <code>Content</code> in your <code>ItemsContainerStyle</code>. Alternatively <code>ContinueAlternation</code> could set the height when it constructs each <code>ListViewItem</code>.</p> <p>I typed all this code off the top of my head, but it is similar to code I've written and used before so it ought to work basically as-is.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload