# .NET and More > WPF, WCF, WF >  [WPF] TextBlock in Border shrink below text size

## NickThissen

Hi,

I am building a 'DataGrid' from scratch. The main element is a Grid with 4 columns and 3 rows. These 4 columns also represent the 4 columns of the 'DataGrid' (there will always be 4 columns, and the user cannot resize them. This is not a generic grid, it only fits this one project with the data I have). The 3 rows contain:
1. A row of 4 column headers (Borders with TextBlocks inside)
2. A row of 4 ComboBoxes (to filter the data rows)
3. A ListBox (spans all 4 columns) to show the data rows.

The ListBox has an ItemTemplate with another Grid with the same 4 columns (so that the headers, comboboxes and data columns are the same width), each of which contains a Border with a TextBlock to hold a specific part of the data.

The XAML is this:

xml Code:
<UserControl x:Class="PaperManager.Controls.PapersGrid"             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"              mc:Ignorable="d"              d:DesignHeight="422" d:DesignWidth="642">        <UserControl.Resources>        <Style TargetType="ComboBox">            <Setter Property="Margin" Value="2" />        </Style>         <Style x:Key="StretchedContainerStyle" TargetType="{x:Type ListBoxItem}">            <Setter Property="HorizontalContentAlignment" Value="Stretch" />        </Style>         <Style x:Key="ItemBorderStyle" TargetType="Border">            <Setter Property="BorderBrush" Value="LightGray" />            <Setter Property="BorderThickness" Value="1" />            <Setter Property="CornerRadius" Value="1" />            <Setter Property="Margin" Value="1" />            <Setter Property="Padding" Value="2" />        </Style>         <Style x:Key="HeaderBorderStyle" TargetType="Border" BasedOn="{StaticResource ItemBorderStyle}">            <Setter Property="BorderBrush" Value="#FFFFFF" />                <Setter Property="BorderThickness" Value="0" />            <Setter Property="CornerRadius" Value="0" />            <Setter Property="Margin" Value="-1" />            <Setter Property="Padding" Value="2" />            <Setter Property="Height" Value="35" />            <Setter Property="Background">                <Setter.Value>                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">                        <GradientStop Offset="0" Color="AliceBlue" />                        <GradientStop Offset="0.3" Color="LightBlue" />                        <GradientStop Offset="0.3" Color="LightBlue" />                        <GradientStop Offset="1.3" Color="AliceBlue" />                    </LinearGradientBrush>                </Setter.Value>            </Setter>        </Style>    </UserControl.Resources>     <Grid>        <Grid.ColumnDefinitions>            <ColumnDefinition Width="*" />            <ColumnDefinition Width="2.5*" />            <ColumnDefinition Width="*" />            <ColumnDefinition Width="*" />        </Grid.ColumnDefinitions>        <Grid.RowDefinitions>            <RowDefinition Height="Auto" />             <RowDefinition Height="Auto" />            <RowDefinition Height="*" />        </Grid.RowDefinitions>         <!-- Headers -->        <Border Style="{StaticResource HeaderBorderStyle}" Grid.Column="0">            <TextBlock Text="Authors" HorizontalAlignment="Center" VerticalAlignment="Center"/>        </Border>        <Border Style="{StaticResource HeaderBorderStyle}" Grid.Column="1">            <TextBlock Text="Title" HorizontalAlignment="Center" VerticalAlignment="Center" />        </Border>        <Border Style="{StaticResource HeaderBorderStyle}" Grid.Column="2">            <TextBlock Text="Journal" HorizontalAlignment="Center" VerticalAlignment="Center" />        </Border>        <Border Style="{StaticResource HeaderBorderStyle}" Grid.Column="3">            <TextBlock Text="Categories" HorizontalAlignment="Center" VerticalAlignment="Center" />        </Border>         <!-- Filter ComboBoxes -->        <ComboBox Grid.Row="1" Grid.Column="0" IsEditable="True" Text="{Binding Path=SelectedAuthor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=Authors, UpdateSourceTrigger=PropertyChanged}" IsTextSearchEnabled="False" />        <ComboBox Grid.Row="1" Grid.Column="1" IsEditable="True" Text="{Binding Path=SelectedTitle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=Titles, UpdateSourceTrigger=PropertyChanged}" IsTextSearchEnabled="False" />        <ComboBox Grid.Row="1" Grid.Column="2" IsEditable="True" Text="{Binding Path=SelectedJournal, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=Journals, UpdateSourceTrigger=PropertyChanged}" IsTextSearchEnabled="False" />        <ComboBox Grid.Row="1" Grid.Column="3" IsEditable="True" Text="{Binding Path=SelectedCategory, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=Categories, UpdateSourceTrigger=PropertyChanged}" IsTextSearchEnabled="False" />         <!-- Grid -->        <ListBox Grid.Row="2" Grid.ColumnSpan="4"             ItemsSource="{Binding Path=Papers, UpdateSourceTrigger=PropertyChanged}"             SelectedItem="{Binding Path=SelectedPaper, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"             ItemContainerStyle="{StaticResource StretchedContainerStyle}">            <ListBox.ItemTemplate>                <DataTemplate>                    <Grid >                        <Grid.ColumnDefinitions>                            <ColumnDefinition Width="*" />                            <ColumnDefinition Width="2.5*" />                            <ColumnDefinition Width="*"  />                            <ColumnDefinition Width="*"  />                        </Grid.ColumnDefinitions>                         <Border Grid.Column="0" Style="{StaticResource ItemBorderStyle}">                            <TextBlock Text="{Binding AllAuthors}" VerticalAlignment="Top" />                        </Border>                         <Border Grid.Column="1" Style="{StaticResource ItemBorderStyle}">                            <TextBlock Text="{Binding Title}" VerticalAlignment="Top" FontWeight="Bold" />                        </Border>                         <Border Grid.Column="2" Style="{StaticResource ItemBorderStyle}">                            <TextBlock Text="{Binding JournalDetails}" VerticalAlignment="Top" />                        </Border>                         <Border Grid.Column="3" Style="{StaticResource ItemBorderStyle}">                            <TextBlock Text="{Binding AllCategories}" VerticalAlignment="Top" />                        </Border>                    </Grid>                </DataTemplate>            </ListBox.ItemTemplate>        </ListBox>    </Grid></UserControl>

