【问题标题】:WPF ListView items to be displayed with individual heightWPF ListView 项目以单独的高度显示
【发布时间】:2018-02-26 16:52:50
【问题描述】:

我目前正在尝试显示字典(保存在字典本身中)。

我一开始使用 UniformGrid 作为 ItemsPanelTemplate,但很快就意识到,要显示的项目可以有单独的高度。

到目前为止,我可以使用 UniformGrid 显示所有内容,但似乎无法使用 Grid 或 StackPanel 作为 ItemsPanelTemplate。

下面的代码工作正常,缺点是每个操作块都被赋予相同的高度,尽管它们的高度可以是可变的。 经过一番思考后,我得出的结论是最好使用 StackPanel,因为操作会显示为相互吹散,以达到他们需要的高度。但是当我尝试时,我发现它们只占用了 ListView 高度的一小部分。

值得一提: Operation-UserControl 本身确实会评估其高度并相应地构建其布局。所以它不会占用显示所有内容所需的空间,而是显示适合可用空间的内容。

那么我怎样才能使 ListViewItems (=operations) 占据 ListView 的全高?

编辑:澄清
如果上述任何控件都无法实现所描述的行为,但任何其他控件都可以提供所需的功能,请告诉我...

EDIT2:一些例子
总可用空间:500
没有滚动条。
旁注:没有 maxItemLimit,但 ItemCount 不太可能超过 10。

给定 1 项:(显示所有内容所需的空间 300)
单项需要 300。

给定 2 个项目:(这些将需要 150 和 200 个空间)
两个项目都将在那里显示全尺寸:150、200。
(大概只使用 StackPanel。)

给出 10 个项目:
这 10 个将与 500 个中的完整所需尺寸相同或相对于 500 个(因此每件 50 个)被挤压。
这两种行为都可以。

UniformGrid vs StackPanel

<UserControl x:Name="vDay" x:Class="RefServiceClient.Day"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:RefServiceClient"
        mc:Ignorable="d" 
        d:DesignHeight="60" d:DesignWidth="120"
        MinHeight="40">

<Grid x:Name="gridDay" 
      Width="{Binding ActualWidth, ElementName=vDay, Mode=OneWay}" 
      Height="{Binding ActualHeight, ElementName=vDay, Mode=OneWay}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Grid x:Name="DayHeader" Grid.Row="0">
        <!--containing header info: several textboxes, which are irrelevant for the question-->

        <TextBox x:Name="dayShortname"
                 Grid.Row="0" Grid.Column="1"
                 VerticalAlignment="Center"
                 HorizontalAlignment="Stretch"
                 Margin="1"
                 Text="{Binding Path=Value.DayShortname}"/>
    </Grid>

    <ListView x:Name="operations" Grid.Row="1" Background="Aqua"
              ItemsSource="{Binding Path=Value.OperationList}"
              HorizontalAlignment="Stretch"
              VerticalAlignment="Stretch"
              HorizontalContentAlignment="Stretch"
              VerticalContentAlignment="Stretch"
              ScrollViewer.HorizontalScrollBarVisibility="Disabled"
              ScrollViewer.VerticalScrollBarVisibility="Disabled">

        <ListView.ItemTemplate>
            <DataTemplate>
                <local:Operation Background="Crimson" VerticalContentAlignment="Stretch" VerticalAlignment="Stretch"/>
                <!--<local:Operation Background="Crimson" />-->
            </DataTemplate>
        </ListView.ItemTemplate>

        <ListView.ItemsPanel>
            <ItemsPanelTemplate>

                <!--<Grid Grid.IsSharedSizeScope="True"/>-->
                <!--<StackPanel/>-->
                <!--<VirtualizingStackPanel Orientation="Vertical"/>-->
                <UniformGrid Columns="1"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>

</Grid>

【问题讨论】:

  • 我认为问题在于您的local:Operation 实施。如果它需要适当的高度,ListViewStackPanel 作为项目面板将为每个列表项提供适当的空间。
  • @grek40 我可以跟着你。但是由于 ListView 可以容纳多个 local:Operation 并且可用的总空间保持不变,我认为只有一种解决方案:使 local:Operations 显示最少的内容(标题数据)并显示详细数据(如果更多)空间可用。否则(如果操作总是占用所需的空间)我将无法在没有滚动条的情况下显示所有 Operations
  • 您是否尝试过使用DataTemplate 代替StackPanel 而不是UserControl
  • 你真的必须澄清你想要的行为......如果我理解正确,给定一件物品和足够的空间,你会希望一件物品占用它需要的尽可能多的空间。给定 100 个项目和 500 个可用高度,您希望将 100 个项目压缩到 500 高度而不是使用滚动条。您尝试显示的内容是否有限制?当空间不足时,这 100 件物品的大小应该相等,还是应该根据所需的全部大小重新调整大小?
  • @XAMlMAX 不,我还没有尝试过。通过 userControl 仅通过 dataTemplate 路由。但我会试试的

标签: c# wpf listview


【解决方案1】:

您可以创建一个自定义面板,根据您的规则排列您的项目。然后,您只需设计您的商品,使其在允许的任何尺寸下都能很好地展示。

面板的粗略草图如下所示:

public class SqueezeStackPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        var desiredHeight = 0.0;
        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);
            desiredHeight += child.DesiredSize.Height;
        }

        if (availableSize.Height < desiredHeight)
        {
            // we will never go out of bounds
            return availableSize;
        }
        return new Size(availableSize.Width, desiredHeight);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        // measure desired heights of children in case of unconstrained height
        var size = MeasureOverride(new Size(finalSize.Width, double.PositiveInfinity));

        var startHeight = 0.0;
        var squeezeFactor = 1.0;
        // adjust the desired item height to the available height
        if (finalSize.Height < size.Height)
        {
            squeezeFactor = finalSize.Height / size.Height;
        }

        foreach (UIElement child in InternalChildren)
        {
            var allowedHeight = child.DesiredSize.Height * squeezeFactor;
            var area = new Rect(new Point(0, startHeight), new Size(finalSize.Width, allowedHeight));
            child.Arrange(area);
            startHeight += allowedHeight;
        }

        return new Size(finalSize.Width, startHeight);
    }
}

此面板可用于您的ListView 中的ItemsPanelTemplate,并禁用滚动条。

【讨论】:

  • 谢谢。我会尝试(可能与 Сергей Боголюбов 建议一起)并报告...
【解决方案2】:

这取决于。我会给你一个选择。第一的。实现,比如说,Boolean AttachedProperty,标记这个特定实例是否应该具有一定的大小。如果 0/1 不够,请声明适当的枚举。第二。扩展现有的 StackPanel,覆盖适当的受保护成员。至少,MeasureOverride/ArrangeOverride。在那里,您可以读取相应附加属性的值并决定它的大小。这听起来像是一个解决方案吗?如果是这样,我可以提供一些例子。

【讨论】:

  • 您在第 1 步中指的是哪个对象? ListView 或 ChildElement(=Operation)?除此之外,您还建议使用类似 grek40 的解决方案。只是你会扩展 StackPanel 而不是 Panel。扩展 StackPanel 而不是 Panel 有什么好处?
猜你喜欢
  • 1970-01-01
  • 2010-11-12
  • 1970-01-01
  • 2018-04-22
  • 1970-01-01
  • 2011-05-10
  • 1970-01-01
  • 2014-04-18
  • 1970-01-01
相关资源
最近更新 更多