I'm working on a WPF project build a couple of years ago.
One control is an expander control which groups a list of check-controls.
This list of check-controls is arranged from Left to Right, Top to Bottom by a WrapPanel!
Now my goal is to arrange the check-controls from Top to Bottom, Left to Right where the vertical wrap occurs at the bottom of the parent window! Any tips/directions in how to achieve this would be awsome!!
I have extracted the issue in a code example to highlight the issue.
Behavior of the example: The code example has the WrapPanel's orientation set to Horizontal. This is to show you what sort of behavior I would like to achieve! The wrap breaks at the Right side of the parent window and a new row starts. When the check-controls overflow the Bottom of the screen a vertical scrollbar appears.
Behavior I would like to achieve: When the Bottom side of the parent window is reached (when the wrappanel is set to Vertical orientation) I want the wrap to break and start at the Top again. When the check-controls overflow the Right side of the window I want a horizontal scrollbar to appear.
Example: In the code: change the Orientation attribute of the Wrappanel to Vertical. Notice that there is only one column overflowing all the way down, there is no wrap at the bottom of the window! Because I'm not sure how to attach a zip file (with the demo project) I have added the code files below. Creating a WPF application (.net framework 3.5) and copying the code in the proper locations should do. If you do have issues running the example I can always mail you a VS2010 solution!
Project called VerticalWrapPanel
UserControl CheckControl.xaml
<UserControl x:Class="VerticalWrapPanel.CheckControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Border BorderThickness="1,1,1,1" BorderBrush="Black">
<Label Content="{Binding Label}"/>
</Border>
</UserControl>
UserControl CheckGroupControl.xaml
<UserControl x:Class="VerticalWrapPanel.CheckGroupControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:VerticalWrapPanel"
x:Name="GroupControl">
<UserControl.Resources>
<DataTemplate x:Key="CheckTemplate">
<controls:CheckControl />
</DataTemplate>
</UserControl.Resources>
<Expander BorderBrush="Black" Header="TEST" IsExpanded="{Binding ElementName=GroupControl, Path=IsExpanded}">
<ItemsControl ItemsSource="{Binding Checks}" ItemTemplate="{StaticResource CheckTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Expander>
</UserControl>
CheckGroupControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace VerticalWrapPanel
{
/// <summary>
/// Interaction logic for CheckGroupControl.xaml
/// </summary>
public partial class CheckGroupControl : UserControl
{
public CheckGroupControl()
{
InitializeComponent();
}
public static DependencyProperty IsExpandedProperty = DependencyProperty.Register("IsExpanded", typeof(bool), typeof(CheckGroupControl));
public bool IsExpanded
{
get { return (bool)GetValue(IsExpandedProperty); }
set { SetValue(IsExpandedProperty, value); }
}
}
}
MainWindow.xaml
<Window x:Class="VerticalWrapPanel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:VerticalWrapPanel"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Window.Resources>
<DataTemplate x:Key="CheckGroupsTemplate">
<controls:CheckGroupControl />
</DataTemplate>
</Window.Resources>
<ScrollViewer CanContentScroll="False">
<ItemsControl ItemsSource="{Binding CheckGroups}" ItemTemplate="{StaticResource CheckGroupsTemplate}" />
</ScrollViewer>
</Window>
MainWindow.xaml.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
namespace VerticalWrapPanel
{
public class MyModel
{
public ObservableCollection<CheckGroup> CheckGroups { get; set; }
}
public class Check
{
public string Label { get; set; }
}
public class CheckGroup
{
public List<Check> Checks { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DataContext = new MyModel
{
CheckGroups = new ObservableCollection<CheckGroup>
{
new CheckGroup
{
Checks =
new List<Check>
{
new Check {Label = "Check 0001"}
,new Check {Label = "Check 0002"}
,new Check {Label = "Check 0003"}
,new Check {Label = "Check 0004"}
,new Check {Label = "Check 0005"}
,new Check {Label = "Check 0006"}
,new Check {Label = "Check 0007"}
,new Check {Label = "Check 0008"}
,new Check {Label = "Check 0009"}
,new Check {Label = "Check 0000"}
,new Check {Label = "Check 0002"}
,new Check {Label = "Check 0003"}
,new Check {Label = "Check 0004"}
,new Check {Label = "Check 0005"}
,new Check {Label = "Check 0006"}
,new Check {Label = "Check 0007"}
,new Check {Label = "Check 0008"}
,new Check {Label = "Check 0009"}
,new Check {Label = "Check 0000"}
,new Check {Label = "Check 0002"}
,new Check {Label = "Check 0003"}
,new Check {Label = "Check 0004"}
,new Check {Label = "Check 0005"}
,new Check {Label = "Check 0006"}
,new Check {Label = "Check 0007"}
,new Check {Label = "Check 0008"}
,new Check {Label = "Check 0009"}
,new Check {Label = "Check 0000"}
}
}
, new CheckGroup
{
Checks =
new List<Check>
{
new Check {Label = "Check 0011"}
,new Check {Label = "Check 0012"}
,new Check {Label = "Check 0013"}
,new Check {Label = "Check 0014"}
,new Check {Label = "Check 0015"}
,new Check {Label = "Check 0016"}
,new Check {Label = "Check 0017"}
,new Check {Label = "Check 0018"}
,new Check {Label = "Check 0019"}
,new Check {Label = "Check 0010"}
}
}
}
};
}
}
}
Try setting the VerticalScrollBarVisibility="Disabled"
and HorizontalScrollBarVisibility="Auto"
on the items control. This will disable the vertical scrolling. Also, alter the template of the items control to include a nice scroll viewer to enable scrolling.
<Expander BorderBrush="Black" Header="TEST" IsExpanded="{Binding ElementName=GroupControl, Path=IsExpanded}">
<ItemsControl ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Auto" ItemsSource="{Binding Checks}" ItemTemplate="{StaticResource CheckTemplate}">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Expander>
UPDATE
Your code is still going with one column of items - that is normal in your case. The XAML code I posted will only work if you constraint you top-level items' height (e.g. using Height
or MaxHeight
). My XAML code assumes that you have a limited amount of space for the expander and you are showing that expander within an ItemsControl which gives its items as much space as they want. For example, alter your data template to look as follows:
<Window.Resources>
<DataTemplate x:Key="CheckGroupsTemplate">
<controls:CheckGroupControl MaxHeight="100"/>
</DataTemplate>
</Window.Resources>
Now your expanders will have a maximum height and when it is reached they will start wrapping. Without that MaxHeight
the expander will be given the opportunity to take as much space as it wants and the WrapPanel inside it will, obviously, just lay out all the items in one vertical line since there is no constraint.