You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为WrapPanel每行动态设置ListViewItem高度?

解决方案:让WrapPanel布局的ListView每行Item高度统一+优化拖拽体验

一、自定义统一高度的WrapPanel

WrapPanel默认不会同步同行子项的高度,因此需要自定义一个UniformHeightWrapPanel,重写ArrangeOverride方法实现每行高度统一:

public class UniformHeightWrapPanel : WrapPanel
{
    protected override Size ArrangeOverride(Size finalSize)
    {
        var rows = new List<List<UIElement>>();
        var currentRow = new List<UIElement>();
        double currentWidth = 0;

        // 先将元素按行分组
        foreach (UIElement child in InternalChildren)
        {
            Size desiredSize = child.DesiredSize;
            if (currentWidth + desiredSize.Width > finalSize.Width && currentRow.Count > 0)
            {
                rows.Add(currentRow);
                currentRow = new List<UIElement>();
                currentWidth = 0;
            }
            currentRow.Add(child);
            currentWidth += desiredSize.Width + ItemWidth;
        }
        if (currentRow.Count > 0)
            rows.Add(currentRow);

        // 排列每行元素,统一使用该行最大高度
        double y = 0;
        foreach (var row in rows)
        {
            double maxHeight = row.Max(child => child.DesiredSize.Height);
            double x = 0;
            foreach (UIElement child in row)
            {
                Size desiredSize = child.DesiredSize;
                child.Arrange(new Rect(x, y, desiredSize.Width, maxHeight));
                x += desiredSize.Width + ItemWidth;
            }
            y += maxHeight + ItemHeight;
        }

        return finalSize;
    }
}

在XAML中替换原WrapPanel:

<ListView.ItemsPanel>
    <ItemsPanelTemplate>
        <local:UniformHeightWrapPanel Orientation="Horizontal" />
    </ItemsPanelTemplate>
</ListView.ItemsPanel>

二、让Item内容拉伸填充高度

确保ListViewItem及内部嵌套ListView的布局设置正确:

  1. 给ListViewItem设置VerticalContentAlignment="Stretch",内部容器(如Grid)也需设置VerticalAlignment="Stretch":
<ListView.ItemTemplate>
    <DataTemplate>
        <Grid VerticalAlignment="Stretch">
            <!-- 其他内容 -->
            <ListView ItemsSource="{Binding PeopleList}" 
                      VerticalAlignment="Stretch"
                      VerticalContentAlignment="Stretch">
                <!-- 嵌套ListView的ItemTemplate -->
            </ListView>
        </Grid>
    </DataTemplate>
</ListView.ItemTemplate>
  1. 禁用嵌套ListView的垂直滚动,避免滚动条限制高度拉伸:
<ListView ItemsSource="{Binding PeopleList}" 
          ScrollViewer.VerticalScrollBarVisibility="Disabled"
          VerticalAlignment="Stretch">

三、优化拖拽体验

  1. 添加拖拽预览:拖拽时生成原元素的半透明副本作为预览,避免原元素消失导致布局跳动:
private void ListView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var listView = sender as ListView;
    var item = FindAncestor<ListViewItem>((DependencyObject)e.OriginalSource);
    if (item == null) return;

    var data = listView.ItemContainerGenerator.ItemFromContainer(item);
    var dragData = new DataObject(typeof(string), (data as Person).Name);

    // 创建拖拽预览视觉元素
    var visual = new DrawingVisual();
    using (var dc = visual.RenderOpen())
    {
        var brush = new VisualBrush(item);
        dc.DrawRectangle(brush, null, new Rect(new Point(), item.RenderSize));
    }
    DragDrop.DoDragDrop(item, dragData, DragDropEffects.Move);
}

private T FindAncestor<T>(DependencyObject current) where T : DependencyObject
{
    do
    {
        if (current is T ancestor)
            return ancestor;
        current = VisualTreeHelper.GetParent(current);
    } while (current != null);
    return null;
}
  1. 目标区域高亮:拖拽进入目标Item时添加边框高亮,明确可放置区域:
private void ListViewItem_DragEnter(object sender, DragEventArgs e)
{
    var item = sender as ListViewItem;
    item.BorderThickness = new Thickness(2);
    item.BorderBrush = Brushes.Blue;
}

private void ListViewItem_DragLeave(object sender, DragEventArgs e)
{
    var item = sender as ListViewItem;
    item.BorderThickness = new Thickness(0);
}

private void ListViewItem_Drop(object sender, DragEventArgs e)
{
    var item = sender as ListViewItem;
    item.BorderThickness = new Thickness(0);
    // 处理数据移动逻辑
}
  1. 暂停实时布局更新:拖拽期间禁用WrapPanel的布局更新,避免卡顿,拖拽结束后恢复:
private void DragStarted()
{
    var wrapPanel = FindVisualChild<UniformHeightWrapPanel>(mainListView);
    wrapPanel.IsHitTestVisible = false;
    wrapPanel.ArrangeOverride(new Size(double.PositiveInfinity, double.PositiveInfinity));
}

private void DragCompleted()
{
    var wrapPanel = FindVisualChild<UniformHeightWrapPanel>(mainListView);
    wrapPanel.IsHitTestVisible = true;
    mainListView.UpdateLayout();
}

内容的提问来源于stack exchange,提问作者horst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:53:10