Search code examples
c#wpftreeview

WPF Treeview with dynamic orientation when resizing horizontally


Is this possible to do from initial view :

Header1

  • item1
  • item2
  • item3

Header2

  • item1
  • item2

When resizing the window horizontally, the items also adjusts from vertical to horizontal :

Header1

  • item1 - item2
  • item3

Header2

  • item1 - item2

The succeeding items are moved to the next horizontal position depending on the window size. That is if in full screen, the items are all lined up horizontally and any excess items will be on the next row.
Example :
Header3
-item1 -item2 -item3 -item4 ...
-item11 -item12 -item13

If possible, how can this be done? Thanks!


Solution

  • From your description I guess that you want to display hierarchical data, so I use a TreeView with static items to demonstrate how it can be done, but it works the same for dynamic data.

    <TreeView ScrollViewer.HorizontalScrollBarVisibility="Disabled">
       <TreeView.ItemContainerStyle>
          <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
             <Setter Property="ItemsPanel">
                <Setter.Value>
                   <ItemsPanelTemplate>
                      <WrapPanel/>
                   </ItemsPanelTemplate>
                </Setter.Value>
             </Setter>
          </Style>
       </TreeView.ItemContainerStyle>
       <TreeViewItem Header="Header 1">
          <TreeViewItem Header="Item 1"/>
          <TreeViewItem Header="Item 2"/>
          <TreeViewItem Header="Item 3"/>
       </TreeViewItem>
       <TreeViewItem Header="Header 2">
          <TreeViewItem Header="Item 1"/>
          <TreeViewItem Header="Item 2"/>
       </TreeViewItem>
    </TreeView>
    

    The key to make this work is using a WrapPanel as ItemsPanel of the TreeViewItems. A wrap panel will put items in the next line if they exceed the available space.

    Positions child elements in sequential position from left to right, breaking content to the next line at the edge of the containing box.

    The ItemContainerTemplate will apply this panel to all TreeViewItems. Disabling horizontal scrolling is necessary, because otherwise the items would be given as much space as they need (measured with positive infinity) and hence the items would not wrap. I do not assign the WrapPanel to the TreeView itself, as that would wrap the headers, too.

    Of course you could use other controls than a TreeView, but the concept is the same.