首页 > 解决方案 > WrapPanel中动态调整ItemWidth

问题描述

我正在使用 WPF MVVM。我有以下代码:

<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。由于其大小和(500 / 100) ,每行WrapPanel最多可以包含 5 个es。CheckBoxItemWidth

我有多个CheckBox不同宽度的。

我不想ItemWidth明确地将其设置为 280,因为大多数项目都较小。相反,我希望每个CheckBox都占用 100 倍的空间来显示其所有内容。如果当前行中WrapPanel没有足够的空间,则将其移至下一行。

对于上面的样本宽度,我期望这一点。

我怎样才能做到这一点?

标签: wpfwrappanel

解决方案


明确定义所有项目的ItemWidth宽度。

一个 Double,表示WrapPanel 中包含的所有项目的统一宽度。默认值为 NaN。

不要 设置. _ ItemWidth然后每个项目占据其单独的大小。

WrapPanel 的子元素可以显式设置其宽度属性。ItemWidth 指定 WrapPanel 为子元素保留的布局分区的大小。因此,ItemWidth 优先于元素自身的 width

现在,如果您没有明确定义项目的宽度,它们的大小将适合其内容,但不与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为您想要的值,并且不要忘记ItemWidthWrapPanel.


推荐阅读