How set same height in group of listbox? - c#

I have some problem with generating listbox.
I have dataset with many rows and i need to split one big table to two or more depends on some RowsLimit. One table with 100 rows will became two tables with 50 rows and so on. These blocks will display next to each other.
For this I use listbox with grouping (in code behind I set property for filtering) and it works well. But each row has different height and I need last row in group fills all remaining space in every group.
I tried use dock panel, but it changes nothing.
Also I need create and set GroupStyle.HeaderTemplate in runtime, because I have in my dataset number of columns, width, bordercolor, and other properties. How can I replace DataTemplate "HeaderGroupStyle" with new?
<ListBox Name="lbTable" >
<ListBox.Resources>
<DataTemplate x:Key="HeaderGroupStyle">
<StackPanel Orientation="Horizontal">
<TextBox Width="100" Text="Header 1" />
<TextBox Width="100" Text="Header 2" />
<TextBox Width="100" Text="Header 3" />
<TextBox Width="100" Text="Header 4" />
</StackPanel>
</DataTemplate>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<DockPanel>
<ContentPresenter DockPanel.Dock="Top"/>
<ItemsPresenter Margin="0,0,0,0" DockPanel.Dock="Top"/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="0"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<TextBox Width="100" Text="{Binding Path=Cell[0].Value}" />
<TextBox Width="100" Text="{Binding Path=Cell[1].Value}" />
<TextBox Width="100" Text="{Binding Path=Cell[2].Value}" />
<TextBox Width="100" Text="{Binding Path=Cell[3].Value}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource HeaderGroupStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</ListBox.GroupStyle>
</ListBox>
This is what I have now
And this is what I want

Related

Change Text of Textblock in controltemplate

I have a list of items which a user can select and I would like to add an explanation text. So far I have this code
<TabItem Name="TabItem02" Header="">
<ListBox Name="listBox01" VerticalAlignment="Stretch" SelectionMode="Multiple" HorizontalAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectedValuePath="Content">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<CheckBox Margin="5,2" IsChecked="{TemplateBinding IsSelected}" Grid.Column="0" VerticalAlignment="Top">
<ContentPresenter VerticalAlignment="Center">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock Text="{TemplateBinding Content}" TextWrapping="Wrap" />
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</CheckBox>
<Expander Header="Explanation" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Right" FlowDirection="RightToLeft">
<TextBlock TextWrapping="Wrap" FlowDirection="LeftToRight"/>
</Expander>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBoxItem Name="List1Item01" IsEnabled="False"/>
<ListBoxItem Name="List1Item02" IsEnabled="False"/>
<ListBoxItem Name="List1Item03" IsEnabled="False"/>
<ListBoxItem Name="List1Item04" IsEnabled="False"/>
<ListBoxItem Name="List1Item05" IsEnabled="False"/>
</ListBox>
</TabItem>
And at the moment I am changing the content of each ListBox through a ressourcefile with this code-behind
foreach (ListBox listBox in ListBoxes)
{
foreach (ListBoxItem item in listBox.Items) item.Content = resourceManager.GetString(item.Name);
}
I would like to change the text of the second TextBlock (the one in the Expander) according to the ListBoxItem it belongs to as easy as the ListBox content itself through the ressourcefile. I would prefer not to create a separate Expander + TextBlock for each ListBoxItem with a separate name.
So if anyone has a solution for my problem, I would really appreciate that.

Is it possible to add the groupitem's itemcount in a separate label somewhere else on the same form?

I am writing a new application that contains a DataGrid (c# WPF) and I have the itemcount displayed above the section and would like that count to show in a label also. How would I do this ?
link to the photo of the datagrid
I have tried
<Label Width="30" Height="30"
Content="{Binding ElementName=dataGrid1, Path=Items.Count}" />
but it shows the entire row count and not just the "installed" count.
<Style x:Key="groupheaderstyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="LightBlue" Foreground="Black">
<Expander.Header>
<DockPanel>
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=ItemCount}" Margin="8,0,4,0"/>
</DockPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>[Link to the datagrid photo][1]
In situation like these having a look at the structure of your ItemsSource helps.
I guess this should do the trick.
// For first group
<Label Content="{Binding Path=ItemsSource.Groups[0].ItemCount, ElementName=dataGrid1}" />
// For second group
<Label Content="{Binding Path=ItemsSource.Groups[1].ItemCount, ElementName=dataGrid1}" />

