I've implemented custom view for ListView using code based on http://msdn.microsoft.com/en-us/library/ms748859.aspx
In the 'TileView" how would I set ListView to stretch each tile to fit the available spac开发者_运维技巧e. I.e. fit exactly 3 columns in the ListView even if the ListView changes size (i.e. keep each tile always 1/3 wide).
<l:PlainView x:Key="tileView" ItemTemplate="{StaticResource centralTile}" />
<DataTemplate x:Key="centralTile">
<StackPanel>
<Grid HorizontalAlignment="Center">
<Image Source="{Binding XPath=@Image}" />
</Grid>
<TextBlock Text="{Binding XPath=@Name}" />
<TextBlock Text="{Binding XPath=@Type}" />
</StackPanel>
</DataTemplate>
Edit:
I have got the ListView to display x tiles using the above and changing the following XAML in that example:
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth),
RelativeSource={RelativeSource
AncestorType=ScrollContentPresenter}}"
ItemWidth="{Binding (ListView.View).ItemWidth,
RelativeSource={RelativeSource AncestorType=ListView}}"
MinWidth="{Binding (ListView.View).ItemWidth,
RelativeSource={RelativeSource AncestorType=ListView}}"
ItemHeight="{Binding (ListView.View).ItemHeight,
RelativeSource={RelativeSource AncestorType=ListView}}"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="3"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
This is exactly what I need where if the ListView resizes the columns will resize as well.
Now I need to figure out how to change the UniformGrid Columns dynamically :)
I have two consideration on subject:
- Your DataTemplate should fit to all arranged rectangle. I mean StackPanel with properties Height/Width = 100 is no good. Use Grid with proportional rows or DockPanel instead.
- There is no standart panel that fills your requirements. I think you should write your own inheritor from Panel(or WrapPanel) class with ColumnCount property. Then override ArrangeOverride and MeasureOverride methods and provide proper rectangles according to ColumnCount.
It's working demonstration but you should improve MyPanel according to your requirements:
public class MyPanel : WrapPanel
{
public int ColumnCount
{
get
{
return (int)GetValue(ColumnCountProperty);
}
set
{
SetValue(ColumnCountProperty, value);
}
}
public static readonly DependencyProperty ColumnCountProperty =
DependencyProperty.Register("ColumnCount",
typeof(int),
typeof(MyPanel),
new FrameworkPropertyMetadata(
0,
FrameworkPropertyMetadataOptions.AffectsRender));
protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
{
if (this.InternalChildren.Count == 0)
{
return finalSize;
}
var arrangedWidth = this.ActualWidth;
var width = this.ActualWidth / this.ColumnCount;
var x = 0.0;
var y = 0.0;
var columnCounter = 0;
for(int i = 0; i<this.InternalChildren.Count; i++)
{
if (columnCounter == this.ColumnCount)
{
y += width;
x = 0;
columnCounter = 0;
}
columnCounter++;
var ch = this.InternalChildren[i];
ch.Arrange(new Rect(x, y, width, width));
x = x + width;
}
return finalSize;
}
protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint)
{
if (this.InternalChildren.Count == 0)
{
return this.DesiredSize;
}
var supposedSize = base.MeasureOverride(constraint);
var width = this.ActualWidth / this.ColumnCount;
var rowsCount = this.InternalChildren.Count / this.ColumnCount + (this.InternalChildren.Count % this.ColumnCount > 0 ? 1 : 0);
for (int i = 0; i < this.InternalChildren.Count; i++)
{
var ch = this.InternalChildren[i];
ch.Measure(new Size(width, width));
}
double totalWidth = this.InternalChildren[0].DesiredSize.Width * this.ColumnCount;
return new Size(totalWidth, rowsCount * width);
}
}
Usage in XAML:
<ListView ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource Template}"
>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<self:MyPanel ColumnCount="3" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
精彩评论