ListBox Grouping WPF - c#

I'm trying to group a listbox. And all I can get to show up is the header.
I've got a list list of 'Online Users' , which look like this.
public class OnlineUser{
public string Branch {get;set;}
public string FirstName{get;set;}
public string LastName{get;set;}
}
Then i populate the list with some users, and put that list into a ICollectionView 'FilterableOnlineUsers'
FilterableOnlineUsers = CollectionViewSource.GetDefaultView(OnlineUsers);
FilterableOnlineUsers.GroupDescriptions.Add(new PropertyGroupDescription("Branch"));
FilterableOnlineUsers.SortDescriptions.Add(new SortDescription("Branch", ListSortDirection.Descending));
And in my Xaml:
<ListBox SelectedItem="{Binding DataContext.SelectedUser" ItemsSource="{Binding DataContext.FilterableOnlineUsers" >
<ListBox.GroupStyle>
<GroupStyle />
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="FirstName"></Binding>
<Binding Path="LastName"></Binding>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
All I can get to show up in the Listbox is the branch name. I can't get first name or lastname to show up underneath the group Descriptions..
Thanks.

You should define a CollectionViewSource in XAML resource Like Below and make the ItemsSource set to the CollectionViewSource,
<CollectionViewSource x:Key="ListBoxItems" Source="{Binding Path=ListOfOnlineUser}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Branch" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
In List Box
<ListBox ItemsSource="{Binding Source={StaticResource ListBoxItems}}"/>
Detail
Below is the ListBox show grouped branch and each branch is inside an expander which you can collapse and expand each groups.
<ListBox
Margin="0,0,5,0"
ItemsSource="{Binding Source={StaticResource ListBoxItems}}"
SelectedIndex="-1"
SelectedItem="{Binding SelectedBranch}">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander
Padding="0"
BorderThickness="0"
Header="{Binding Name}"
IsExpanded="True">
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text="{Binding LastName}" />
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

Related

Listbox : listboxitem with group and without group listboxitem

So I am using list box as a side navigation bar
I am trying to sort my listbox from this
Listboxitem 1 (Home)
Listboxitem 2 (Log out)
Group with expander (Accounting) with listboxitems children(Sales, Product)
to this :
Listboxitem 1 (Home)
Group with expander (Accounting) with listboxitems children(Sales, Product)
Listboxitem 2 (Log out)
but I cant seem to sort the 3 items based on their index in itemsource.
Basically this is listbox I am trying to achieve
This is how I added the items in my listbox
public ObservableCollection<ContentObject> ContentItems { get; set; } = new ObservableCollection<ContentObject>();
public MainWindowViewModel()
{
ChangeToggleStateCommand = new RelayCommand(action => { IsMenuToggleEnabled = false;});
ContentItems.Add(new ContentObject("Home", new HomeView(), MaterialDesignThemes.Wpf.PackIconKind.Home,"None"));
ContentItems.Add(new ContentObject("Sales", new SalesView(), MaterialDesignThemes.Wpf.PackIconKind.CashMultiple, "Accounting"));
ContentItems.Add(new ContentObject("Product", new ProductsView(), MaterialDesignThemes.Wpf.PackIconKind.CubeOutline, "Accounting"));
ContentItems.Add(new ContentObject("Log out", new SalesView(), MaterialDesignThemes.Wpf.PackIconKind.Logout, "None"));
}
The list box XAML CODE
<ListBox x:Name="ContentList" Margin="0 16 0 16" SelectedIndex="0" ItemsSource="{Binding Source={StaticResource ListBoxItems}}" >
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="False">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="15" Text="{Binding Name}" Margin="15 15" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Name}" Value="None">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel>
<ItemsPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0">
<Grid>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="{Binding Icon}" Height="15" Width="15" Margin="15 15" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock FontSize="15" Text="{Binding Title}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding ChangeToggleStateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
Here's how I grouped my ContentItems
<Window.Resources>
<CollectionViewSource x:Key="ListBoxItems" Source="{Binding Path=ContentItems,UpdateSourceTrigger=PropertyChanged}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Category"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
Based on the way I implemented it. the default template is tagged to category :None
.Wpf is assuming that none is also a group containing Home and Logout thus the treating it as a group without a header. that is why I am not able to separate the two listboxitems. Is there another way to separate this or implement this?
I found a similar question but sorting was not addressed
WPF Listbox grouping, items with no groups
Test the code here : https://github.com/asdtgb/NavigatorTest

How do I add a Label over a ListBox in WPF?

