DataGrid Grouping - get each group rows - c#

I am using DataGrig Grouping for my data. In my group header I am using checkboxes for ColumnCheckBox cell check, for that I have to have rows data for each group.
XAML:
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount, StringFormat=({0})}"/>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter/>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
CS:
Instances = new ListCollectionView(types);
Instances.GroupDescriptions.Add(new PropertyGroupDescription("View"));
Instances.GroupDescriptions.Add(new PropertyGroupDescription("Category"));
Instances.GroupDescriptions.Add(new PropertyGroupDescription("Family"));
So an idea is to bind header checkboxes with array of Id for each row and on header check, change binded CheckColumn values. But for that i need to collect all group rows. Is it possible to implement?
So I've got: https://i.ibb.co/7g9GpqL/p1.png
And I need : https://i.ibb.co/WW7S4cn/p2.png

Related

Sorting by chosen column in grouped datagrid WPF

I have a grouped data grid that is bound to a ListCollectionView.
I want to add an option for inner sort (in the groups) by pressing one of the columns.
I wrote the following code:
<DataGrid x:Name = "ProjectsDataGrid" ItemSource = "{Binding}"
AutoGeneratedColumns = "False"
CanUserDeleteRows = "False"
CanUserAddRows = "False"
CanUserResizeColumns = "True"
SelectionMode = "Single"
SelectionUnit = "FullRow"
CanUserSortColumns = "True"
Sorting = "ProjectsDataGrid_Sorting"
>
<... columns info ...>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" Background="White" Foreground="Black">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid>
When I ran the program I couldn't press the columns and get to the sorting function even though I allowed it in the dataGrid definition, any ideas why?
Thanks :)

How do I better stylize a ListBox of images in WPF?

