Search code examples
uwpuwp-xamlwindows-community-toolkitwinuivariablesizedwrapgrid

WinUI list control that allows for dynamic item size, reordering, and virtualization


I am trying to implement a document editor similar to Notion or Craft but in a WinUI/UWP application. Instead of using a "single-field" editor (like MS Word has), these apps show a vertical stack of content rows (so-called "blocks") that can contain text, media, link previews, LaTeX, etc. These rows can be rearranged with a :: handle on the side:

Notion UI recording

So I've been looking for some list/stack control that:

  • Recycles the row views that are not visible (i.e. "virtualization" in the XAML terminology).
  • Allows to reorder rows by dragging and dropping them (single or multiple).
  • Automatically adjusts row heights based on their content growing or shrinking in height (due to the user's input or because the app's window resized horizontally and wrapped some content).

Features I do not need: headers, columns, sorting, filtering. I have reviewed the following controls in WinUI 2.x and Windows Community Toolkit, but it looks like each of them lacks one or more of the required capabilities.

ListView

It seems to be the go-to control for the lists with drag'n'drop, but it can't resize the items dynamically. Also, its dragging uses the whole item area while I need to make it available only with a :: handle on the side.

ItemsStackPanel

A virtualization-supporting version of StackPanel, but, as far as I understand, panels are supposed to be used for simple layouting of child items and not for presenting long lists based on a data source.

VariableSizedWrapGrid

This is the only list/grid control that officially declares the support of variable-sized items, but at the same time, it does not support virtualization. However, I found a solution from 2013 that is based on pre-calculating the content size for invisible elements.

ItemsRepeater

A very basic control that does not provide virtualization on its own: "ItemsRepeater supports virtualization when attached to a host that supports virtualization."

DataGrid

A rather heavy control from WCT that seems to be the only one to dynamically resize cells depending on their content. Unfortunately, it does not allow row reordering (only sorting), so I can't use it either.


Did I miss something? If not, I wonder which one would be the best to build upon. Thanks!


Solution

  • It turns out, a ListView can resize its items dynamically – one just needs to put a StackPanel inside a ListViewItem because a stack "pushes" its parent's size outwards. As this answer says:

    Container controls like Grid and RelativePanel automatically scale to the full available size of their parent, while others like StackPanel only grow to the minimal size needed for their child elements.

    Also, adding a TextBox inside a ListViewItem overrides the dragging behavior with text input behavior, but the list item is still draggable outside the text box. I can leave it like this or reduce the draggable area to the :: handle by following Arya's answer.