One layout issue many folks run into in WPF and Silverlight is
the problem of ListBox content not automatically sizing to the
width of the ListBox.
Using my WPF Twitter Application video as an example,
here's a shot with it with the items not fitting correctly. Compare
to the second screen shot, and you can see the text has scrolled
off the right of the ListBox.
Here's a shot with the ListBox fixed, and the items all fit in
place. Notice that the text has wrapped and there is no horizontal
scrollbar.
Luckily, the solution is pretty simple: You just need to do four
things, but because it is a combination of these things, the
solution often eludes folks:
- Use a grid as the root element of your
ItemTemplate/DataTemplate
- Tell the ListBox to disable horizontal scrolling.
- Wrap or clip any text
- Use * sizing, not Auto sizing for variable width columns
Here's the updated Xaml. Note the highlighted lines.
<ListBox Margin="12,83,12,12"
Name="listBox1"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Path=Tweets}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- In the video, this is in a UserControl. That's still ok to do. -->
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding Path=FromImage}"
Height="70"
VerticalAlignment="Top"
Grid.RowSpan="2" />
<TextBlock Text="{Binding Path=From}"
Grid.Column="1" />
<TextBlock Text="{Binding Path=Text}"
TextWrapping="Wrap"
Grid.Column="1"
Grid.Row="1" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here's an explanation of why:
1. Use a Grid
The Grid is the most powerful and flexble of the standard panel
controls. It also has provisions to ensure that it stays at a width
which does not exceed what it has been allowed. If you use another
panel, they may stretch their content to the right and otherwise
not behave well in a listbox.
2. Disable Horizontal Scrolling
When horizontal scrolling is enabled, the listbox allows the
content to be any width. When disabled, the listbox constrains the
items width to be the visible width on-screen.
3. Wrap or Trim, or Clip Text
When #1 and #2 are in place, but you do not wrap text, the text
will simply be truncated. If you trim it (using TextTrimming) or
clip it (using the default clip or your own), the text will take up
only the amount of space you want it to. This isn't required to get
layout to work the way you want, but it is required to get the
result to look the way you want.
4. Use Star Sizing instead of Auto Sizing for Width
If you set the width of your grid columns to be "Auto" for the
bits that are pushing out the horizontal size of the template,
Silverlight and WPF will gladly give your grid all the room it
needs. "Auto" means, "give me what I want". If you set it to "*"
(Star), the grid will give your element the room that is
available. If you set the variable-width column to
a fixed number, you will always get that size, even if the ListBox
doesn't really have it. Always set the columns containing
variable-width content to have a Width of * or a multiple of * like
2* if your layout is more complex. The other items can have Auto or
fixed (a number) width.
That's all there is to it. This will solve 90% of the ListBox
sizing issues out there. If it's not working for you, start
dismantling your DataTemplate element-by-element and see if you've
got something in there that's forcing the list box item to be a
wider width.