Combobox not showing groupings - c#

I'm trying to organize the items in a combobox into groups. To do this I've created an object that has project and group name strings. I then set the GroupStyle and ItemTemplate to display these values. However, Currently, only the project string is displayed in the combobox (and the box has a red border, indicating some kind of error).
Here's the xaml for my combobox:
<ComboBox x:Name="comboBoxProjects" Margin="165,90,28,0" Grid.Column="0" VerticalAlignment="Top" Height="25"
IsSynchronizedWithCurrentItem="True" SelectedIndex="0" Style="{StaticResource ComboBoxDefault}"
ItemsSource="{Binding Path=ProjectClientSelections.ProjectGroupItems,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Path=ProjectClientSelections.SelectedProject, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding GroupName}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Project}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Does anyone see where I'm going wrong?

In GroupStyle, the DataContext is not your item (the type contained in your ItemsSource), but a CollectionViewGroup object, which is formed based on the collection of items that you have grouped. Because of this you have to declare a binding path to one of the properties in CollectionViewGroup, for example, based on your code you probably want to use Name property. See MSDN CollectionViewGroup Class
Change your GroupStyle.HeaderTemplate to this:
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
You don't show how you have formed your GroupDescriptions. If you have not grouped the items already, you can do it in following way (assuming the XAML you have provided is contained inside Window and Window's and GroupBox's DataContext is the same):
<Window.Resources>
<CollectionViewSource
Source="{Binding ProjectClientSelections.ProjectGroupItems}"
x:Key="GroupedProjectItems">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription
PropertyName="GroupName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
After this change GroupBox ItemSource binding to the following (directly to CollectionViewSource resource):
ItemsSource="{Binding Source={StaticResource GroupedProjectItems}}"

Related

How to create a template with parameters in WPF?

I have 3 List views. They are very similar. The only difference is that their ItemsSource binds to different variables. Is there a way to create a template list view with unknown ItemsSource, and I can pass a parameter to fill that ItemsSource?
My code is something like this:
<ListView Name="View1" ItemsSource={"Binding Student1"}>
<TextBlock Text={"Binding Name"}/>
</ListView>
<ListView Name="View2" ItemsSource={"Binding Student2"}>
<TextBlock Text={"Binding Name"}/>
</ListView>
<ListView Name="View3" ItemsSource={"Binding Student3"}>
<TextBlock Text={"Binding Name"}/>
</ListView>
Edit:
I might have expressed my question in a wrong way. I would like to have a separate user control view called "StudentView":
<ListView ItemsSource=Parameter1>
<TextBlock Text={"Binding Name"}/>
</ListView>
So that in my main window, I can do something like this:
<local:StudentView Parameter1={"Binding Student1"}/>
You are on the right track with thinking about templating
What you are looking for is something called a ControlTemplate.
Your ControlTemplate would then target the ListView control and use the key word TemplateBinding to pass through the ItemsSource binding from your ListView
You would look to add this as a window resource as shown below.
<Window.Resources>
<ControlTemplate x:Key="ListViewTemplate" TargetType="ListView">
<ListView ItemsSource="{TemplateBinding ItemsSource}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ControlTemplate>
</Window.Resources>
This would enable you to use this template on your ListView controls as shown below
<ListView Template="{StaticResource ListViewTemplate}" ItemsSource="{Binding PersonList}"/>
<ListView Template="{StaticResource ListViewTemplate}" ItemsSource="{Binding PersonList1}"/>
<ListView Template="{StaticResource ListViewTemplate}" ItemsSource="{Binding PersonList2}"/>
Hope this gives you what you were looking for

How to collapse contents of a databound ListBoxItem when a button is clicked in WPF MVVM

I have a ListBox in my WPF MVVM app using the following code:
<GroupBox Grid.Column="0" Margin="0,0,0,-58">
<DockPanel>
<TextBlock DockPanel.Dock="Top"
HorizontalAlignment="Center"
Margin="0,0,0,8"
FontWeight="Bold"
Text="{x:Static p:Resources.AvaliableLEDsLabel}" />
<ListBox Name="AvailableLEDsListbox" SelectionMode="Extended"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}"
ItemTemplate="{StaticResource DataTemplateListBoxItem}"
ItemsSource="{Binding AvailableLeds}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
>
<ListBox.GroupStyle>
<StaticResource ResourceKey="StyleListBoxGroup" />
</ListBox.GroupStyle>
</ListBox>
</DockPanel>
</GroupBox>
This displays grouped lists of devices, with LEDs under them. The DataTemplate is the following:
<GroupStyle x:Key="StyleListBoxGroup">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Command="{Binding HideGroupCommand}">X</Button>
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Left"
FontWeight="Bold"
Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<DataTemplate x:Key="DataTemplateListBoxItem">
<TextBlock x:Name="LedId" Text="{Binding LedId}"/>
</DataTemplate>
I would like to make the X button in the header hooked up to the HideGroupCommand toggle the hiding of all the items under that particular header. How would I go about doing this? Thanks in advance.
You have few options.
First one :
You would need to have a property in your view model something like 'ListBoxVisibility' then u would bind that property to your UI. In command text u just changed visibility property of that property in view model- so u have it reflected on UI. This visibility property can be of type 'bool' , or 'Visibility' or whatever. Only if it's type of Visibility u don't need converter when binding.
NOTE : Some people use it - even though it kinda goes out of general principel of MVVM patter. But sometimes u have to do it.
Second
If wanna stick to MVVM , then u need to fully separate your UI from your viewmodel. Create click event and change visibility.

