TextBox content vertical stretch to available size - c#

My goal is a TextBox that accepts return but only shows 4 lines of text that is alligned to other lines of text, but I'm having some problems that basically seem to boil down to the question: What is the correct way to get the content of a TextBox to vertically stretch to the available space?
A minimal example looks like this:
<Window 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="150" d:DesignWidth="150">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="1" />
<Label Grid.Column="0" Grid.Row="1" Content="2" />
<Label Grid.Column="0" Grid.Row="2" Content="3" />
<Label Grid.Column="0" Grid.Row="3" Content="4" />
<TextBox Grid.Column="1" Grid.Row="0" Grid.RowSpan="4" VerticalContentAlignment="Stretch" VerticalAlignment="Stretch" AcceptsReturn="True" MaxLines="4" Text="1
2
3
4" />
</Grid>
</Window>
But the output is not what I expected:
I tried setting the LineHeigt, but it only "cuts off" the text:
<TextBox Grid.Column="1" Grid.Row="0" Grid.RowSpan="4" VerticalContentAlignment="Stretch" VerticalAlignment="Stretch" AcceptsReturn="True" MaxLines="4" Text="1
2
3
4" TextBlock.LineStackingStrategy="MaxHeight" TextBlock.LineHeight="18" VerticalScrollBarVisibility="Visible" />
edit
Setting a fixed height for the TextBox corrects the behaviour, but that's not really a good way to solve the problem.

The immediate reason for your current issue is because you're using Label instead of TextBlock
The issue this causes is that TextBox renders lines as TextBlock which is a framework element. Whereas Label is a templated control inheriting from ContentControl and has a Padding set by default within it.
So if you you want them to align in your scenario you've got some options such as;
Curb the padding on your Label's;
<Label Padding="0"/>
Or swap them for good old TextBlock (which by the way is a "lighter" control and suggested instead unless using Label is actually necessary).
Or you could adjust your TextBox to reflect the padding of your Label's by targeting TextBlock with attached properties like TextBlock.LineHeight and TextBlock.LineStackingStrategy="BlockLineHeight" which would take some tinkering to get the exact output you want.
Also keep in mind TextBox is also a templated control with an embedded ScrollViewer so there will be a 1px offset for the default BorderThickness
So keeping your original control pairs if we do something like this instead, you'll see the culprit as example;
<Grid ShowGridLines="True"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Label Content="1" Padding="0"/>
<Label Grid.Row="1" Content="2" Padding="0"/>
<Label Grid.Row="2" Content="3" Padding="0"/>
<Label Grid.Row="3" Content="4" Padding="0"/>
<TextBox BorderThickness="0"
Grid.Column="1" Grid.RowSpan="4"
VerticalAlignment="Top"
VerticalContentAlignment="Stretch"
AcceptsReturn="True" MaxLines="4"
Text="1
2
3
4" />
</Grid>
Giving the result of;
Hope this helps, cheers.

A textbox could be stretched if it is inside a viebox, like this:
<Viewbox Stretch="Uniform" Grid.Column="1" Grid.Row="0" Grid.RowSpan="4" >
<TextBox Name="textBox" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" Text="1
2
3
4"/>
</Viewbox>
But in similar condition, I'd like to use a DataGrid

Just wrap the Textbox into Grid and set his MaxHeight to Infinity and his Height Value from that Grid:
<Grid x:Name="ValueTextBoxGrid" Grid.Row="1">
<TextBox
MaxHeight="Infinity"
Text="Your Text"
TextWrapping="Wrap"
Height="{Binding ElementName=ValueTextBoxGrid,
Path=ActualHeight}" />
</Grid>

Related

Why does the border stop rendering its minus margin while resizing the grid