listbox inside ScrollViewer - freeze program

I need some advice. We noticed unusual behavior within the ScrollViewer. I have a StackPanel with whom I am more items including ListBox when the StackPanel placed in a ScrollViewer, when loading data to the listbox, a program for a brief moment freezes. When I am alone ListBox but everything works normally, no freezing of the program.
Here is my code:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="tStack" >
<Grid Height="300">
</Grid>
<Grid Height="300">
</Grid>
<ListBox x:Name="ListBox1" ItemsSource="{Binding AlbumsCvs.View, IsAsync=True}"
Style="{StaticResource ListBoxAlbumsTracksStyles}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingStackPanel.VirtualizationMode="Recycling" >
<ListBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource AlbumsHeader}" />
</ListBox.GroupStyle>
</ListBox>
</StackPanel>
</ScrollViewer>
<Style x:Key="ListBoxAlbumsTracksStyles" TargetType="{x:Type ListBox}">
<Setter Property="Padding" Value="0,0,0,0" />
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate >
<DockPanel>
<Border Background="#00000000"
Height="36"
Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}}">
<DockPanel>
<TextBlock x:Name="TrackNumber"
DockPanel.Dock="Left" Margin="2,0,5,0"
Text="{Binding TrackNumber}"
VerticalAlignment="Center"
FontSize="13"
MinWidth="17"
Foreground="Black"/>
<DockPanel>
<TextBlock DockPanel.Dock="Left"
Text="{Binding TrackTitle}"
TextAlignment="Left"
FontSize="13"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
TextTrimming="CharacterEllipsis"
Margin="0,0,2,0"/>
<TextBlock DockPanel.Dock="Right"
Text="{Binding Duration}"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
TextTrimming="CharacterEllipsis"
Margin="0,0,10,0"
FontSize="13" TextAlignment="Right"/>
</DockPanel>
</DockPanel>
</Border>
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- GroupItem -->
<Style x:Key="AlbumsHeader" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}}" Background="#00000000">
<StackPanel Margin="0,0,0,15">
<StackPanel>
<TextBlock Text="{Binding AlbumName}"
DataContext="{Binding Items}"
Margin="0,5,0,0"
HorizontalAlignment="Stretch"
FontSize="20"
FontWeight="Light"
TextTrimming="CharacterEllipsis"
Foreground="Black"/>
<TextBlock Text="{Binding IdAlbum}"
DataContext="{Binding Items}"
Margin="0,0,0,10"
HorizontalAlignment="Stretch"
TextTrimming="CharacterEllipsis"
Foreground="Black"/>
</StackPanel>
<ItemsPresenter HorizontalAlignment="Stretch"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
code behind:
private async Task AlbumsArtistInformation()
{
if (string.IsNullOrEmpty(ArtistName))
return;
ObservableCollection<AlbumsArtistCollections> _albumsArtistCollections =
new ObservableCollection<AlbumsArtistCollections>();
try
{
var search = await spotifyDataService.GetArtists(ArtistName);
if (search == null) throw new ArgumentNullException(nameof(search));
foreach (var _artist in search.Artists.Items.Take(1))
{
this.IdArtist = _artist.Id;
}
var _artistAlbum = await spotifyDataService.GetArtistsAlbumsAsync(this.IdArtist, AlbumType.All);
if (_artistAlbum == null) throw new ArgumentNullException(nameof(_artistAlbum));
_albumsArtistCollections = _artistAlbum;
}
finally
{
// Unbind to improve UI performance
Application.Current.Dispatcher.Invoke(() =>
{
this.Albums = null;
this.AlbumsCvs = null;
});
Application.Current.Dispatcher.Invoke(() =>
{
this.Albums = _albumsArtistCollections;
});
Application.Current.Dispatcher.Invoke(() =>
{
// Populate CollectionViewSource
this.AlbumsCvs = new CollectionViewSource { Source = this.Albums };
//Group by Album if needed
this.AlbumsCvs.GroupDescriptions.Add(new PropertyGroupDescription("IdAlbum"));
});
}
}
Does anyone know how to solve this problem.
Vertically oriented StackPanel provides an unbounded available space for the the ListBox, when it calls MeasureOverride(Size availableSize) method, during layout. Therefore, the ListBox (which by default uses virtualization) should create the whole items and this is why you program freezes for a moment.
Therefore, use a DockPanel instead:
<DockPanel x:Name="tStack" LastChildFill="True" >
<Grid DockPanel.Dock="Top" Height="300">
</Grid>
<Grid DockPanel.Dock="Top" Height="300">
</Grid>
<ListBox DockPanel.Dock="Bottom" x:Name="ListBox1" ItemsSource="{Binding AlbumsCvs.View, IsAsync=True}"
Style="{StaticResource ListBoxAlbumsTracksStyles}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingStackPanel.VirtualizationMode="Recycling" >
<ListBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource AlbumsHeader}" />
</ListBox.GroupStyle>
</ListBox>
</DockPanel>
LastChildFill is true by default. The ListBox should be the last element, in order to fill the space.
As another option, you can set the Height of the ListBox and put the DockPanel in a ScrollViewer or you can consider a Grid with splitters as another option.