When large enough to accomodate all data, the grid looks like this: 



Now, when I make the window smaller, the columns resize accordingly (since they use "*" widths), which is correct. However, once a columns gets smaller than the width of the text it is displaying in its data row, then it seems the data row no longer cares about the star resizing and simply retains a minimum width in order to keep displaying all the text:


This is not what I want! 


For now, what I would like to see is that the borders/textblocks in the data rows simply become smaller (the same width as the column headers and comboboxes above) and simply cut off the text. 

A slightly better approach would be to get text trimming to work (so that the text is not just cut off but shows some ellipsis, "..." instead).

The best approach would be to wrap the text over multiple lines (usually there will be multiple authors / categories so that the data row is already larger than one line, so that is room wasted at the moment).

I have tried every kind of combination I could think of to get the TextBlocks to wrap (TextWrapping) or trim (TextTrimming), but nothing, the behavior remains as in the second screenshot... 


How can I do this? I don't understand why this is happening in the first place. I clearly tell the columns to have widths *, 2.5*, * and *. This is the case in the first row (the second column is 2.5 times as wide as the three others), but certainly not in the second row (otherwise the columns would be equally long...). So for some reason the textblocks are overriding these width settings?

Thanks!

----------


## Evil_Giraffe

The grid is being intelligent and fudging the column widths to display all your content.  The other three columns don't need all the space, so it's okay for that second column to be a bit wider.

That is, unless the grid column widths are supposed to line up with something else...

What you need to use is the Grid's SharedSizeGroup feature.  Give the column definitions a SharedSizeGroup attribute that is the same for the same columns in each grid (that is, the first column in each grid gets (for example) SharedSizeGroup="column_authors", second column in each grid gets SharedSizeGroup="column_title" and so on).

You then need to tell WPF that these size groups are scoped to the control, so on your UserControl add the Grid.IsSharedSizeScope attached property and set it to True.

----------


## Evil_Giraffe

As to why the text blocks won't wrap/trim: They are asking for as much space as they need from the layout engine.  The layout engine sees no reason why it can't give it to them, so they get it.

Wrapping/trimming only comes in to play when the layout engine doesn't give them as much space as they need to display the full text.

As an additional point to the above, you only need to specify the widths of the columns on the header grid once you set the sizegroup on all the columns.  I would expect then that WPF will layout the grid column widths taking only the contents in that grid into account, meaning the grids in the listview will be given a width, rather than given an opportunity to ask for how much space they need.  You will probably therefore see trimming/wrapping spring into effect if you have it set up.

----------


## NickThissen

Thanks. I have tried using shared size groups, but got some really strange results. 

Try #1: the top grid columns get the widths while the DataTemplate grid columns merely get the SharedSizeGroups. Then I put the Grid.IsSharedSizeScope property on the UserControl as you said (that seems a bit strange, but I just tried it)

xml Code:
<UserControl Grid.IsSharedSizeScope="true">    <Grid>        <Grid.ColumnDefinitions>            <ColumnDefinition Width="*" SharedSizeGroup="A"/>            <ColumnDefinition Width="2.5*" SharedSizeGroup="B"/>            <ColumnDefinition Width="*" SharedSizeGroup="C"/>            <ColumnDefinition Width="*" SharedSizeGroup="D"/>        </Grid.ColumnDefinitions>    </Grid>        ...        <ListBox ...>        <ListBox.ItemTemplate>            <DataTemplate>                    <Grid>                        <Grid.ColumnDefinitions>                            <ColumnDefinition SharedSizeGroup="A"/>                            <ColumnDefinition SharedSizeGroup="B"/>                            <ColumnDefinition SharedSizeGroup="C"/>                            <ColumnDefinition SharedSizeGroup="D"/>                        </Grid.ColumnDefinitions>                    </Grid>                                        ...            </DataTemplate>        </ListBox.ItemTemplate>    </ListBox></UserControl>
Result, believe it or not, is that the grid columns seem to double in size about every second. 

The same happens when I put the Grid.IsSharedSizeScope on the top level grid.

When I put it on the grid in the DataTemplate, no weird 'animations' occur but the columns in the DataTemplate simply don't follow (they all seem to get a width of Auto which is probably the default, so it seems they are ignoring the shared size groups completely).


I can't figure out the right combination of properties here... 
I did read this blog post which seems to explain exactly what I want to do, except it also allows for resizing the columns. I've downloaded his sample, and I don't like his grid at all, when you resize a column the other columns start resizing like mad as well, I definitely don't want that, so I decided to stay with static columns. I'm completely fine with that, columns don't need to resize (it would be much better if the contents wrapped instead), except if the window width changes (in which case the * resizing should do its job and resize thme correctly).

Anyway, that post tells me that using shared size groups doesn't really work as well with * resizing, and he goes through all kinds of trouble (databinding) to get it to work after all. So maybe it's not as simple as setting the shared size group, since I am using * resizing on every column?

----------

