问题描述
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ListView ItemsSource="{Binding ItemCollection}" Height="160" Width="810">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="500" Height ="150" ItemWidth="100" ItemHeight="30"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Checked}">
<TextBlock Text="{Binding Label}"/>
</CheckBox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
代码显示每个CheckBox
的宽度为100。WrapPanel
中的每一行由于其大小和CheckBox
最多可包含5个ItemWidth
es (500/100)。
我不想将ItemWidth
显式设置为280,因为大多数项目都较小。相反,我希望每个CheckBox
占用100的整数倍,可以显示其所有内容。如果WrapPanel
中的当前行没有足够的空间,则将其移至下一行。
对于上面的样本宽度,我希望如此。
- 宽度
- 宽度
- 宽度> 300和
我该如何实现?
解决方法
ItemWidth
明确定义了所有项目的宽度。
一个Double,代表WrapPanel中包含的所有项目的统一宽度。默认值为NaN。
不不要设置ItemWidth
。然后每个项目都占据其各自的大小。
WrapPanel的子元素可能具有明确设置的width属性。 ItemWidth指定WrapPanel为子元素保留的布局分区的大小。结果, ItemWidth优先于元素自身的宽度。
现在,如果您没有明确地定义项目的宽度,则它们的大小将适合其内容,但不会与100
的倍数对齐。 WrapPanel
不支持将项目自动缩放为已定义大小的倍数。
如果要启用这种动态大小调整,则必须创建一个自定义包装面板,也可以编写自定义行为。我为您展示了后者的示例,因为它可重用且更灵活。我使用Microsoft.Xaml.Behaviors.Wpf
NuGet程序包,该程序包包含该程序的基类。
public class AlignWidthBehavior : Behavior<FrameworkElement>
{
public static readonly DependencyProperty AlignmentProperty = DependencyProperty.Register(
nameof(Alignment),typeof(double),typeof(AlignWidthBehavior),new PropertyMetadata(double.NaN));
public double Alignment
{
get => (double)GetValue(AlignmentProperty);
set => SetValue(AlignmentProperty,value);
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.LayoutUpdated += OnLayoutUpdated;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.LayoutUpdated -= OnLayoutUpdated;
}
private void OnLayoutUpdated(object sender,EventArgs e)
{
var size = AssociatedObject.ActualWidth;
var alignment = Alignment;
var isAligned = size % alignment < 10E-12;
if (!double.IsNaN(alignment) && !isAligned)
AssociatedObject.Width = Math.Ceiling(size / alignment) * alignment;
}
}
当项目的布局更改时,将触发此行为。然后,它检查关联项目的宽度是否与Alignment
属性给定的值对齐,如果没有,请对其进行调整。
<DataTemplate>
<CheckBox IsChecked="{Binding Checked}">
<b:Interaction.Behaviors>
<local:AlignWidthBehavior Alignment="100"/>
</b:Interaction.Behaviors>
<TextBlock Text="{Binding Label}"/>
</CheckBox>
</DataTemplate>
您必须如上所述将行为附加到XAML中,并将Alignment
设置为所需的值,并且不要忘记从ItemWidth
中删除WrapPanel
属性。