SharedSizeGroup in ListView.ItemTemplate - wpf

I have this scenario where I want to share the column size among all the ListViewItems, and I'm using SharedSizeGroup on the column definitions but it doesn't work:
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="A" />
<ColumnDefinition Width="Auto" SharedSizeGroup="B" />
<ColumnDefinition Width="Auto" SharedSizeGroup="C" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="10,0" Text="{Binding Text1}" />
<TextBlock Grid.Column="1" Margin="10,0" Text="{Binding Text2}" />
<TextBlock Grid.Column="2" Margin="10,0" Text="{Binding Text3}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I know a possible solution is using a GridView as the ListView.View, but there's a few design issues that prevent us from doing this. Is there any other way I can achieve sharing the column widths?
This is what I want to achieve (the columns with the same colors should share width):
Thanks in advance.

The only thing that is missing is the scope i think, add Grid.IsSharedSizeScope="True" to the ListView attributes.

Related

WPF ListBox Header And Data Alignment

I am trying to align data with the headers in a WPF application. The headers a line up and spaced nicely. However, I cannot get the data items underneath to line up with the headers. Any suggestions?
I have been poking around a bit, but have not found a solution to my problem. I do have to stick with list box as it is part of the requirements. Also, I am new to WPF.
Here is what the output is:
And here is the xaml that I am using:
<Grid Grid.Row="2">
<ListBox ItemsSource="{Binding MyData}">
<ListBox.Template>
<ControlTemplate>
<StackPanel>
<Grid Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" x:Name="ToteNumber"></ColumnDefinition>
<ColumnDefinition Width="*" x:Name="Desription"></ColumnDefinition>
<ColumnDefinition Width="*" x:Name="Time"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Tote Number" HorizontalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="Description" HorizontalAlignment="Center"/>
<TextBlock Grid.Column="2" Text="Time" HorizontalAlignment="Center"/>
</Grid>
<ItemsPresenter></ItemsPresenter>
</StackPanel>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border BorderThickness="1" BorderBrush="Black">
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Property1}" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Column="1" Text="{Binding Property2}" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Column="2" Text="{Binding Property3}" HorizontalAlignment="Stretch"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You need to set Grid.IsSharedSizeScope="True" on a parent panel and you need to identify the SharedSizeGroup on each column so it knows which column in your listbox template grid corresponds to which one in your itemtemplate.
Note that I think * width is treated as Auto when you apply Sharedsizegroup.
I use width auto and minwidth instead when I've done something similar.
You may find you need to bind width of each column to some parent measuring grid or calculate minwidth using a converter based on ViewportWidth of the scrollviewer in your listbox.
<Grid Grid.Row="2" Grid.IsSharedSizeScope="True">
<ListBox ItemsSource="{Binding MyData}">
<ListBox.Template>
<ControlTemplate>
<StackPanel>
<Grid Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" SharedSizeGroup="A" x:Name="ToteNumber"></ColumnDefinition>
<ColumnDefinition Width="*" SharedSizeGroup="B" x:Name="Desription"></ColumnDefinition>
<ColumnDefinition Width="*" SharedSizeGroup="C" x:Name="Time"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Tote Number" HorizontalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="Description" HorizontalAlignment="Center"/>
<TextBlock Grid.Column="2" Text="Time" HorizontalAlignment="Center"/>
</Grid>
<ItemsPresenter></ItemsPresenter>
</StackPanel>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border BorderThickness="1" BorderBrush="Black">
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" SharedSizeGroup="A"></ColumnDefinition>
<ColumnDefinition Width="*" SharedSizeGroup="B"></ColumnDefinition>
<ColumnDefinition Width="*" SharedSizeGroup="C"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Property1}" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Column="1" Text="{Binding Property2}" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Column="2" Text="{Binding Property3}" HorizontalAlignment="Stretch"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As I mentioned, I use a similar technique in some of my own markup. For that I put the headers grid and then the listbox with an itemtemplate in a stackpanel.
<StackPanel>
<Grid>
Headers
<ListBox>
ItemTemplate
</StackPanel>
Sounds like that doesn't suit whatever is driving your requirements though.

Why does a String DataTemplate cause a stack overflow exception?

I have a couple of DataTemplates defined in the resources of a ContentControl:
<DataTemplate DataType="{x:Type sys:String}">
<Label Content="{Binding}" HorizontalContentAlignment="Center" />
</DataTemplate>
<DataTemplate DataType="{x:Type dmodels:CBClient}"> <!-- Client Details Template -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Client Details" Background="{StaticResource brush_Client}" Foreground="White" Margin="0,0,1,0" VerticalAlignment="Center" />
<TextBlock Grid.Column="1" Text="Id:" Background="{StaticResource brush_Client}" Foreground="White" />
<TextBlock Grid.Column="2" Text="{Binding Path=ClientId}" Background="{StaticResource brush_Client}" Foreground="White" Margin="0,0,1,0" />
<Button Grid.Column="3" Style="{StaticResource EditButton}" />
</Grid>
</DataTemplate>
If I return a CBClient object, I get the proper display from the defined DataTemplate.
If I return a string, I get a StackOverflowException.
If I eliminate the String DataTemplate and return a string, I get the string displayed, but not formatted as I want it.
What am I doing wrong? Do I have to wrap the basic string return into a full class, and expose a message property? Is there no way to combine complex objects with integral types for DataTemplates?
Thanks.
J
You introduced a complication by using a Label. It automatically generates a textblock if you bind to a string. Binding in that way has an odd effect if you rely on it automatically adding the textblock. I should think it's because it sees an object rather than a string from the type of the property you're binding.
You could just do:
<DataTemplate DataType="{x:Type sys:String}">
<Label HorizontalContentAlignment="Center">
<TextBlock Text="{Binding}" />
</Label>
</DataTemplate>

