我尝试在Windows 10中创建一个类似于默认新闻应用的网格视图。据我所知,我必须为ItemSeight设置VariableSizedWrapGrid的ItemWidth。但是它不会拉伸项目以适应整个网格宽度,而新闻应用程序确实这样做,如下图所示。他们是怎么做到的?它是一种特殊的自定义控件吗?
答案 0 :(得分:9)
我会给你一个概念:
+---------+ +---------+ +---------+ | small | | | | | +---------+ | | | | --- gap --- | medium | | | +---------+ | | | | | small | | | | big | +---------+ +---------+ | | --- gap --- --- gap --- | | +---------+ +---------+ | | | small | | small | | | +---------+ +---------+ +---------+ --- gap --- --- gap --- --- gap ---
所以我们只有3个不同的盒子用于具有已知高度的演示。 视图本身可以决定(代码隐藏)使用哪个模板来呈现内容。
每个组的Alle项目按5到9个项目分组排列。这些组在ItemsControl中显示,每个组由WrapPanel(垂直oriantation)呈现。
让我们看一下这些行:
lllll mmmmm lllll mmmmm lllll mmmmm lllll lllll sssss lllll mmmmm lllll mmmmm lllll mmmmm lllll lllll sssss
lllll lllll mmmmm lllll lllll mmmmm lllll lllll mmmmm lllll lllll lllll lllll lllll lllll mmmmm mmmmm lllll mmmmm mmmmm lllll mmmmm mmmmm lllll
lllll lllll lllll sssss lllll lllll lllll lllll lllll lllll sssss lllll lllll lllll lllll lllll lllll sssss
mmmmm mmmmm mmmmm mmmmm sssss mmmmm mmmmm mmmmm mmmmm mmmmm mmmmm mmmmm mmmmm sssss
因此,我们需要三个DataTemplates用于内容项,一些模板用于WrapPanel,一些逻辑用于将项目分组为行,以及WrapPanel和内部项目的模板管理。
这里有一个简单的XAML PoC来测试这个概念:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ScrollViewer>
<ItemsControl x:Name="ItemsPresenter" SizeChanged="ItemsPresenter_SizeChanged">
<ItemsControl.Resources>
<Style x:Key="col" TargetType="WrapPanel">
<Setter Property="Orientation" Value="Vertical"/>
<Setter Property="ItemWidth" Value="{Binding ColumnWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"/>
</Style>
<Style x:Key="content" TargetType="TextBlock">
<Setter Property="Margin" Value="5"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="TextAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
</Style>
<Style x:Key="small" TargetType="TextBlock" BasedOn="{StaticResource content}">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Height" Value="30"/>
</Style>
<Style x:Key="medium" TargetType="TextBlock" BasedOn="{StaticResource content}">
<Setter Property="Background" Value="LightGreen"/>
<Setter Property="Height" Value="70"/>
</Style>
<Style x:Key="large" TargetType="TextBlock" BasedOn="{StaticResource content}">
<Setter Property="Background" Value="LightSalmon"/>
<Setter Property="Height" Value="110"/>
</Style>
<Style x:Key="1col6items" TargetType="WrapPanel" BasedOn="{StaticResource col}">
<Setter Property="Height" Value="480"/>
</Style>
<Style x:Key="2col6items" TargetType="WrapPanel" BasedOn="{StaticResource col}">
<Setter Property="Height" Value="240"/>
</Style>
<Style x:Key="3col6items" TargetType="WrapPanel" BasedOn="{StaticResource col}">
<Setter Property="Height" Value="200"/>
</Style>
<Style x:Key="4col6items" TargetType="WrapPanel" BasedOn="{StaticResource col}">
<Setter Property="Height" Value="120"/>
</Style>
<Style x:Key="5col6items" TargetType="WrapPanel" BasedOn="{StaticResource col}">
<Setter Property="Height" Value="80"/>
</Style>
</ItemsControl.Resources>
<!-- first row -->
<WrapPanel >
<TextBlock>1</TextBlock>
<TextBlock>2</TextBlock>
<TextBlock>3</TextBlock>
<TextBlock>4</TextBlock>
<TextBlock>5</TextBlock>
<TextBlock>6</TextBlock>
</WrapPanel>
<!-- second row -->
<WrapPanel >
<TextBlock>7</TextBlock>
<TextBlock>8</TextBlock>
<TextBlock>9</TextBlock>
<TextBlock>10</TextBlock>
<TextBlock>11</TextBlock>
<TextBlock>12</TextBlock>
</WrapPanel>
<!-- third row -->
<WrapPanel >
<TextBlock>13</TextBlock>
<TextBlock>14</TextBlock>
<TextBlock>15</TextBlock>
<TextBlock>16</TextBlock>
<TextBlock>17</TextBlock>
<TextBlock>18</TextBlock>
</WrapPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
和相似的
非常简单的 ProofOfConcept,在调整大小时使用拉伸和模板
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent( );
}
public int ColumnCount
{
get { return (int) GetValue( ColumnCountProperty ); }
private set { SetValue( ColumnCountProperty, value ); }
}
// Using a DependencyProperty as the backing store for ColumnCount. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ColumnCountProperty =
DependencyProperty.Register( "ColumnCount", typeof( int ), typeof( MainWindow ), new PropertyMetadata( 1 ) );
public double ColumnWidth
{
get { return (double) GetValue( ColumnWidthProperty ); }
private set { SetValue( ColumnWidthProperty, value ); }
}
// Using a DependencyProperty as the backing store for ColumnWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ColumnWidthProperty =
DependencyProperty.Register( "ColumnWidth", typeof( double ), typeof( MainWindow ), new PropertyMetadata( (double) 100 ) );
public double ColumnMinWidth
{
get { return (double) GetValue( ColumnMinWidthProperty ); }
set
{
SetValue( ColumnMinWidthProperty, value );
CalculateColumnLayout( );
}
}
// Using a DependencyProperty as the backing store for ColumnMinWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ColumnMinWidthProperty =
DependencyProperty.Register( "ColumnMinWidth", typeof( double ), typeof( MainWindow ), new PropertyMetadata( (double) 200 ) );
public double ColumnMaxWidth
{
get { return (double) GetValue( ColumnMaxWidthProperty ); }
set
{
SetValue( ColumnMaxWidthProperty, value );
CalculateColumnLayout( );
}
}
// Using a DependencyProperty as the backing store for ColumnMaxWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ColumnMaxWidthProperty =
DependencyProperty.Register( "ColumnMaxWidth", typeof( double ), typeof( MainWindow ), new PropertyMetadata( (double) 250 ) );
private void CalculateColumnLayout()
{
int colCount = ColumnCount;
double totalWidth = ItemsPresenter.ActualWidth;
double colWidth = totalWidth / colCount;
while ( colCount > 1 && colWidth < Math.Min( ColumnMinWidth, ColumnMaxWidth ) )
{
colCount--;
colWidth = totalWidth / colCount;
}
while ( colCount < 5 && colWidth > Math.Max( ColumnMinWidth, ColumnMaxWidth ) )
{
colCount++;
colWidth = totalWidth / colCount;
}
if ( ColumnCount != colCount )
{
ColumnCount = colCount;
StyleItemsPresenterItems( );
}
ColumnWidth = colWidth;
}
private Dictionary<int, string[]> _styles = new Dictionary<int, string[]>
{
[ 1 ] = new string[] { "medium", "medium", "medium", "medium", "medium", "medium" },
[ 2 ] = new string[] { "large", "medium", "small", "small", "medium", "large" },
[ 3 ] = new string[] { "large", "medium", "medium", "large", "large", "medium" },
[ 4 ] = new string[] { "large", "large", "large", "small", "small", "small" },
[ 5 ] = new string[] { "medium", "medium", "medium", "medium", "small", "small" },
};
private void StyleItemsPresenterItems()
{
foreach ( var pnl in ItemsPresenter.Items.OfType<WrapPanel>( ) )
{
if ( pnl != null )
{
pnl.Style = ItemsPresenter.Resources[ $"{ColumnCount}col6items" ] as Style;
foreach ( var item in pnl.Children.OfType<TextBlock>( ).Zip( _styles[ ColumnCount ], ( border, stylename ) => new { border, stylename } ) )
{
item.border.Style = ItemsPresenter.Resources[ item.stylename ] as Style;
}
}
}
}
private void ItemsPresenter_SizeChanged( object sender, SizeChangedEventArgs e )
{
CalculateColumnLayout( );
}
}
和代码隐藏
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FBSDKLoginManager.initialize() // Initialize facebook login
return true
}
最后结果
答案 1 :(得分:3)
根据MSDN,ItemWidth可以设置为Auto。
ItemHeight和ItemWidth的默认值不是0,它是 Double.NaN。 ItemHeight和ItemWidth支持成为一个 取消设置“自动”值。因为ItemHeight和ItemWidth是Double 值,Double.NaN用作表示此“Auto”的特殊值 行为。布局系统通常将“自动”值解释为 表示对象的大小应该是布局中可用的大小, 而不是特定的像素值。
我不知道这是否会导致你想要的行为。如果没有,那么您可以通过将ItemWidth绑定到一个属性来获取它,您可以根据网格的宽度计算项目宽度。它看起来像这样:
D:\apache-jena-3.1.1\lib\*.jar
答案 2 :(得分:2)
作为我之前回答的补充,我在这里展示了基本概念,这是一个使用问题中提到的VariableSizedWrapPanel
的UWP平台解决方案:
主要工作由
完成<local:MyGridView
ItemsSource="{Binding}"
ItemTemplateSelector="{StaticResource MyGridTemplateSelector}"
MinItemWidth="300" MaxItemWidth="600"
ScrollViewer.VerticalScrollBarVisibility="Hidden">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid ItemHeight="180" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</local:MyGridView>
与
一起using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace App1
{
public class MyGridView : GridView
{
private int _columnCount = 1;
private double _itemWidth = 100;
public double MinItemWidth
{
get { return (double) GetValue( MinItemWidthProperty ); }
set { SetValue( MinItemWidthProperty, value ); }
}
// Using a DependencyProperty as the backing store for MinItemWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinItemWidthProperty =
DependencyProperty.Register( "MinItemWidth", typeof( double ), typeof( MyGridView ), new PropertyMetadata( 100.0 ) );
public double MaxItemWidth
{
get { return (double) GetValue( MaxItemWidthProperty ); }
set { SetValue( MaxItemWidthProperty, value ); }
}
// Using a DependencyProperty as the backing store for MaxItemWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MaxItemWidthProperty =
DependencyProperty.Register( "MaxItemWidth", typeof( double ), typeof( MyGridView ), new PropertyMetadata( 200.0 ) );
private long _itemsPanelPropertyChangedToken;
public MyGridView()
{
_itemsPanelPropertyChangedToken = RegisterPropertyChangedCallback( ItemsPanelProperty, ItemsPanelChangedAsync );
}
private async void ItemsPanelChangedAsync( DependencyObject sender, DependencyProperty dp )
{
UnregisterPropertyChangedCallback( ItemsPanelProperty, _itemsPanelPropertyChangedToken );
await this.Dispatcher.RunIdleAsync( ItemsPanelChangedCallback );
}
private void ItemsPanelChangedCallback( IdleDispatchedHandlerArgs e )
{
var wg = ItemsPanelRoot as VariableSizedWrapGrid;
if (wg != null)
{
wg.ItemWidth = _itemWidth;
}
}
protected override void PrepareContainerForItemOverride( DependencyObject element, object item )
{
var itemIndex = this.Items.IndexOf( item );
element.SetValue( VariableSizedWrapGrid.RowSpanProperty, GetRowSpanByColumnCountAndIndex( _columnCount, itemIndex ) );
element.SetValue( VerticalContentAlignmentProperty, VerticalAlignment.Stretch );
element.SetValue( HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch );
base.PrepareContainerForItemOverride( element, item );
}
private static readonly Dictionary<int, int[]> _rowSpanLayout = new Dictionary<int, int[]>
{
[ 1 ] = new int[] { /* 5 */ 2, 2, 2, 2, 2, /* 6 */ 2, 2, 2, 2, 2, 2, /* 7 */ 2, 2, 2, 2, 2, 2, 2, /* 8 */ 2, 2, 2, 2, 2, 2, 2, 2, /* 9 */ 2, 2, 2, 2, 2, 2, 2, 2, 2 },
[ 2 ] = new int[] { /* 5 */ 2, 1, 2, 2, 1, /* 6 */ 3, 3, 3, 2, 2, 2, /* 7 */ 3, 3, 1, 2, 3, 1, 1, /* 8 */ 2, 3, 2, 3, 3, 3, 3, 1, /* 9 */ 3, 2, 1, 3, 2, 2, 3, 1, 1 },
[ 3 ] = new int[] { /* 5 */ 3, 2, 2, 1, 1, /* 6 */ 2, 3, 2, 3, 3, 2, /* 7 */ 3, 3, 3, 2, 1, 2, 1, /* 8 */ 2, 3, 3, 1, 2, 1, 2, 1, /* 9 */ 3, 3, 3, 1, 2, 1, 3, 3, 2 },
[ 4 ] = new int[] { /* 5 */ 2, 2, 1, 2, 1, /* 6 */ 3, 3, 2, 2, 1, 1, /* 7 */ 3, 2, 2, 2, 1, 1, 1, /* 8 */ 3, 3, 3, 3, 2, 2, 2, 2, /* 9 */ 3, 3, 3, 2, 2, 2, 2, 2, 1 },
[ 5 ] = new int[] { /* 5 */ 2, 2, 2, 2, 2, /* 6 */ 2, 2, 2, 1, 2, 1, /* 7 */ 3, 3, 3, 2, 2, 1, 1, /* 8 */ 3, 3, 2, 2, 2, 1, 1, 1, /* 9 */ 3, 2, 2, 2, 2, 1, 1, 1, 1 },
};
private int GetRowSpanByColumnCountAndIndex( int columnCount, int itemIndex )
{
return _rowSpanLayout[ columnCount ][ itemIndex % 35 ];
}
protected override Size MeasureOverride( Size availableSize )
{
System.Diagnostics.Debug.WriteLine( availableSize );
int columnCount = _columnCount;
double availableWidth = availableSize.Width;
double itemWidth = availableWidth / columnCount;
while ( columnCount > 1 && itemWidth < Math.Min( MinItemWidth, MaxItemWidth ) )
{
columnCount--;
itemWidth = availableWidth / columnCount;
}
while ( columnCount < 5 && itemWidth > Math.Max( MinItemWidth, MaxItemWidth ) )
{
columnCount++;
itemWidth = availableWidth / columnCount;
}
var wg = this.ItemsPanelRoot as VariableSizedWrapGrid;
_itemWidth = itemWidth;
if ( _columnCount != columnCount )
{
_columnCount = columnCount;
if ( wg != null )
{
Update( );
}
}
if ( wg != null )
{
wg.ItemWidth = itemWidth;
}
return base.MeasureOverride( availableSize );
}
// refresh the variablesizedwrapgrid layout
private void Update()
{
if ( !( this.ItemsPanelRoot is VariableSizedWrapGrid ) )
throw new ArgumentException( "ItemsPanel is not VariableSizedWrapGrid" );
int itemIndex = 0;
foreach ( var container in this.ItemsPanelRoot.Children.Cast<GridViewItem>( ) )
{
int rowSpan = GetRowSpanByColumnCountAndIndex( _columnCount, itemIndex );
VariableSizedWrapGrid.SetRowSpan( container, rowSpan );
itemIndex++;
}
this.ItemsPanelRoot.InvalidateMeasure( );
}
}
}
和
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace App1
{
public class MyGridViewTemplateSelector : DataTemplateSelector
{
public DataTemplate Small { get; set; }
public DataTemplate Medium { get; set; }
public DataTemplate Large { get; set; }
protected override DataTemplate SelectTemplateCore( object item, DependencyObject container )
{
var rowSpan = container.GetValue( VariableSizedWrapGrid.RowSpanProperty );
int index;
try
{
dynamic model = item;
index = model.Index;
}
catch ( Exception )
{
index = -1;
}
long token = 0;
DependencyPropertyChangedCallback lambda = ( sender, dp ) =>
{
container.UnregisterPropertyChangedCallback( VariableSizedWrapGrid.RowSpanProperty, token );
var cp = (ContentControl) container;
cp.ContentTemplateSelector = null;
cp.ContentTemplateSelector = this;
};
token = container.RegisterPropertyChangedCallback( VariableSizedWrapGrid.RowSpanProperty, lambda );
switch ( rowSpan )
{
case 1:
return Small;
case 2:
return Medium;
case 3:
return Large;
default:
throw new InvalidOperationException( );
}
}
private void Foo( DependencyObject sender, DependencyProperty dp )
{
throw new NotImplementedException( );
}
}
}
在这里完成其他文件
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="Small">
<Grid Margin="5">
<Grid.Background>
<SolidColorBrush Color="{Binding Path=Color}"/>
</Grid.Background>
<StackPanel VerticalAlignment="Top">
<StackPanel.Background>
<SolidColorBrush Color="White" Opacity="0.75"/>
</StackPanel.Background>
<TextBlock FontSize="15" Margin="10">
<Run Text="{Binding Path=Index}"/>. <Run Text="{Binding Path=Name}"/>
</TextBlock>
<TextBlock Text="Small" TextAlignment="Center"/>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="Medium">
<Grid Margin="5">
<Grid.Background>
<SolidColorBrush Color="{Binding Path=Color}"/>
</Grid.Background>
<StackPanel VerticalAlignment="Top">
<StackPanel.Background>
<SolidColorBrush Color="White" Opacity="0.75"/>
</StackPanel.Background>
<TextBlock FontSize="15" Margin="10">
<Run Text="{Binding Path=Index}"/>. <Run Text="{Binding Path=Name}"/>
</TextBlock>
<TextBlock Text="Medium" TextAlignment="Center"/>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="Large">
<Grid Margin="5">
<Grid.Background>
<SolidColorBrush Color="{Binding Path=Color}"/>
</Grid.Background>
<StackPanel VerticalAlignment="Top">
<StackPanel.Background>
<SolidColorBrush Color="White" Opacity="0.75"/>
</StackPanel.Background>
<TextBlock FontSize="15" Margin="10">
<Run Text="{Binding Path=Index}"/>. <Run Text="{Binding Path=Name}"/>
</TextBlock>
<TextBlock Text="Large" TextAlignment="Center"/>
</StackPanel>
</Grid>
</DataTemplate>
<local:MyGridViewTemplateSelector x:Key="MyGridTemplateSelector"
Small="{StaticResource Small}"
Medium="{StaticResource Medium}"
Large="{StaticResource Large}"/>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- top left section -->
<Border Background="#D13438">
</Border>
<!-- top bar -->
<Border Grid.Column="1" Grid.Row="0" Padding="5" Background="#F2F2F2">
<TextBlock Text="MenuBar" VerticalAlignment="Center"/>
</Border>
<!-- left bar -->
<Border Grid.Column="0" Grid.Row="1" Width="48" Background="#2B2B2B">
</Border>
<!-- content -->
<Border Grid.Column="1" Grid.Row="1" Background="#E6E6E6">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Padding="5" Background="#F2F2F2">
<TextBlock Text="SectionBar" VerticalAlignment="Center"/>
</Border>
<ScrollViewer Grid.Row="1">
<Border Margin="7,7,10,7">
<!-- the wrapped news items -->
<local:MyGridView ItemsSource="{Binding}" ItemTemplateSelector="{StaticResource MyGridTemplateSelector}" MinItemWidth="300" MaxItemWidth="600" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid ItemHeight="180" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</local:MyGridView>
</Border>
</ScrollViewer>
</Grid>
</Border>
</Grid>
</Page>
using System.Linq;
using Windows.UI;
using Windows.UI.Xaml.Controls;
using System.Reflection;
namespace App1
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent( );
// just some sample data
var colors = typeof( Colors )
.GetRuntimeProperties( )
.Take( 140 )
.Select( ( x, index ) => new
{
Color = (Color) x.GetValue( null ),
Name = x.Name,
Index = index,
} );
this.DataContext = colors;
}
}
}
如果你会想到“我从某个地方知道”你应该看看Jerry Nixon's blog:o)
答案 3 :(得分:0)
事实证明,实现所需结果的最佳方法是编写自定义面板,并在ItemPanel
(或GridView
)中将其用作ListView
。
此控件可让您实现以下目标:
ItemMinWidth
属性自动计算的列数和列数(默认值为300px)。 GridView
VariableSizedWrapGrid
中整个面板的高度)MaxColumnCount
属性(例如,如果设置为4,列数可以是1,2,3或4)。 我的自定义面板(我称之为SmartPanel
,对此抱歉):
using System;
using System.Linq;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
class SmartPanel : Panel
{
int _colCount;
double _cellWidth;
double[] _cellHeights;
public static readonly DependencyProperty ItemMinWidthProperty = DependencyProperty.Register("ItemMinWidth", typeof(double), typeof(SmartPanel), new PropertyMetadata(300D));
public double ItemMinWidth
{
get { return (double)GetValue(ItemMinWidthProperty); }
}
public static readonly DependencyProperty MaxColumnCountProperty = DependencyProperty.Register("MaxColumnCount", typeof(int), typeof(SmartPanel), new PropertyMetadata(10));
public int MaxColumnCount
{
get { return (int)GetValue(MaxColumnCountProperty); }
set { SetValue(MaxColumnCountProperty, value); }
}
protected override Size MeasureOverride(Size availableSize)
{
_colCount = (int)(availableSize.Width / ItemMinWidth);
if (_colCount > MaxColumnCount) _colCount = MaxColumnCount;
_cellWidth = (int)(availableSize.Width / _colCount);
var rowCount = (int)Math.Ceiling((float)Children.Count / _colCount);
_cellHeights = new double[rowCount];
var y = 0;
var x = 0;
foreach (UIElement child in Children)
{
child.Measure(new Size(_cellWidth, double.PositiveInfinity));
_cellHeights[y] = Math.Max(_cellHeights[y], child.DesiredSize.Height);
x++;
if (x >= _colCount)
{
x = 0;
y++;
}
}
y = 0;
x = 0;
foreach (UIElement child in Children)
{
child.Measure(new Size(_cellWidth, _cellHeights[y]));
x++;
if (x >= _colCount)
{
x = 0;
y++;
}
}
if (double.IsInfinity(availableSize.Height))
{
availableSize.Height = _cellHeights.Sum();
}
return availableSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
double x = 0;
double y = 0;
int colNum = 0;
int rowNum = 0;
foreach (UIElement child in Children)
{
child.Arrange(new Rect(x, y, _cellWidth, _cellHeights[rowNum]));
//child.Arrange(new Rect(new Point(x, y), child.DesiredSize));
x += _cellWidth;
colNum++;
if (colNum >= _colCount)
{
x = 0;
y += _cellHeights[rowNum];
colNum = 0;
rowNum++;
}
}
return finalSize;
}
}
<强>用法:强>
<GridView x:Name="MainGrid" Grid.Row="1" Margin="0,20,0,20"
ItemsSource="{Binding Tiles}"
ItemTemplateSelector="{StaticResource TemplateSelector}"
>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="10" />
<Setter Property="Background" Value="White" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="Padding" Value="20" />
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ctl:SmartPanel Margin="10,0,10,0" MaxColumnCount="4" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>