I have started to learn WPF and my first task has been to explore the most basic controls, such as the textbox. It has caught my attention as in WPF everything is much more customizable and powerful, but it has caught my attention how the design of the default textbox differs from those of Winforms, acquiring a rather ugly design.
In the following image we see a textbox with the selected text. One textbox with Winforms and one textbox with WPF.
As you can see, in Winforms the upper and lower highlighting space (highlighted in violet) of the selection is distributed equally, while in WPF the upper part is much larger giving a rather "ugly" appearance to the textboxes when the text is selected.
Edit: Seems that some users don't get the problem correctly. So I go to add the xaml of the WPF textbox is next:
<TextBox HorizontalAlignment="Left" Margin="183,172,0,0" Text="TextBox" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
When I change the property to VerticalAlignment="Center" issue is solved until you change the FontSize which makes the problem reappear. The problem is that my font size is 16px.
I would like to know if there is any way to fix this visual misalignment, because I really don't understand why they have left so much space at the top of the text selection.
Probably I should have touched on the cause of the difference between top and bottom spaces of font glyphs. In short, the top space is reserved to draw symbols (diaeresis) above alphabetic characters.
The following code produces the TextBox shown below.
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.ColumnSpan="2"
Text="0ay/AÁÊÑÖ 0ay/AÁÊÑÖ"
FontFamily="Verdana" FontSize="36"
Padding="3"/>
<Rectangle Grid.Column="0"
Stroke="DarkViolet" StrokeThickness="1" StrokeDashArray="1 3"
VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
<Rectangle Grid.Column="1"
Stroke="Red" StrokeThickness="1" StrokeDashArray="1 3"
VerticalAlignment="Center" Margin="0,3,0,0" HorizontalAlignment="Stretch"/>
</Grid>
The area highlighted blue is the font area and the purple dotted line is the actual vertical center of font. If there were no symbol, you may think the red dotted line is the vertical center but it is not true. The font glyphs are slightly aligned to the bottom to accomodate spaces for symbols.
Setting VerticalContentAlignment="Center" can adjust the vertical alignment of the font inside TextBox but can not change the placement of font glyphs inside the font itself. Therefore, I think the only way to make font glyphs (except symbols) shown truly at the vertical center of TextBox is to move the font by arbitary length so as to offset the difference inside font.
Please note that the difference inside font may vary depending on each font and if the height of top space is cut out and if the text which has these symbols is typed, these symbols can be hidden.
That said, you can adjust the inner padding by setting Padding property as follows.
<TextBox Padding="0,-2,0,0" ClipToBounds="True" ... />
Or you can lower the space between font griph and padding by setting the line height of inner text if you do not mind it affects the spacing between multiples lines.
<TextBox Padding="2" FontSize="16"
TextBlock.LineHeight="18" TextBlock.LineStackingStrategy="BlockLineHeight" ... />
Edit: Add explanation and alternative suggestion to respond to OP's comment.
To center the content, in this case the text, you can use VerticalContentAlignment.
<TextBox VerticalContentAlignment="Center"... />
If you set the Height property, try to remove it. This affects the alignment in some way. If you vary the FrontSize, similar problems arise.
To find out how the Text-Property of a TextBox is aligned, I wrote a small app. In this, various properties can be changed using Controls and you can see the result immediately.
The source code of the app comes at the bottom of the answer.
As #emoacht has already described, all glyphs of the font are taken into account when calculating the space requirement.
The reference point for aligning the Text is at the top right.
In order to center a specific text, you could adjust the Padding-Property or the Height and FontSize-Property so that the text is centered.
Please note: I would not follow this approach. Since all of these properties influence each other, inconsistent behavior occurs. It would be enough for the user to enter characters or strings of characters that you hadn't considered and the whole alignment is gone. I think it's more important that the text is presented completely and correctly. And many users wouldn't even notice that the text isn't exactly in the middle.
The source Code of the TextBox - TestApp:
<Window x:Class="TextBoxTestApp.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:TextBoxTestApp"
xmlns:clr="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="TextBox - TestApp -- MK-NEUKO" Height="450" Width="800">
<Window.Resources>
<Style x:Key="testTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border BorderBrush="Black"
BorderThickness="1"
CornerRadius="2">
<Border.Background>
<LinearGradientBrush StartPoint="0, 0" EndPoint="0, 0.25"
SpreadMethod="Repeat">
<GradientStop Color="White"
Offset="0"/>
<GradientStop Color="Gray"
Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0"
Orientation="Horizontal"
Margin="5">
<GroupBox Header="Style Options">
<ComboBox x:Name="styleOptionsComboBox"
Margin="4"
VerticalAlignment="Center"
Width="100">
<ComboBoxItem Tag="{x:Null}"
IsSelected="True"
Content="Default Style"/>
<ComboBoxItem Tag="{StaticResource testTextBoxStyle}"
Content="Custom Style"/>
</ComboBox>
</GroupBox>
<GroupBox Header="TestText"
Width="300">
<TextBox x:Name="inputTestText"
Margin="4"
VerticalContentAlignment="Center"
Text="{Binding ElementName=testTextBox, Path=Text}"/>
</GroupBox>
<GroupBox Header="FontSize">
<StackPanel Orientation="Horizontal"
Margin="5">
<ComboBox x:Name="frontSizeSelect"
Margin="0,0,5,0">
<ComboBoxItem Tag="{x:Null}" Content="x:Null" IsSelected="True"/>
<ComboBoxItem Tag="{Binding ElementName=fontSizeSlider, Path=Value}" Content="On"/>
</ComboBox>
<Slider x:Name="fontSizeSlider"
TickFrequency="2"
Minimum="10"
Maximum="100"
TickPlacement="BottomRight"
Width="200"/>
<TextBlock Text="{Binding ElementName=fontSizeSlider, Path=Value, StringFormat=Value: {0:0}}"/>
</StackPanel>
</GroupBox>
<GroupBox Header="Height">
<StackPanel Orientation="Horizontal"
Margin="5">
<ComboBox x:Name="heightSelect"
Margin="0,0,5,0">
<ComboBoxItem Tag="{x:Null}" Content="x:Null" IsSelected="True"/>
<ComboBoxItem Tag="{Binding ElementName=heightSlider, Path=Value}" Content="On"/>
</ComboBox>
<Slider x:Name="heightSlider"
TickFrequency="4"
Minimum="20"
Maximum="200"
TickPlacement="BottomRight"
Width="200"/>
<TextBlock Text="{Binding ElementName=heightSlider, Path=Value, StringFormat=Value: {0:0}}"/>
</StackPanel>
</GroupBox>
<GroupBox Header="VerticalAlignment">
<ComboBox x:Name="verticalAlignment"
Margin="4">
<ComboBoxItem Tag="{x:Null}" Content="x:Null" IsSelected="True"/>
<ComboBoxItem Tag="Bottom" Content="Bottom"/>
<ComboBoxItem Tag="Center" Content="Center"/>
<ComboBoxItem Tag="Stretch" Content="Stretch"/>
<ComboBoxItem Tag="Top" Content="Top"/>
</ComboBox>
</GroupBox>
<GroupBox Header="VerticalContentAlignment">
<ComboBox x:Name="verticalContentAlignment"
Margin="4">
<ComboBoxItem Tag="{x:Null}" Content="x:Null" IsSelected="True"/>
<ComboBoxItem Tag="Bottom" Content="Bottom"/>
<ComboBoxItem Tag="Center" Content="Center"/>
<ComboBoxItem Tag="Stretch" Content="Stretch"/>
<ComboBoxItem Tag="Top" Content="Top"/>
</ComboBox>
</GroupBox>
<GroupBox Header="HorizontalAlignment">
<ComboBox x:Name="horizontalAlignment"
Margin="4">
<ComboBoxItem Tag="{x:Null}" Content="x:Null" IsSelected="True"/>
<ComboBoxItem Tag="Center" Content="Center"/>
<ComboBoxItem Tag="Left" Content="Left"/>
<ComboBoxItem Tag="Right" Content="Right"/>
<ComboBoxItem Tag="Stretch" Content="Stretch"/>
</ComboBox>
</GroupBox>
<GroupBox Header="HorizontalContentAlignment">
<ComboBox x:Name="horizontalContentAlignment"
Margin="4">
<ComboBoxItem Tag="{x:Null}" Content="x:Null" IsSelected="True"/>
<ComboBoxItem Tag="Center" Content="Center"/>
<ComboBoxItem Tag="Left" Content="Left"/>
<ComboBoxItem Tag="Right" Content="Right"/>
<ComboBoxItem Tag="Stretch" Content="Stretch"/>
</ComboBox>
</GroupBox>
<GroupBox Header="Select FontFamily">
<StackPanel Orientation="Horizontal"
Margin="4">
<ComboBox x:Name="selectFontFamily">
<ComboBoxItem Tag="{x:Null}" Content="x:Null" IsSelected="True"/>
<ComboBoxItem Tag="{Binding ElementName=fontFamilyTextBox, Path=Text}" Content="On"/>
</ComboBox>
<TextBox Margin="10,0,0,0" x:Name="fontFamilyTextBox" Width="300"/>
</StackPanel>
</GroupBox>
</WrapPanel>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<StackPanel>
<GroupBox Header="Padding Left">
<Slider x:Name="paddingLeftSlider"
Minimum="0"
Maximum="20"
TickFrequency="1"
TickPlacement="BottomRight"
IsSnapToTickEnabled="True"
ValueChanged="PaddingSliderValueChanged"/>
</GroupBox>
<GroupBox Header="Padding Top">
<Slider x:Name="paddingTopSlider"
Minimum="0"
Maximum="20"
TickFrequency="1"
TickPlacement="BottomRight"
IsSnapToTickEnabled="True"
ValueChanged="PaddingSliderValueChanged"/>
</GroupBox>
</StackPanel>
<GroupBox Grid.Column="1"
Header="Padding">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0"
Text="{Binding ElementName=paddingTopSlider, Path=Value}"
x:Name="paddingTopDisplay"
VerticalAlignment="Center"
HorizontalAlignment="Center"
BorderBrush="Black"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
Text="{Binding ElementName=paddingLeftSlider, Path=Value}"
x:Name="paddingLeftDisplay"
VerticalAlignment="Center"
HorizontalAlignment="Center"
BorderBrush="Black"/>
<TextBox Grid.Column="1"
x:Name="paddingThicknesObject"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
<TextBox Grid.Column="2"
Text="{Binding ElementName=paddingRightSlider, Path=Value}"
x:Name="paddingRightDisplay"
VerticalAlignment="Center"
HorizontalAlignment="Center"
BorderBrush="Black"/>
</Grid>
<TextBox Grid.Row="2"
Text="{Binding ElementName=paddingBottomSlider, Path=Value}"
x:Name="paddingBottomDisplay"
VerticalAlignment="Center"
HorizontalAlignment="Center"
BorderBrush="Black"/>
</Grid>
</GroupBox>
<StackPanel Grid.Column="2">
<GroupBox Header="Padding Right">
<Slider x:Name="paddingRightSlider"
Minimum="0"
Maximum="20"
TickFrequency="1"
TickPlacement="BottomRight"
IsSnapToTickEnabled="True"
ValueChanged="PaddingSliderValueChanged"/>
</GroupBox>
<GroupBox Header="Padding Bottom">
<Slider x:Name="paddingBottomSlider"
Minimum="0"
Maximum="20"
TickFrequency="1"
TickPlacement="BottomRight"
IsSnapToTickEnabled="True"
ValueChanged="PaddingSliderValueChanged"/>
</GroupBox>
</StackPanel>
</Grid>
<TextBox Grid.Row="2"
x:Name="testTextBox"
Style="{Binding ElementName=styleOptionsComboBox, Path=SelectedItem.Tag}"
Text="{Binding ElementName=inputTestText, Path=Text}"
FontSize="{Binding ElementName=frontSizeSelect, Path=SelectedItem.Tag}"
Height="{Binding ElementName=heightSelect, Path=SelectedItem.Tag}"
VerticalAlignment="{Binding ElementName=verticalAlignment, Path=SelectedItem.Tag}"
VerticalContentAlignment="{Binding ElementName=verticalContentAlignment, Path=SelectedItem.Tag}"
HorizontalAlignment="{Binding ElementName=horizontalAlignment, Path=SelectedItem.Tag}"
HorizontalContentAlignment="{Binding ElementName=horizontalContentAlignment, Path=SelectedItem.Tag}"
FontFamily="{Binding ElementName=selectFontFamily, Path=SelectedItem.Tag}">
</TextBox>
</Grid>
</Window>
And the Code-Behinde:
namespace TextBoxTestApp
{
public partial class MainWindow : Window
{
private double _paddingLeft;
private double _paddingRight;
private double _paddingTop;
private double _paddingBottom;
private Thickness _paddingTestTextBox;
public MainWindow()
{
InitializeComponent();
_paddingTestTextBox = new Thickness(0,0,0,0);
}
private void PaddingSliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
ResetPaddingDisplayBorderBrush();
var currentSlider = (Slider)sender;
switch(currentSlider.Name)
{
case "paddingLeftSlider":
_paddingLeft = currentSlider.Value;
paddingLeftDisplay.BorderBrush = Brushes.Red;
break;
case "paddingTopSlider":
_paddingTop = currentSlider.Value;
paddingTopDisplay.BorderBrush = Brushes.Red;
break;
case "paddingRightSlider":
_paddingRight = currentSlider.Value;
paddingRightDisplay.BorderBrush = Brushes.Red;
break;
case "paddingBottomSlider":
_paddingBottom = currentSlider.Value;
paddingBottomDisplay.BorderBrush = Brushes.Red;
break;
default: throw new ArgumentException("PaddingSliderValueChanged");
}
SetPaddingTestTextBox();
}
private void ResetPaddingDisplayBorderBrush()
{
paddingLeftDisplay.BorderBrush = Brushes.Black;
paddingTopDisplay.BorderBrush= Brushes.Black;
paddingRightDisplay.BorderBrush = Brushes.Black;
paddingBottomDisplay.BorderBrush = Brushes.Black;
}
private void SetPaddingTestTextBox()
{
_paddingTestTextBox.Left = _paddingLeft;
_paddingTestTextBox.Top = _paddingTop;
_paddingTestTextBox.Right = _paddingRight;
_paddingTestTextBox.Bottom = _paddingBottom;
paddingThicknesObject.Text = _paddingTestTextBox.ToString();
testTextBox.Padding = _paddingTestTextBox;
}
}
}
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="740">
<Window.Resources>
<local:Leute x:Key="freunde"/>
<DataTemplate x:Key="detail">
<StackPanel FlowDirection="LeftToRight" Orientation="Horizontal">
<TextBlock x:Name="tb2" Text="{Binding Path=Vorname}"></TextBlock>
<TextBlock Text="{Binding Path=Nachname}"></TextBlock>
<TextBlock Text="{Binding Path=Geburtsdatum, StringFormat = dd.MM.yy}"></TextBlock>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid DataContext="{StaticResource freunde}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox ItemTemplate="{StaticResource detail}" ItemsSource="{StaticResource freunde}"/>
<TextBlock Grid.Column="1" Text="Vorname" Margin="0,23,254,265"></TextBlock>
<TextBlock Grid.Column="1" Text="Nachname" Margin="0,72,290,221"></TextBlock>
<TextBlock Grid.Column="1" Text="Geburtsdatum" Margin="0,121,254,162" RenderTransformOrigin="0.086,1.118"></TextBlock>
<TextBox Grid.Column="1" Text="{Binding Path=Vorname}" Margin="122,28,110,261"/>
<TextBox Grid.Column="1" Text="{Binding Path=Nachname}" Margin="122,71,110,221"/>
<TextBox Grid.Column="1" Text="{Binding Path=Geburtsdatum, StringFormat = dd.MM.yy}" Margin="122,120,110,162"/>
</Grid>
Hello,
im learning for a test, an this was one task of it. If i select an Item in the Listbox it wont show in the Textbox. Tried some things like element name and so on but it didnt work out. Could you help me?
Solved it
IsSynchronizedWithCurrentItem="true"
was missing here :
<ListBox ItemTemplate="{StaticResource detail}" ItemsSource="{StaticResource freunde}" IsSynchronizedWithCurrentItem="True" x:Name="list" />
I have an Image(named car1) on grid and i want to bind car1 coordinates to textblock.
<Canvas>
<Image Name="car1" />
</Canvas>
<WrapPanel>
<TextBlock Text="" Margin="10" Name="xx" Width="50"></TextBlock>
<TextBlock Text="" Margin="10" Name="yy" Width="50">0</TextBlock>
</WrapPanel>
How to solve it ?
try this
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Canvas>
<Image Name="car1" Canvas.Left="40" Canvas.Top="30"/>
</Canvas>
<WrapPanel>
<TextBlock Text="{Binding Path=(Canvas.Left), ElementName=car1}" Margin="10" Name="Left" Width="50"/>
<TextBlock Text="{Binding Path=(Canvas.Top), ElementName=car1}" Margin="10" Name="Top" Width="50"/>
</WrapPanel>
</Grid>
</Window>
I have an image that is bigger than it's window container and it is placed in a ScrollViewer, however, the image does not scroll at all. I've tried putting the image in a container with no luck. What settings am I missing here? (I copied the code straight from MS, but they have it wrong)
Here's the code:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:h="http://helixtoolkit.codeplex.com" x:Class="TileLayout"
Title="TileLayout" Height="1000" Width="845" WindowStartupLocation="CenterScreen" WindowStyle="ThreeDBorderWindow">
<StackPanel HorizontalAlignment="center" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" >
<TextBox x:Name="txtSourceFilePath" Width="500" Margin="10" Height="22" TextChanged="TextBox_TextChanged" Text="E:\projects\Test3D\SavedSnapshots\snapshot.png"/>
<Button x:Name="btnPickFile" Width="100" Margin="0,10,10,10" Content="Pick File" ></Button>
</StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" >
<Image x:Name="imgFinal" Source="SteelMotion_chevron2.png"/>
</ScrollViewer>
</StackPanel>
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:h="http://helixtoolkit.codeplex.com" x:Class="TileLayout"
Title="TileLayout" Height="1000" Width="845" WindowStartupLocation="CenterScreen" WindowStyle="ThreeDBorderWindow">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Height="50" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Row="0">
<TextBox x:Name="txtSourceFilePath" Width="500" Margin="10" Height="22" TextChanged="TextBox_TextChanged" Text=""/>
<Button x:Name="btnPickFile" Width="100" Margin="0,10,10,10" Content="Pick File" ></Button>
</StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="1" >
<Image x:Name="imgFinal" Source="SteelMotion_chevron2.png" Width="768" Height="1408"/>
</ScrollViewer>
</Grid>
You need to specify the size of the ScrollViewer.
In this case ScrollViewer and Image are same size, so the scroll bar does not show.
In my window threre is small black line.
Why?
<Window x:Class="WpfPortOfTestingCamera.InputSelection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="InputSelection" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" SizeToContent="WidthAndHeight" d:DesignWidth="280" d:DesignHeight="206">
<StackPanel HorizontalAlignment="Center" Name="stackPanel1" VerticalAlignment="Top" Margin="10" MaxWidth="500">
<GroupBox Header="Select Camera" HorizontalAlignment="Center" VerticalAlignment="Center">
<ComboBox Height="23" Name="comboBox1" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="120" />
</GroupBox>
<Button Content="OK" Name="ButtonOK" IsDefault="True" Click="ButtonOK_Click" />
</StackPanel>
</Window>
It seems to be a rendering artifact that occurs when the window is resized to the width of your combo box when the content string is set.
If you add the attribute SnapsToDevicePixels="True" to the Window-tag the black line goes away.