WPF and wrapping text inside elements of a ListView

TextBlock have the possibility to wrap, but sometimes you can get surprised by its behaviour. When I first began to work in WPF I started to use ListView to show complex object, because of the rich possibility to format the output with great flexibility. One day I created this little listview.

<ListView x:Name="GroupsView" ItemsSource="{Binding}" > <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock TextWrapping="Wrap" Margin="2,0,2,0" Text="{Binding Path=LogIdentifier}" VerticalAlignment="Center" FontSize="14" /> <TextBlock Margin="2,0,2,0" Text="Count:" FontWeight="Bold" VerticalAlignment="Center" FontSize="14" /> <TextBlock Margin="2,0,2,0" Text="{Binding Path=Messages.Count}" VerticalAlignment="Center" FontSize="14" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView>

It is a simple list and each element is composed by three textblock, the first should be the long one and I want it to wrap when the form is resized, the other two are small and should stay to the right. When I launched the form the result is not the desidered one, the first text does not wrap , nor the Count: is aligned to the right. The first error is that you should use DockPanel when you want elements to stay somewhere (right in this situation) and you want one of the element to fill remaining space, then I moved to this solution.

<ListView x:Name="GroupsView" ItemsSource="{Binding}" > <ListView.ItemTemplate> <DataTemplate> <DockPanel > <TextBlock TextWrapping="Wrap" Margin="2,0,2,0" Text="{Binding Path=LogIdentifier}" VerticalAlignment="Center" FontSize="14" /> <TextBlock DockPanel.Dock="Right" Margin="2,0,2,0" Text="Count:" FontWeight="Bold" VerticalAlignment="Center" FontSize="14" /> <TextBlock DockPanel.Dock="Right" Margin="2,0,2,0" Text="{Binding Path=Messages.Count}" VerticalAlignment="Center" FontSize="14" /> </DockPanel> </DataTemplate> </ListView.ItemTemplate> </ListView>

You can be still surprised that the result is not the desidered one, the first textblock does not gets wrapped, and “count: X” text is still not aligned to the right. To understand why the layout is arranged in such a way you should consider how the various container constrain dimension for their content. In this post you can find a good description. We have to face two problems, the first is that we want the content of our ListView to have X size equal to that of the listview itself, this can be accomplished with HorizontalContentAlignment="Stretch" attribute, that instructs the ListView to stretch the X size of its content on the horizontal size of the list itself. Then you should instruct the ListView not to show horizontal scrollbar. When scrollbar are enabled the listview grabs the “desidered size” of the controls, then it renders scrollbars accordingly, thus avoiding the word wrapping. To disable scrollbar you can simply use the attribute ScrollViewer.HorizontalScrollBarVisibility="Disabled". Finally you should notice that the order of the elements in the DockPanel is wrong. The dockPanel starts aligning from the first control to the last, and if the last has no DockPanel.Dock specified it is considered to fill remaining space. I need to work from right to left, first element is the number of count, then the Count: string, both with right alignment, finally the text that I wanted to wrap with no Dock specified.

<ListView x:Name="GroupsView" ItemsSource="{Binding}" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> <ListView.ItemTemplate> <DataTemplate> <DockPanel > <TextBlock DockPanel.Dock="Right" Margin="2,0,2,0" Text="{Binding Path=Messages.Count}" VerticalAlignment="Center" HorizontalAlignment="Right" FontSize="14" /> <TextBlock DockPanel.Dock="Right" Margin="2,0,2,0" Text="Count:" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Right" FontSize="14" /> <TextBlock TextWrapping="WrapWithOverflow" Margin="2,0,2,0" Text="{Binding Path=LogIdentifier}" VerticalAlignment="Center" FontSize="14" /> </DockPanel> </DataTemplate> </ListView.ItemTemplate> </ListView>

Finally I got what I wanted.

image

I’m doing this post because this morning I woke up early, and wrote again the same wrong XAML (errare umanum est …), when I launch the application I though “mmm I solved this long time ago…” and begin crawling in my projects, then I preferred to do a post, so the next time I can search in my blog. 😀

Alk.

Tags:

DotNetKicks Image

Published by

Ricci Gian Maria

.Net programmer, User group and community enthusiast, programmer - aspiring architect - and guitar player :). Visual Studio ALM MVP

5 thoughts on “WPF and wrapping text inside elements of a ListView”

  1. Thanks a lot. I spent all morning trying to get my textblocks to wrap. Another thing to watch out for is using a StackPanel with Orientation=”Horizontal”. That will also cause textblocks not to wrap.

  2. Thank you so much for explaining this, I was pulling my hair out. I visited so many articles but none explained the problem. Yours explained it clearly and it now makes sense.

  3. That you for this article… I have been pulling my hair out for hours trying to work this out, the scroll bar was the final piece of the puzzle!

Leave a Reply

Your email address will not be published.