28
votes

I have a ListBox with it's ItemTemplate bound to a DataTemplate. My problem is I cannot get the elements in the template to stretch to the full width of the ListBox.

<ListBox x:Name="listPeople" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" 
    Margin="0,0,0,0" Background="{x:Null}" SelectionMode="Extended" Grid.Row="1" 
    ItemTemplate="{StaticResource PersonViewModel.BrowserDataTemplate}" 
    ItemsSource="{Binding Mode=OneWay, Path=SearchResults}" >
</ListBox>

<DataTemplate x:Key="PersonViewModel.BrowserDataTemplate">
   <ListBoxItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
     <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5">
       <Border Opacity=".1" x:Name="itemBorder"  Background="#FF000000"   
         HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
         CornerRadius="5,5,5,5" MinWidth="100" Height="50"/>
      </Grid>
   </ListBoxItem>
</DataTemplate>

As you can see, I have added a border within the grid to indicate the width of the template. My goal is to see this border expand to the full width of the listbox. Currently its width is determined by its contents or MinWidth, which is the only thing at the moment keeping it visible at all.

6
I'm sure this has come up before, so I should know the answer to this, but: Does Silverlight's ListBox have a HorizontalContentAlignment property? If so, that's the one you want to set to "Stretch".Matt Hamilton
You need to set the HorizontalContentAlignment property on ListBoxItem, not ListBox, to "Stretch".markti

6 Answers

68
votes

I spent an hour trying to resolve this one. Very very frustrasting. You don't have to override the entire default style for the ListBoxItem. I couldn't get this to work. In the end I resolved the issue by simply overriding just the HorizontalContentAlignment property in my ListBox.ItemContainerStyle section e.g:

            <ListBox x:Name="ClassList" ItemsSource="{Binding LineClasses}"
                     ScrollViewer.VerticalScrollBarVisibility="Visible"
                     SelectionMode="Extended"
                     ScrollViewer.HorizontalScrollBarVisibility="Hidden" HorizontalContentAlignment="Stretch"
                     HorizontalAlignment="Stretch" Loaded="ClassList_Loaded"
                     VerticalAlignment="Stretch" Grid.Row="0">
                <ListBox.ItemContainerStyle>
                    <Style TargetType="ListBoxItem">
                        <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
                    </Style>
                </ListBox.ItemContainerStyle>
                    <ListBox.ItemTemplate>

                    <DataTemplate>
                        <Border BorderBrush="Black" CornerRadius="3" Background="#FFE88D34"
                            BorderThickness="1" HorizontalAlignment="Stretch" >
                            <Grid Background="Transparent" HorizontalAlignment="Stretch" >
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <TextBlock 
                                    Grid.Column="0" HorizontalAlignment="Stretch"
                                    Margin="2"                                   
                                    FontSize="10"
                                    Text="{Binding DisplayClassNm}"/>
                            </Grid>

                        </Border>
                    </DataTemplate>
                </ListBox.ItemTemplate>

This worked a treat for me.

Myles

29
votes

When creating Data Templates for ListBox, you should not incldue <ListBoxItem>. The contents of the DataTemplate will be placed inside of a generated container. You can control how that container is constructed using ItemContainerStyle.

The default control style for ListBoxItem is used to define the ItemContainerStyle by default. This style sets the ListBoxItem.HorizontalContentAlignment property to 'Left'. Notice how the ContentPresenter binds its HorizontalAlignment to this property.

You need to override the style of the ListBoxItem container that is being generated when you bind to your ListBox. This can be done by setting the ItemContainerStyle. Set the HorizontalContentAlignment property to be "Stretch".

Below is the default ListBoxItem Style. Included for reference.

<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
            <Setter Property="Padding" Value="3"/>
            <Setter Property="HorizontalContentAlignment" Value="Left"/>
            <Setter Property="VerticalContentAlignment" Value="Top"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="TabNavigation" Value="Local"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Grid Background="{TemplateBinding Background}">
                            <!-- VSM excluded for readability -->
                            <Rectangle x:Name="fillColor" Fill="#FFBADDE9" RadiusX="1" RadiusY="1" IsHitTestVisible="False" Opacity="0"/>
                            <Rectangle x:Name="fillColor2" Fill="#FFBADDE9" RadiusX="1" RadiusY="1" IsHitTestVisible="False" Opacity="0"/>
                            <ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
                            <Rectangle x:Name="FocusVisualElement" Stroke="#FF6DBDD1" StrokeThickness="1" RadiusX="1" RadiusY="1" Visibility="Collapsed"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
1
votes

Here is an example of using the control templates and data templates for the listbox control. Refer to the XAML markup which streaches the border for the listbox items.

0
votes

My ListBoxItem contained a CheckBox and the above solutions did not work for me (most likely due to the nature of a CheckBox, not those solutions) I was able to coerce this functionality by not binding to the "Content" property of the checkbox, but explicitely defining the XAML inline:

<CheckBox HorizontalAlignment="Stretch" IsChecked="{Binding Path=IsSelected, Mode=TwoWay}">
    <TextBlock
        MinWidth="130"
        Margin="0,-2,0,0"
        HorizontalAlignment="Stretch"
        Text="{Binding Path=DisplayText}" />
</CheckBox>

The margin is needed because the TextBox text did not align with the CheckBox's checkmark. The MinWidth was also necessary.

0
votes

I am working with Silverlight 5 with VS 2012. I have the same issue. I have horizontal listbox with my own custom objects as ItemsSource. I want listbox items to expand. But they are not expanding. I donot want to give any hard coded width for every listbox item. I tried all answers here but nothing works. I just gave ItemsSource ={Binding Persons} DisplayMemberPath="First Name". Thats all

-1
votes

Two things I noticed here, because I had the same issue and wasn't able to solve it the way you're trying.

First, you don't need to explicitly put a ListBoxItem in your DataTemplate. This is created for you automatically, so you actually have your ListBoxItem inside of the one that was created for you. I checked this out in Snoop to confirm.

Second, and I don't know exactly why, but I wasn't able to get the stretching behavior out of the alignment attributes either. I changed it to use RelativeSource binding on the Width attribute to the ActualWidth property of the containing ListBoxItem. This worked for me.

Width="{Binding RelativeSource={RelativeSource 
   AncestorType={x:Type ListBoxItem}}, Path=ActualWidth}"

If you need to set style properties on the ListBoxItem that is implicitly created for you, use a Style element inside of the ListBox.ItemContainerStyle element.

Hope this helps...