I've binded a List from my code-behind to a ListBox but I'm having difficulty stylizing the look to get what I want. I'd like to show up to 8 images at once, but no more than that without scrolling down. When the window resizes, I would like the image sizes to scale with it but still have no more than 8 showing. Here's my current XAML:
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Center" VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Grid Background="{TemplateBinding Background}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Here's a pic of what this XAML produces. As you can see the images are much too large and we only see the top half of the second row. If I mess around with ListBoxItem margin I can get them smaller but this isn't really ideal as it only works if the screen resolution stays the same.
Set your image dimensions to be the same and use a WrapPanel instead:
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Margin="5" >
<Image Source="{Binding}" Stretch="Uniform" Width="400" Height="400"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
Alternatively, if you want a fixed number of columns then don't specify image dimensions at all and instead use a UniformGrid:
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Margin="5" >
<Image Source="{Binding}" Stretch="Uniform" />
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
UPDATE: I'm at a bit of a loss now to understand exactly what it is you're trying to do, the images you're posting don't match your description. If you want the panels to be square, and the images to scale up to them uniformly with a thin border around them, then there are a few things you'll have to do:
1) change your ListBoxItem ControlTemplate to be a Border with a Transparent background and the ContentPresenter inside it. This will ensure that your yellow border doesn't fill the whole box, and that the rest of the box doesn't highlight when selected, but that you can still click anywhere on it to select it.
2) change your ItemTemplate to be a grid (so that it fills all available space) with a border centered in the middle of it with padding (so that you'll be able to see the yellow border when selected), then put your Image content inside that but wrap.
This should do the job:
<Style TargetType="{x:Type ListBox}" x:Key="PictureListBoxStyle">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid Margin="5">
<Border Padding="5" HorizontalAlignment="Center" VerticalAlignment="Center">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Transparent" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}" Value="True">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Image Source="{Binding}" Stretch="Uniform" />
</Border>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
</Style>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Border Background="Transparent">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If that still isn't it then you'll need to define your requirements more clearly.
You could use a UniformGrid as ItemsPanel with appropriate HorizontalAlignment and VerticalAlignment. Also remove the redundant Border element from the DataTemplate.
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Width="200" Height="200" Margin="5" Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Update: In order to have the yellow selection border directly around the image, use a ListBoxItem Style like shown below. To have the images scaled to (a fraction of) the full ListBox width, add an appropriate ControlTemplate.
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="LightGray" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Grid Background="{TemplateBinding Background}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
BorderThickness="5"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

How to check all child checkboxes in a datagrid header

I have a datagrid with 3 level grouping. Grouping is done in code behind using the CollectionView and PropertyGroupDescription.
Every row of record will have a DataTemplateColumn (CheckBox). I included a checkbox infront of each header so that I can check all the child data.
Unfortunately I have tried few methods but i cant check all the child checkboxes.
xaml codes
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander x:Name="MyExpander" IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<CheckBox Click="checkBoxHeader_Click"/>
<TextBlock x:Name="MyExpanderHeader" Text="{Binding Name}" FontWeight="Bold" VerticalAlignment="Bottom">
</TextBlock>
</StackPanel>
</Expander.Header>
<ItemsPresenter Margin="20,0,0,0"/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
cs code
CollectionView collectionView = (CollectionView)CollectionViewSource.GetDefaultView(m_stationInfoList);
PropertyGroupDescription groupDescription1 = new PropertyGroupDescription("Property1");
PropertyGroupDescription groupDescription2 = new PropertyGroupDescription("Property2");
PropertyGroupDescription groupDescription3 = new PropertyGroupDescription("Property3");
collectionView.GroupDescriptions.Clear();
collectionView.GroupDescriptions.Add(groupDescription1);
collectionView.GroupDescriptions.Add(groupDescription2);
collectionView.GroupDescriptions.Add(groupDescription3);

listview conditional grouping

In my WPF app I have a ListView of documents with grouping of sections:
myitems.Add(new Data("document_1", "section_1"));
myitems.Add(new Data("document_1", "section_2"));
myitems.Add(new Data("document_2", "one_and_only_section"));
lv.ItemsSource = myitems;
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(lv.ItemsSource);
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("document");
This results in something that roughly looks like
< document_1
section_1
section_2
< document_2
one_and_only_section
This is in theory fine, but it is very tedious to select the "one_and_only_section" item if everything is collapsed, because it needs two clicks (first on "document_2", second on "one_and_only_section"). Ideally, the document_2 shouldn't be grouped in the same way as document_1:
< document_1
section_1
section_2
document_2
So if there is just one element to a group, it shouldn't have an expander and reveal that one element. If selected it should act as if "one_and_only_section" is selected.
Is this feasible with ListView?
I was able to produce the desired output with the following XAML code:
<ListView ItemsSource="{Binding Path=ItemsView}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<ControlTemplate.Resources>
<DataTemplate DataType="{x:Type local:ItemViewModel}">
<TextBlock Text="{Binding Path=Section}" />
</DataTemplate>
</ControlTemplate.Resources>
<Expander Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}">
<Expander.Header>
<StackPanel Margin="0,8,0,0"
HorizontalAlignment="Stretch"
Orientation="Horizontal">
<TextBlock x:Name="Title"
VerticalAlignment="Center"
FontWeight="Bold">
<Run Text="{Binding Path=Name, Mode=OneWay}" />
<Run Text=" " />
<Run Text="{Binding Path=Items.Count, Mode=OneWay}" />
</TextBlock>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count}" Value="1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<ControlTemplate.Resources>
<DataTemplate DataType="{x:Type local:ItemViewModel}">
<TextBlock Text="{Binding Path=Document}" />
</DataTemplate>
</ControlTemplate.Resources>
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
You might want to add some extra attention to your expander style and the datatemplates, to make it look similar.

WPF ListBox - using ItemTemplate in GroupStyle

I'm trying to makeaA grouped listbox. Firstly I did a ItemTemplate. Now I'm trying to group the data but I don't have any idea how to use that ItemTemplate. Could anybody help me a little?
My current listbox xaml
<ListBox x:Name="kontakty" ItemsSource="{Binding kontakt}">
<ListBox.GroupStyle>
<GroupStyle HeaderStringFormat="Group">
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel>
<TextBlock Text="{Binding Path=Name}" Foreground="Red"/>
<ComboBox ItemsSource="{Binding Path=Items}" DisplayMemberPath="Name"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
//...............//
</ListBox.ItemTemplate>
</ListBox>
Solution is adding ItemControl with this ItemTemplate to GroupStyle.

Categories