I have currently a ListBox in a DockPanel (that represents a wonderful Diaballik game) and at the end I want to be able to show up a label Victory over the grid made by the boxes like in the picture :
<DockPanel>
<ListBox DockPanel.Dock="Top" ItemsSource="{Binding Cases}" SelectedItem="{Binding SelectedCase, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Top" SnapsToDevicePixels="True">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding Size}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="0"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid >
<Ellipse Fill="{Binding Color}" Width="50" Height="50" Visibility="{Binding HasPawn, Converter={StaticResource bool2visibility}}"/>
...
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Label Content="VICTORY" /> <!-- How can this go over the list box ? -->
</DockPanel>
You could do something like this (the behaviour of a Grid is such that it will just "stack" the items "on top" of each other):
<DockPanel>
<Grid DockPanel.Dock="Top">
<ListBox ItemsSource="{Binding Cases}" SelectedItem="{Binding SelectedCase, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Top" SnapsToDevicePixels="True">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding Size}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="0"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid >
<Ellipse Fill="{Binding Color}" Width="50" Height="50" Visibility="{Binding HasPawn, Converter={StaticResource bool2visibility}}"/>
...
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Label Content="VICTORY" HorizontalAlignment="Center" VerticalAlignment="Center" /> <!-- How can this go over the list box ? -->
</Grid>
</DockPanel>

How To Grouping Data In WPF DataGrid

In my WPF Application i'm having datagrid in this datagrid i want to grouping up data from database based on column name called "City" ,i'm not using mvvm architecture and list method,I'm Using ICollectionView and passed datatable object as a parameter,This is my c# code
ICollectionView cv = CollectionViewSource.GetDefaultView(dt);
cv.GroupDescriptions.Add(newPropertyGroupDescription("City"));
Hotels.ItemsSource = cv;
And This is my XAML Code:
<Window.Resources>
<Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel>
<TextBlock Text="{Binding City}" Name="grouping" Foreground="Black"></TextBlock>
<ItemsPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DataGrid Background="Azure" ItemsSource="{Binding Hotels}" CanUserAddRows="False" Name="Hotels" Style="{StaticResource AzureDataGrid}" Margin="0,173,0,0">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource ResourceKey=GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
It does not display text in textblock i'm binding Textblock with column name but it does't works...Please help me
If you don't use viewmodel for each item, but DataTable's row object, WPF can't recognize the name "City". You need to use group's name which is held by CollectionViewGroupInternal.Name property of object representing a group item. In this particular scenario it's the name of the city. Just bind Name to your TextBlock.
You can achieve your goal in less lines of code using group's HeaderTemplate. Default ItemPresenter will be visible below the Header.
<!-- resources -->
<CollectionViewSource x:Key="devicesCollection" IsLiveSortingRequested="True" IsLiveGroupingRequested="True" Source="{Binding MyCollection}">
<!-- Sorting -->
<CollectionViewSource.SortDescriptions>
<componentModel:SortDescription PropertyName="Id" />
</CollectionViewSource.SortDescriptions>
<!-- Grouping -->
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="City"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="GroupingHeader">
<Border Background="Gray">
<TextBlock Margin="10 5 5 5" FontSize="12" FontWeight="Bold" Text="{Binding Name}"/>
</Border>
</DataTemplate>
<!-- data grid -->
<DataGrid ItemsSource="{Binding Source={StaticResource ResourceKey=devicesCollection}, Mode=OneWay}">
<DataGrid.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource ResourceKey=GroupingHeader}" />
</DataGrid.GroupStyle>
</DataGrid>

How to add ItemsSource to Combobox nested in ListBox Template from codebehind?

I have some problem with ComboBox nested in ListBox. I want to add the same ItemsSource(gained from database, adding from codebehind) to each of comboboxes created in ListBox, but don't know how. Any ideas how to do this?
</Window.Resources>
<Style x:Key="lbxKey" TargetType="ListBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type Type1}">
<StackPanel Orientation="Horizontal" Width="Auto" HorizontalAlignment="Stretch">
<TextBlock TextTrimming="CharacterEllipsis" Width="200" Text="{Binding NAMETYPE1}" HorizontalAlignment="Left"></TextBlock>
<ComboBox HorizontalAlignment="Stretch" Tag="{Binding IDTYPE1}">
<ComboBox.ItemsSource>
<!-- no idea what should be here or even if this is needed -->
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type Type2}">
<StackPanel Orientation="Horizontal" Width="100">
<TextBlock Text="{Binding NAMETYPE2}" TextTrimming="CharacterEllipsis"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
In codebehind:
lbxListbox.ItemsSource = observableCollectionFromDatabase;
//here should be sth to set ItemsSource for comboboxes in ListBox
There should be a collection type property in your item class (anything that implements IEnumerable will do). Then you would bind the ComboBox's ItemSource like this:
<ComboBox Tag="{Binding IDTYPE1}" ItemsSource="{Binding ITEMS}" ...>

WPF Expander Order by GroupItem count

I have a WPF app with search functionality, and data is bind to data grid. i am grouping the data by table name. how can i sort the expander header by descending order. how to show max count group on top.
XAML code.
</DataGrid.Columns>
<DataGrid.GroupStyle>
<!--Default GroupStyle-->
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Padding="3"/>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp"
BorderBrush="#FFA4B97F"
BorderThickness="0,0,0,1"
IsExpanded="{Binding Path=Items[0].IsExpanded}">
<Expander.Header>
<DockPanel TextBlock.FontWeight="Bold">
<TextBlock Text="{Binding Name}" Margin="5,0,5,0" Foreground="Blue" />
<TextBlock Text=" (" />
<TextBlock Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" Items )" />
</DockPanel>
</Expander.Header>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
Sort the databound list in your ViewModel. Order by item count after the list is populated.

Categories