UWP: Accessing Usercontrol and elements Inside Usercontrol from parent listview

My XAML is as below.:
<ComboBox x:Name="cbCurrencyValueList" SelectionChanged="cbCurrencyValueList_SelectionChanged" ItemsSource="{Binding Source={StaticResource MyCurrencyLists}, Path=librarycurrencylist}" DisplayMemberPath="CurrencyCode" SelectedValuePath="CurrencyCode" SelectedValue="{Binding PricingCurrency, Mode=TwoWay}"/>
<ListView x:Name="lbPriceChangeSchedule" ItemsSource="{Binding PricingScheduleList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<ComboBox x:Name="cbSchedulePriceValueList" ItemsSource="{Binding Source={StaticResource MyPricingLists}, Path=librarypricinglist}" DisplayMemberPath="PriceValue" SelectedValuePath="PriceValue" SelectedValue="{Binding ScheduleDisplayPricing, Mode=TwoWay}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Question: Any selection change in 'cbCurrencyValueList' combobox will change the itemssource list of cbSchedulePriceValueList inside listview. if listview contains n instance of ComboBox cbSchedulePriceValueList then all of them's itemsource will change.
So how can I access every instance of cbSchedulePriceValueList in codebehind and update/change its itemssource individually.?
Any guidance ?

C# WPF Listbox Group Header Style

I'm using a Listbox to show multiple items.
The items are grouped. Now I want to edit the header style but the only thing happens is that the text isn't shown anymore.
Thats my xaml:
<ListBox x:Name="lbTreatments" HorizontalAlignment="Left" Height="473" Margin="10,37,0,0" VerticalAlignment="Top" Width="309" FontSize="13">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding subcategoryName}" FontWeight="Bold"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And thats my code to group the items:
ICollectionView view = CollectionViewSource.GetDefaultView(treatmentsCategory);
view.GroupDescriptions.Add(new PropertyGroupDescription("subcategoryName"));
view.SortDescriptions.Add(new SortDescription("subcategoryName", ListSortDirection.Ascending));
lbTreatments.ItemsSource = view;
The items are grouped but the header text is missing. If I delete the Groupstyle from xaml the text will be shown. Can anybode help me please?
MSDN says:
Each group is of type CollectionViewGroup.
The actual data type is CollectionViewGroup which doesn't have a subcategoryName property so the binding will fail. Instead you have to use the Name property, which will already be set to the value from subcategoryName.
As such, use this...
<TextBlock Text="{Binding Name}"/>
...in your header template to get the group name.

ComboBox with grouping and custom group headers

I would like to create a grouped ComboBox with a group header which is bound to not only the group's name, but other properties of the values by which the 'ItemsSource' of the ComboBox is grouped as well.
This is the CollectionViewSource which is used as the ComboBoxes ItemsSource:
<CollectionViewSource x:Key="Tools" Source="{Binding AvailableTools}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Toolbox" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
The property by which I group, is not a string property, but an object of a custom type. The CollectionViewSource obviously creates groups and gives each group the name of [object by which is group].ToString(), yielding the type name of the property Toolbox in my example.
Here's the combo:
<ComboBox
SelectedItem="{Binding SelectedTool, Mode=TwoWay}"
Margin="10,0,0,0"
Width="40"
ItemsSource="{Binding Source={StaticResource Tools}}">
<ComboBox .GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate DataType="CollectionViewGroup">
<Grid Background="{StaticResource LighterBackgroundBrush}">
<TextBlock Text="{Binding Name}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox .GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate DataType="viewModels1:ToolSelectionItem">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Tool.ToolIcon}" Width="16" />
<TextBlock Text="{Binding ToolName}" Margin="10,0,0,0"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
In the header template, I can bind to the groups name but nothing else. What I would like to achieve, is a binding to the object by which a group was created and not just it's ToString() result. I.e. the values of the Toolbox property by which I group contain an Icon property of type BitmapImage which I would like to bind to an Image inside the header template to display this icon in the group header. Can this be done at all and if so, how?
The issue is a bit difficult to explain, please ask, if I am not being clear enough...

Categories

Resources