I've used a border with negativ margin to mark a grid row. But I get a strange behaviour while resizing the window. Cutting the second column of the row makes the margin of the border disappear:
Of course this is a small example, in the main application I'm using a grid splitter, but the bahaviour stays the same. Is it possible to fix this somehow or is it a WPF bug?
MainWindow.xaml:
<Window x:Class="TestHighlightBorder.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestHighlightBorder"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="100,0,0,0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Border Background="DarkRed" Opacity="0.3" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Margin="-80,0,0,0" Panel.ZIndex="1" />
<TextBlock Text="column 0" Background="LightBlue" Grid.Row="0" Grid.Column="0" />
<TextBlock Text="column 2" Background="LightGreen" Grid.Row="0" Grid.Column="2" />
</Grid>
ps:
This is how the main application looks like. It's some sort of a propertygrid. The amount of the negativ margin depends on the level of nested objects.
I tried your example and it happens just as you said: column 2 gone, margin gone.
This seems to happen whenever the grid can't be displayed completely.
If, for example you set the third column definition to 200, the margin disappears as soon as column 2 isn't shown in it's entirety. Same thing happens when you resize the window from the bottom.
If you put the existing grid in another container (Grid, StackPanel, etc.) and set the MinWidth to something at least the size of the width of the columns + margin (in your example 310), this doesn't happen.
Like so:
<StackPanel MinWidth="310">
<Grid Margin="100,0,0,0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Border Background="DarkRed" Opacity="0.3" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Margin="-80,0,0,0" Panel.ZIndex="1" />
<TextBlock Text="column 0" Background="LightBlue" Grid.Row="0" Grid.Column="0" />
<TextBlock Text="column 2" Background="LightGreen" Grid.Row="0" Grid.Column="2" />
</Grid>
</StackPanel>
Instead of adding a 100 left-margin to the grid, you could just fix a column at the beginning with the width of 100, set the column-span of the border to 4, replace the negative margin with 20 positive left-margin (100-80=20), and add 1 to the value of Grid.Column for each of your controls. So the final approach would look like that:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Border Background="DarkRed" Opacity="0.3" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4" Margin="20,0,0,0" Panel.ZIndex="1" />
<TextBlock Text="column 0" Background="LightBlue" Grid.Row="0" Grid.Column="1" />
<TextBlock Text="column 2" Background="LightGreen" Grid.Row="0" Grid.Column="3" />
</Grid>

WPF: TreeView height

I'm using a TreeView in WPF that has an explicit height set. The vertical scrollbar is cut off at the bottom (independent of whether items are bound/shown or not; I've enabled the scrollbar to be able to reproduce the problem without items attached). XAML source below.
<Window x:Class="demo.TreeViewProblem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="..."
ResizeMode="CanResizeWithGrip"
SizeToContent="WidthAndHeight">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock
Grid.Column="0"
Grid.Row="0"
Margin="5,10,5,5"
Text="Some label"/>
<TextBlock
Grid.Column="1"
Grid.Row="0"
Margin="5,10,5,5"
Text="Some value"/>
<TreeView
ScrollViewer.VerticalScrollBarVisibility="Visible"
Grid.Column="1"
Grid.Row="1"
Height="200"
MinHeight="200"
Width="300"
Margin="5,10,5,5"
VerticalAlignment="Top" />
<TextBlock
Grid.Column="0"
Grid.Row="2"
Margin="5,10,5,5"
Text="Some label"/>
<TextBox
Grid.Column="1"
Grid.Row="2"
Width="80"
Margin="5,10,5,5"
HorizontalAlignment="Left"
Text="Some value"/>
<TextBlock
Grid.Column="0"
Grid.Row="3"
Margin="5,10,5,5"
Text="Some label"/>
<TextBox
Grid.Column="1"
Grid.Row="3"
Width="80"
Margin="5,10,5,5"
HorizontalAlignment="Left"
Text="Some value"/>
<Button
HorizontalAlignment="Center"
Margin="10,10,10,10"
Content="Close"
Grid.ColumnSpan="2"
Grid.Column="0"
Grid.Row="4"/>
</Grid>
</Window>
Change the RowDefinition for the row containing your TreeView to this:
<RowDefinition Height="Auto" />
When set to "Auto", the row will calculate how much space it needs.
EDIT: Alternatively, you could set the other rows to Auto and then make your TreeView stretch instead. With this approach your window will scale nicer when the user resizes it.
From the row definitions:
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
From the tree:
<TreeView VerticalAlignment="Stretch"
... />

How can I keep dynamic sized controls aligned?

