我正在尝试在Windows 10中的默认新闻应用程序中创建一个gridview.据我所知,我必须为ItemSeight设置VariableSizedWrapGrid的ItemWidth.但是它不会拉伸项目以适应整个网格宽度,而新闻应用程序确实这样做,如下图所示.他们是怎么做到的?它是一种特殊的自定义控件吗?

我会给你一个概念:
+---------+ +---------+ +---------+ | 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来测试这个概念:
<Grid>
<ScrollViewer>
<ItemsControl>
<ItemsControl.Resources>
<Style x:Key="col" TargetType="WrapPanel">
<Setter Property="Orientation" Value="Vertical"/>
<Setter Property="ItemWidth" Value="80"/>
</Style>
<Style x:Key="content" TargetType="Border">
<Setter Property="Margin" Value="5,5"/>
</Style>
<Style x:Key="small" TargetType="Border" BasedOn="{StaticResource content}">
<Setter Property="Background" Value="Orange"/>
<Setter Property="Height" Value="30"/>
</Style>
<Style x:Key="medium" TargetType="Border" BasedOn="{StaticResource content}">
<Setter Property="Background" Value="Green"/>
<Setter Property="Height" Value="70"/>
</Style>
<Style x:Key="large" TargetType="Border" BasedOn="{StaticResource content}">
<Setter Property="Background" Value="Red"/>
<Setter Property="Height" Value="110"/>
</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 Style="{StaticResource 5col6items}">
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource small}"/>
<Border Style="{StaticResource small}"/>
</WrapPanel>
<!-- second row -->
<WrapPanel Style="{StaticResource 4col6items}">
<Border Style="{StaticResource large}"/>
<Border Style="{StaticResource large}"/>
<Border Style="{StaticResource large}"/>
<Border Style="{StaticResource small}"/>
<Border Style="{StaticResource small}"/>
<Border Style="{StaticResource small}"/>
</WrapPanel>
<!-- third row -->
<WrapPanel Style="{StaticResource 3col6items}">
<Border Style="{StaticResource large}"/>
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource large}"/>
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource large}"/>
</WrapPanel>
<!-- fourth row -->
<WrapPanel Style="{StaticResource 2col6items}">
<Border Style="{StaticResource large}"/>
<Border Style="{StaticResource large}"/>
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource small}"/>
<Border Style="{StaticResource medium}"/>
<Border Style="{StaticResource small}"/>
</WrapPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
Run Code Online (Sandbox Code Playgroud)
和相似的
一个非常简单的 ProofOfConcept,在调整大小时进行拉伸和模板化
<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>
Run Code Online (Sandbox Code Playgroud)
和代码隐藏
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( );
}
}
Run Code Online (Sandbox Code Playgroud)
最后结果
根据MSDN, ItemWidth 可以设置为 Auto。
ItemHeight和ItemWidth的默认值不是0,而是Double.NaN。ItemHeight 和 ItemWidth 支持成为未设置的“自动”值。由于 ItemHeight 和 ItemWidth 是 Double 值,因此使用 Double.NaN 作为特殊值来表示此“自动”行为。布局系统将“自动”值解释为通常意味着对象的大小应调整为布局中的可用大小,而不是特定的像素值。
我不知道这是否会导致您想要的行为。如果没有,那么您可以通过将 ItemWidth 绑定到一个属性来获取它,在该属性中您可以根据网格的宽度计算项目宽度。它看起来像这样:
float DynamicItemWidth {
get {
int ItemMinimumWidth = 300, margin = 16; //just some guesses
var gridWidth = ...;
var numberOfColumns = gridWidth % ItemMinimumWidth;
var itemWidth = (gridWidth - margin * (numberOfColumns - 1)) / numberOfColumns;
return itemWidth;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
630 次 |
| 最近记录: |