ItemsControl/ListBox items exceed available width

I want text in column 3 wrap and have no horizontal scrollbar. Why doesn't this work?
<ItemsControl x:Name="listMessages" ItemsSource="{Binding Messages}" Grid.IsSharedSizeScope="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Column1"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="Column2"/>
<ColumnDefinition Width="*" SharedSizeGroup="Column3"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="Column4"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Text1" />
<TextBlock Grid.Column="1" Text="Text2" />
<TextBlock Grid.Column="2" Text="Very long text that should wrap to the next line, but it doesn't work" TextWrapping="Wrap"/>
<TextBlock Grid.Column="3" Text="Text4" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Items take more width than is available to ItemsControl. Same problem is with ListBox.
I tried to add ScrollViewer.HorizontalScrollbarVisibility=Disabled both on ItemsControl and Grid, but this doesn't help.
The text will be wrapped if you don't set the SharedSizeGroup property:
<ColumnDefinition Width="*"/>
Text wrapping and shared size groups don't go well together. You may want to specify a fixed MaxWidth for the ColumnDefinition or the TextBlock.

WP8 - XAML Grid column expanding when text is too long

I have a grid with column definitions.
Whenever the text inside a column cell exceeds the designated width, it shrinks the left hand column down.
Here's an example
And this is my xaml markup
<ItemsControl Name="rfbItems" ItemsSource="{Binding}"
Style="{StaticResource contentItemsControl}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Width="Auto" HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.7*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Title}" Style="{StaticResource App_Content_Grid}" TextAlignment="Left" />
<TextBlock Grid.Column="1" Text="{Binding Description}" Style="{StaticResource App_Content_Grid_Subtle}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
How should I restrict this behavior without losing responsiveness in the layout?
Also, if there is a better way to achieve what I'm trying to do here (inside the datatemplate), please feel free to share :)
Try setting margin and horizontal alignment to text boxes as below:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.7*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="5" HorizontalAlignment="Stretch" Text="{Binding Title}" Style="{StaticResource App_Content_Grid}" TextAlignment="Left" />
<TextBlock Grid.Column="1" Margin="5" HorizontalAlignment="Stretch" Text="{Binding Description}" Style="{StaticResource App_Content_Grid_Subtle}" />
</Grid>
The Grid doesn't have a limited width unless you give your StackPanel a fixed width. Setting Width="123" should work, HorizontalAlignment="Stretch" might do it as well (untested).
I'm sorry for all your efforts, but I found a solution.
None of the answers worked for me, so feel free to find a fitting solution and I'll accept your answer.
<ItemsControl Name="rfbItems" ItemsSource="{Binding}"
Style="{StaticResource contentItemsControl}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Width="Auto" HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="125" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Title}" Style="{StaticResource App_Content_Grid}" TextAlignment="Left" />
<TextBlock Grid.Column="1" Text="{Binding Description}" Style="{StaticResource App_Content_Grid_Subtle}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The first column has a fixed width, that's why the second column can't expand anymore.

Autosize header in WPF HeaderedItemsControl

I'm using a HeaderedItemsControl to show person names. I also want to show a header that contains 3 labels: Title, First Name and Last Name. This is easy when the names are short.
However, when there is a very long firstname, the header's don't match the names anymore. How can I fix this? Thank you!
Not sure if you really want to use this class:
A HeaderedItemsControl has a limited default style. To create a HeaderedItemsControl with a custom appearance, create a new ControlTemplate.
Anyway, to line up stuff you can use Grids with shared size, e.g.:
<HeaderedItemsControl ItemsSource="{Binding Data}" Grid.IsSharedSizeScope="True">
<HeaderedItemsControl.Template>
<ControlTemplate TargetType="HeaderedItemsControl">
<StackPanel>
<ContentPresenter ContentSource="Header" />
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</HeaderedItemsControl.Template>
<HeaderedItemsControl.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A" />
<ColumnDefinition SharedSizeGroup="B" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Name" />
<TextBlock Grid.Column="1" Text="Occupation" />
</Grid>
</HeaderedItemsControl.Header>
<HeaderedItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A" />
<ColumnDefinition SharedSizeGroup="B" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Name}"/>
<TextBlock Grid.Column="1" Text="{Binding Occupation}" />
</Grid>
</DataTemplate>
</HeaderedItemsControl.ItemTemplate>
</HeaderedItemsControl>

Resources