I have a WPF application and I am looking for a way to align some Label and TextBox controls so that the TextBox controls are always inline, but also allow for the Label content to be dynamic (which should move the TextBoxes as required).
It is a little hard to explain so here are a couple of screenshots that should show my requirements...
Before:
After:
Notice how the first TextBox shifts to the right in order to make room for the longer text, while the second TextBox also shifts to keep inline with the first. (The behavior I want is similar to that of an HTML table with two rows of two cells each)
Keeping in mind I am fairly new to WPF (so I may be going down the wrong road completely), I have used a couple of StackPanels in order to cater for the dynamic sized labels. However, the problem of course is that both StackPanels do not know about each other.
Here is my current code:
<StackPanel Orientation="Horizontal">
<Label Content="Label 1" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="200"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Label 2" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="200"/>
</StackPanel>
Is there anyway to get what I want by using StackPanels? If not, what other controls or methods can I use to meet my requirements?
If you want the columns to be sized the same for all controls, simply use a Grid.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="23"/>
<RowDefinition Height="23"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Longer Label 1"/>
<TextBox Grid.Row="0" Grid.Column="1" TextWrapping="Wrap"/>
<Label Grid.Row="1" Grid.Column="0" Content="Label 2" />
<TextBox Grid.Row="1" Grid.Column="1" TextWrapping="Wrap"/>
</Grid>
With this setup, the first column will size to fit the widest label, and the second will take up the rest.
Just use a Grid:
<Grid Grid.Row="2" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
...
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Grid.Column="0" Text="Name" Style="{StaticResource
LabelStyle}" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Name,
UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource TextBoxStyle}" />
<TextBox Grid.Row="1" Grid.Column="0" Text="Age" Style="{StaticResource
LabelStyle}" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Age,
UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource TextBoxStyle}" />
...
</Grid>

Vertically align tops of blocks of text in WPF

I'm trying to visually align the top of the content of 2 (or more) blocks of Text.
The content and the Font (Size, Family, Weight) of each block can be modified by user.
I tried to play with the GetCellAscent, GetCellDescent and GetLineSpacing functions but the results depends only on the font and not the real content. And anyway I can't find how is distributed the difference between LineSpacing and Ascent+ Descent at the top and bottom of the block.
For example I want to produce this kind of output:
Any help?
Try This.....
<Grid Width="171" Height="100" Background="Black" Margin="257,78,75,133">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Name="aaa" Text="12" FontSize="40" HorizontalAlignment="Center" VerticalAlignment="Stretch" Grid.Row="1" FontWeight="Bold" Foreground="White" />
<TextBlock Text="$" HorizontalAlignment="Left" FontSize="20" Grid.Column="1" FontFamily="Euphemia" FontWeight="Bold" Foreground="White" Margin="8,0,72,0" />
<TextBlock Text="00 le Kg" FontSize="15" Grid.Column="1" Grid.Row="3" HorizontalAlignment="Left" Grid.IsSharedSizeScope="True" FontFamily="Euphemia" FontWeight="Bold" Foreground="White"/>
</Grid>

How to make selectable text with 100% height and 100% width of a Grid Cell

I have a Silverlight application and I try to display a generated text into a Cell of my grid. Unfortunately the TextBox does not seem to be able to have a stretching height and stretching width to his parent size. For the moment, I have simply use a ScrollViewer and Set the content but I can't select the text so I still have a problem.
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="500*" />
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Button Content="Generate" Grid.Row="1" HorizontalAlignment="Left" Name="button1" VerticalAlignment="Top" Height="50" Click="GenerateSerialization" />
<ScrollViewer Name="scrollText" Grid.Column="2"></ScrollViewer>
<sdk:GridSplitter Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" Name="gridSplitter1" VerticalAlignment="Stretch" />
</Grid>
Sorry... when I think I understand English I see have a lot of road to travel :o)
Check this:
<ScrollViewer Name="scrollText"
HorizontalScrollBarVisibility="Disabled"
Grid.Column="2">
<TextBox TextWrapping="Wrap"
Text="Bla, bla, bla..." />
</ScrollViewer>

Categories

Resources