Datagrid Grouping displaying the Field value that you are grouping on as Header

I am trying to Group Items in a DataGrid and display the value of the Field it is grouping on in the header. For example:
Ford - 3 items
F150
Mustang
Chevy - 2 items
Every example I have looked at shows me the exact same thing which doesn't seem to work at all for me.
<DataGrid IsSynchronizedWithCurrentItem="True" SelectionUnit="FullRow" RowHeaderWidth="0" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" IsReadOnly="True" ItemsSource="{Binding View}" SelectedItem="{Binding Path=SelectedContingency, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" >
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text=" wtf " />
<TextBlock Text="{Binding Path=Description, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
<TextBlock Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" Items" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
Also had this for a while but it made no difference
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Description}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
Instead of getting a description here I just get ( wtf 3 items ) etc. I've tried different fields and nothing. I've tried every variation I can think of for the field in the exapander header.
What magic is required to make this common feature function?
The answer to this is that in the examples they bind to the field name. So when you see in the examples:
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name"} />
<TextBlock Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" Items" />
</StackPanel>
</Expander.Header>
You might assume as I did that "Name" is used because thats also the field they chose to bind to. This is not the case. "Name" is the actual property on the GroupItem that you are binding to that has the value.
So no matter what Field you are grouping on, you always display that field by binding to "Name" on the GroupItem.

WPF Datagrid - How to avoid second level grouping when value is null

I have a grid that supports two-level grouping, the grouping is based on multiple columns. In cases when the value is "null", how can I avoid the second level grouping.
DataTable - converted to CollectionView is the data source of the below DataGrid. The data table has multiple two columns, "Category" and "SubCategory" based on which two-level grouping should be done - primary and secondary respectively. However, the catch is that the "SubCategory" is not applicable in all cases and certain rows may only have the "Category" - In that case, I don't want the second group level header to show up at all - right now it shows up as an empty row with the "expander" toggle button.
The Data is flexible, if I have to make changes to the datatable - I can do so. Please suggest.
<DataGrid Name="gridResult" IsSynchronizedWithCurrentItem="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True" AlternationCount="2" ItemsSource="{Binding }" HeadersVisibility="All" CanUserAddRows="False"
CanUserDeleteRows="False" EnableRowVirtualization="False" EnableColumnVirtualization="False" Margin="2,10,2,2" BorderThickness="0" HorizontalGridLinesBrush="Gray"
VerticalGridLinesBrush="Gray" Background="Transparent" AllowDrop="False" Grid.Row="2">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
<GroupStyle ContainerStyle="{StaticResource SecondGroupContainerStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
<Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="#FFBDC8C9" Foreground="Black" FontWeight="Bold" BorderBrush="Black" BorderThickness="0 0 0 1">
<Expander.Header>
<TextBlock Text="{Binding Name}"/>
<!--</StackPanel>-->
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SecondGroupContainerStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}" >
<Expander x:Name="exp" IsExpanded="True" Background="#FFC2CBCC" Foreground="Black" FontWeight="Bold" BorderBrush="Black" BorderThickness="0 0 0 1" Margin="5 0 0 0">
<Expander.Header>
<TextBlock Text="{Binding Name}">
</TextBlock>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Categories

Resources