WPF ListBox Header And Data Alignment - wpf

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.

Related

ListView fill the width of parent, screen or whatever [duplicate]

This question already has answers here:
ListViewItem won't stretch to the width of a ListView
(2 answers)
Closed 7 years ago.
I am trying to display some data from an Observable Collection to a ListView.
Binding is working fine. My only problem I cannot fix is the layout of the ListView.I use a Grid with 2 rows to split my View. The ListView is one the second row. I only try to use * for setting Columns and Rows as suggested in most sources. The code for the ListView is this.
<Grid Grid.Row="1" Margin="10,0,10,0" HorizontalAlignment="Stretch">
<ListView ItemsSource="{Binding Collection}" HorizontalAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Center" Text="{Binding Period}" Foreground="{StaticResource ColorBrush}" FontFamily="{StaticResource Family}" FontSize="20"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center" Text="{Binding Currency}" Foreground="{StaticResource ColorBrush}" FontFamily="{StaticResource Family}" FontSize="20"/>
<TextBlock Grid.Column="2" HorizontalAlignment="Center" Text="{Binding Date}" Foreground="{StaticResource ColorBrush}" FontSize="20" FontFamily="{StaticResource Family}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
When I use HorizontalAlignment="Stretch" for the Grid that contains the ListView and the ListView itself the data is displayed on the left side without getting the whole width of parent View.
When I explicitly set Width to some value (i.e.380) it displays OK.
<Grid Grid.Row="1" Margin="10,0,10,0">
<ListView ItemsSource="{Binding Collection}" Width="380">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Width="380">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Center" Text="{Binding Period}" Foreground="{StaticResource ColorBrush}" FontFamily="{StaticResource Family}" FontSize="20"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center" Text="{Binding ValueInCurrency}" Foreground="{StaticResource ColorBrush}" FontFamily="{StaticResource Family}" FontSize="20"/>
<TextBlock Grid.Column="2" HorizontalAlignment="Center" Text="{Binding Date}" Foreground="{StaticResource ColorBrush}" FontSize="20" FontFamily="{StaticResource Family}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
But I want to know a better way to not use implicit values, but *.
Try this. Add the following jus after </ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>

WPF ListBox size don't changed after unwrap

I have ListBox and dynamic DataTempletes Items.
When TextBlock text wrapping, ListBox size is adding and size changing when unwrapping doesn't return to old value and remains un-changed.
I don't understand what is the problem. TextBlock size changed but not ListBox.
<ListBox x:Name="ctrlFavOdds"
Grid.Row="2"
ItemsSource="{Binding 'FavStakesList'}"
ItemContainerStyle="{StaticResource alternatingStyle}"
AlternationCount="2"
FontWeight="Bold"
HorizontalContentAlignment="Stretch"
IsHitTestVisible="False"
VerticalAlignment="Top"
VirtualizingStackPanel.IsVirtualizing="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
Margin="2,0,5,0"
Source="{Binding 'MakeExpressBetImage', Converter={StaticResource 'imageconverter'}}"/>
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
FontSize="12"
Text="{Binding Stake}"
VerticalAlignment="Center"
HorizontalAlignment="Left"/>
<TextBlock Grid.Column="2"
TextWrapping="Wrap"
Margin="5,0,0,0"
Text="{Binding StakeFactor}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="14"/>
<Image Grid.Column="3"
Margin="5,0,2,0"
Source="{Binding 'UpDounImage', Converter={StaticResource imageconverter}}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When TextBlock text wraping, ListBox size is adding and size changing when unwrapping doesn't return to old value and remains un-changed

Radiobutton Even Horizontal Alignment

Is there a way to evenly layout radiobuttons including the radiobutton text? I have tried StackPanel with Orientation=Horizontal, DockPanel and UniformGrid but I have not achieved the exact look I am going for which is an even amount of white space between the controls without having to wrap or truncate the text.
<GroupBox Name="grpLegend" Header="{x:Static res:Strings.ChartOptionsDisplayControlView_GroupBox_Legend}">
<ItemsControl
ItemsSource="{Binding IsAsync=True, Path=AvailablePitchbookLegendPosition}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton
Content="{Binding IsAsync=True, Path=DisplayName}"
IsChecked="{Binding IsAsync=True, Path=IsSelected}"
GroupName="LegendPosition"
Margin="2,3.5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</GroupBox>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<RadioButton Grid.Column="0" Content="Left"/>
<RadioButton Grid.Column="1" HorizontalAlignment="Center" Content="Center"/>
<RadioButton Grid.Column="2" Content="Right"/>
</Grid>
If this Grid was part of a list's ItemTemplate and you wanted to synchronize the widths of the grid's columns you should use the SharedSizeGroup property.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="c1"/>
<ColumnDefinition SharedSizeGroup="c2"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="c3"/>
</Grid.ColumnDefinitions>
<RadioButton Grid.Column="0" Content="Left"/>
<RadioButton Grid.Column="1" HorizontalAlignment="Center" Content="Center"/>
<RadioButton Grid.Column="2" Content="Right"/>
</Grid>
and then on a suitable parent container use the attached property Grid.IsSharedSizeScope="true"
<ListBox Grid.IsSharedSizeScope="True" ItemTemplate={StaticResource RadioButtonTemplate}/>

WPF: Horizontal Alignment

