Search code examples
wpfwrappanel

ItemsControl (WrapPanel) Grouping should split GroupItems


I have a ItemsControl with a WrapPanel as ItemsHost and multiple Groupings. Got this going so far with the following Templates:

<GroupStyle.ContainerStyle>
   <Style TargetType="GroupItem">
      <Setter Property="Template">
         <Setter.Value>
            <ControlTemplate TargetType="GroupItem">
               <Grid>
                  <Grid.RowDefinitions>
                     <RowDefinition Height="Auto" />
                     <RowDefinition Height="*" />
                  </Grid.RowDefinitions>
                  <ContentPresenter Grid.Row="0" x:Name="PART_Header" Content="{TemplateBinding Content}" />
                  <ItemsPresenter Grid.Row="1" />
               </Grid>
            </ControlTemplate> 
         </Setter.Value>
      </Setter>
   </Style>
</GroupStyle.ContainerStyle>
<GroupStyle.Panel>
   <ItemsPanelTemplate>
      <WrapPanel IsItemsHost="True" Orientation="Vertical" />
   </ItemsPanelTemplate>
</GroupStyle.Panel>

Now I have the Problem that every Group does start a new Column why I want it to Continue right under the last GroupItem and Wrap in the Middle of the GroupItem instead of at the beginning.

It should look like the Windows 8 Apps overview (not the start page, if you go down to the overview)

Is that possible?


Solution

  • I solved this in the ViewModel instead. I add a GroupItem into the ObservableCollection that is styled like a (Expandable) GroupHeader. Than I added a seperate DataTemplate for the GroupHeader that sets a IsCollapsed property on the Group. All Items do now have a reference to the parent Group and bind the Visibility to the IsCollapsed property of the Parent Group.

    Sadly i was not able to achive this using the CollectionViewSource.

    This is the XAML:

    <ItemsControl ItemsSource="{Binding Items}">
        <ItemsControl.DataContext>
            <local:ViewModel/>  
       </ItemsControl.DataContext>
       <ItemsControl.Resources>
           <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
           <DataTemplate DataType="{x:Type local:GroupViewModel}">
               <StackPanel>
                   <CheckBox IsChecked="{Binding IsExtended}" />
                   <!--Restyle to look like a extender-->
               </StackPanel>
           </DataTemplate>
           <DataTemplate DataType="{x:Type local:ItemViewModel}">
               <TextBlock Text="{Binding Name}" 
                   Visibility="{Binding Group.IsExtended, Converter={StaticResource BooleanToVisibilityConverter}}"/>
           </DataTemplate>
       </ItemsControl.Resources>
    </ItemsControl>
    

    This is the ViewModel:

    public class ViewModel
    {
        public ViewModel()
        {
            //Some Test data
            GroupViewModel group1 = new GroupViewModel("Group1");
            GroupViewModel group2 = new GroupViewModel("Group2");
    
            this.Items = new ObservableCollection<object>(new[]
            {
                new ItemViewModel("Item1", group1),
                new ItemViewModel("Item2", group1),
                new ItemViewModel("Item3", group2),
                new ItemViewModel("Item4", group2)
            });
    
            string groupName = string.Empty;
            foreach (ItemViewModel item in this.Items.ToArray())
            {
                //Insert Group headers
                if (item.Group.Name != groupName)
                {
                    groupName = item.Group.Name;
                    this.Items.Insert(this.Items.IndexOf(item), item.Group);
                }
            }
        }
    
        public ObservableCollection<object> Items { get; }
    }
    
    
    public class GroupViewModel : ViewModelBase
    {
        private bool isExtended = true;
    
        public GroupViewModel(string name)
        {
            this.Name = name;
        }
    
        public string Name { get; }
    
        public bool IsExtended
        {
            get { return this.isExtended; }
            set { this.SetProperty(ref this.isExtended, value); }
        }
    }
    
    public class ItemViewModel
    {
        public ItemViewModel(string name, GroupViewModel group)
        {
            this.Name = name;
            this.Group = group;
        }
    
        public string Name { get; }
        public GroupViewModel Group { get; }
    }