【问题标题】:WinUI list control that allows for dynamic item size, reordering, and virtualizationWinUI 列表控件,允许动态项目大小、重新排序和虚拟化
【发布时间】:2021-06-29 18:21:54
【问题描述】:

我正在尝试在 WinUI/UWP 应用程序中实现类似于 Notion 或 Craft 的文档编辑器。这些应用程序没有使用“单字段”编辑器(如 MS Word 那样),而是显示垂直堆栈的内容行(所谓的“块”),其中可以包含文本、媒体、链接预览、LaTeX 等。这些行可以用侧面的:: 句柄重新排列:

所以我一直在寻找一些列表/堆栈控件:

  • 回收不可见的行视图(即 XAML 术语中的“虚拟化”)。
  • 允许通过拖放(单个或多个)对行重新排序。
  • 根据内容高度的增长或缩小自动调整行高(由于用户的输入或应用的窗口水平调整大小并包裹了一些内容)。

我确实不需要需要的功能:标题、列、排序、过滤。我已经查看了 WinUI 2.x 和 Windows Community Toolkit 中的以下控件,但看起来它们中的每一个都缺少一个或多个必需的功能。

ListView

它似乎是拖放列表的首选控件,但它不能动态调整项目的大小。此外,它的拖动使用了整个项目区域,而我需要使其仅在侧面带有 :: 句柄时可用。

ItemsStackPanel

StackPanel 的虚拟化支持版本,但据我了解,面板应该用于子项的简单布局,而不是用于基于数据源呈现长列表。

VariableSizedWrapGrid

这是唯一一个官方声明支持可变大小项目的列表/网格控件,但同时不支持虚拟化。但是,我发现了一个solution from 2013,它基于预先计算不可见元素的内容大小。

ItemsRepeater

一个非常基本的控件,它本身不提供虚拟化:“ItemsRepeater 在连接到支持虚拟化的主机时支持虚拟化。”

DataGrid

来自 WCT 的相当重的控制,这似乎是 dynamically resize cells 的唯一一个,具体取决于其内容。不幸的是,它不允许行重新排序(仅排序),所以我也不能使用它。


我错过了什么吗?如果没有,我想知道哪一个是最好的基础。谢谢!

【问题讨论】:

    标签: uwp uwp-xaml windows-community-toolkit winui variablesizedwrapgrid


    【解决方案1】:

    我不得不说没有任何控制可以满足所有的要求。其实::是用来控制darg指定的item,在ListView控件中也可以实现类似的行为。

    ListView 允许您通过将 CanReorderItemsAllowDrop 属性设置为 True 来轻松地重新排序 ListView 中的项目。如果您不想让用户拖动特定项目,您可以将CanDragItems 属性设置为True,并为DragItemsStarting 事件添加事件处理程序。对于事件处理程序,您可以检查任何条件,然后如果要取消拖动操作,只需将事件参数的 Cancel 属性设置为 true。如下:

    Xaml 代码:

    <ListView x:Name="TargetListView"              
                    CanReorderItems="True" CanDragItems="True" AllowDrop="True"         DragItemsStarting="TargetListView_DragItemsStarting">
    
                <ListViewItem>
                    <TextBlock x:Name="item1" Text="item1"/>
                </ListViewItem>
                <ListViewItem >
                    <TextBlock x:Name="item2" Text="item2"/>
                </ListViewItem>
                <ListViewItem>
                    <TextBlock x:Name="item3" Text="item3"/>
                </ListViewItem>
              
      </ListView>
    

    后面的代码:

    private void TargetListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
            {
                e.Cancel = e.Items.Any(o =>
                {
                    if (o is TextBlock t && t.Name.ToString() == "item2")
                        return true;
    
                    return false;
                });
            }
    

    如您所见,ListView中有3个textBlock,名为item2的textblock的拖拽动作会受到限制。

    【讨论】:

    • 我添加了一个赏金,然后在 .NET Discord 的帮助下自己解决了这个问题,所以它交给了你! :)
    • 很高兴听到您的问题已得到解决。祝你一切顺利。
    【解决方案2】:

    事实证明,ListView 可以动态调整其项目的大小 - 只需将 StackPanel 放入 ListViewItem 中,因为堆栈会向外“推”其父项的大小。正如this answer 所说:

    GridRelativePanel 这样的容器控件会自动缩放到其父元素的完整可用大小,而像 StackPanel 这样的其他容器控件只会增长到其子元素所需的最小大小。

    此外,在ListViewItem 内添加TextBox 会使用文本输入行为覆盖拖动行为,但列表项仍可拖动到文本框外。我可以保持这样,也可以按照Arya's answer 将可拖动区域缩小到:: 句柄。

    【讨论】:

      猜你喜欢
      • 2021-07-31
      • 2011-01-18
      • 1970-01-01
      • 1970-01-01
      • 2011-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多