Probably I'm just missing something obvious, but I can't get the image in my DataTemplate to align to the right in the Grid, so that when the window is stretched, the image is "pulled" to the right as well:
<Window.Resources>
<DataTemplate x:Key="PersonTemplate" DataType="Minimal.Client.Person">
<Border BorderBrush="Purple" BorderThickness="2" CornerRadius="2" Padding="5" Margin="5">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="200"/>
<ColumnDefinition Width="Auto" MaxWidth="200"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column ="0" Orientation="Horizontal" >
<TextBlock FontFamily="Verdana" FontSize="16" FontWeight="Bold" Text="{Binding LastName}" />
<TextBlock FontFamily="Verdana" FontSize="16" Text=", " />
<TextBlock FontFamily="Verdana" FontSize="16" Text="{Binding FirstName}" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Vertical" HorizontalAlignment="Right">
<Border BorderBrush="Black" BorderThickness="1">
<Image Source="{Binding Picture}" Width="180" Height="150" />
</Border>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
Any suggestions?
I think the problem is that you have set a MaxWidth of 200 for the second column (where the Image is contained). Therefore, the column will not be any wider than 200 pixels and the two columns will not use the complete available space. If you insert another column in between the two columns and make this one star-sized, the Image will be right-aligned:
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="200"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" MaxWidth="200"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column ="0" Orientation="Horizontal" >
<TextBlock FontFamily="Verdana" FontSize="16" FontWeight="Bold" Text="{Binding LastName}" />
<TextBlock FontFamily="Verdana" FontSize="16" Text=", " />
<TextBlock FontFamily="Verdana" FontSize="16" Text="{Binding FirstName}" />
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Vertical" HorizontalAlignment="Right">
<Border BorderBrush="Black" BorderThickness="1">
<Image Source="{Binding Picture}" Width="180" Height="150" />
</Border>
</StackPanel>
</Grid>
This way, it works for me. However, you should be careful when using StackPanels. They always take as much space as they need. And if they are not given that much space, part of the content will simply be hidden.
gehho.
Try taking out the "MaxWidth" from your second column definition, and setting the Width to "*".
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
This keeeps the explicit settings from positioning your second column to the left.

How to make a StackPanel Width that of another StackPanel?

I have two dockpanels which each have a left StackPanel.
The width of the bottom StackPanel is determined by the width of the text is in it.
The width of the top StackPanel should be the same as the width of the bottom StackPanel.
I've tried to bind the Width of the top StackPanel to the Width of the bottom StackPanel via ElementName but this doesn't work.
How can I make the top width the same as the bottom width?
<StackPanel>
<DockPanel LastChildFill="True" Height="100" >
<StackPanel Width="{Binding ElementName=LeftMenuText, Path=Width}"
DockPanel.Dock="Left"
Background="Yellow">
<TextBlock
Text="This is some text."/>
</StackPanel>
<StackPanel DockPanel.Dock="Right"
Background="Orange">
</StackPanel>
</DockPanel>
<DockPanel
Height="3"
Background="Black"></DockPanel>
<DockPanel LastChildFill="True" Height="100">
<StackPanel Name="LeftMenuWrapper"
DockPanel.Dock="Left"
Background="Yellow">
<TextBlock
Text="This is some text that is longer."/>
</StackPanel>
<StackPanel DockPanel.Dock="Right"
Background="Blue">
</StackPanel>
</DockPanel>
</StackPanel>
Bind it to ActualWidth of LeftMenuWrapper:
<StackPanel>
<DockPanel LastChildFill="True" Height="100" >
<StackPanel Width="{Binding ElementName=LeftMenuWrapper, Path=ActualWidth}"
DockPanel.Dock="Left"
Background="Yellow">
<TextBlock
Text="This is some text."/>
</StackPanel>
<StackPanel DockPanel.Dock="Right"
Background="Orange">
</StackPanel>
</DockPanel>
<DockPanel
Height="3"
Background="Black"></DockPanel>
<DockPanel LastChildFill="True" Height="100">
<StackPanel Name="LeftMenuWrapper"
DockPanel.Dock="Left"
Background="Yellow">
<TextBlock
Text="This is some text that is longer."/>
</StackPanel>
<StackPanel DockPanel.Dock="Right"
Background="Blue">
</StackPanel>
</DockPanel>
</StackPanel>
Just to add to your arsenal another way to do this. You can also use Grid's IsSharedScope property:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Grid.IsSharedSizeScope="True">
<Grid Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TextHolder"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="Yellow">
<TextBlock Text="This is some text."/>
</Border>
<Border Grid.Column="1" Background="Orange"/>
</Grid>
<Border Height="3" Background="Black"/>
<Grid Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TextHolder"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="Yellow">
<TextBlock Text="This is some text that is longer."/>
</Border>
<Border Grid.Column="1" Background="Blue"/>
</Grid>
</StackPanel>
</Page>
You can do this using Grids with a SharedSizeGroup instead of DockPanels. I.e.
<StackPanel Grid.IsSharedSizeScope="True">
<Grid Height="100" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="A"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Width="{Binding ElementName=LeftMenuText, Path=Width}"
DockPanel.Dock="Left"
Background="Yellow">
<TextBlock
Text="This is some text."/>
</StackPanel>
<StackPanel Grid.Column="1" DockPanel.Dock="Right"
Background="Orange">
</StackPanel>
</Grid>
<DockPanel
Height="3"
Background="Black"></DockPanel>
<Grid Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="A"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Name="LeftMenuWrapper"
DockPanel.Dock="Left"
Background="Yellow">
<TextBlock
Text="This is some text that is longer."/>
</StackPanel>
<StackPanel Grid.Column="1" DockPanel.Dock="Right"
Background="Blue">
</StackPanel>
</Grid>
</StackPanel>
The key things to remember are to give each column inside your grids a SharedSizeGroup with the same name ("A" in this example), and add Grid.IsSharedSizeScope="True" to a shared parent of the Grids (the StackPanel containing the Grids in this example)

Resources