Here is full application xaml:
< Window x:Class="WpfApplication30.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Width="525"
Height="350">
< Border VerticalAlignment="Center"
BorderBrush="Green"
BorderThickness="1">
< TextBlock Text="HELLO WORLD!"
VerticalAlignment="Center"
FontSize="16" />
</Border>
</Window>
When system font is set to 125% text is not in the center of the border. There is 7 pixels between top border and text and only 4 pixels between bottom border and text. How can I fix it?
UPD:
added
UseLayoutRounding="True"
SnapsToDevicePixels="True"
but diffrenece is still here: 8px and 6px
Font vertical centering is complicated, as the TextBlock will align to the center of the provisioned space so that any character from your selected Font fits this area. A basic overview why this is, can be found in the Wikipedia Baseline (typography) article
You can try to compensate for the specific font's metrics by using
GetEmHeight(FontStyle)
GetCellAscent(FontStyle)
GetCellDescent(FontStyle)
GetLineSpacing(FontStyle)
on the FontFamily class. And adjust the placement of the TextBlock.
Source: How to: Obtain Font Metrics
But i would really advice against doing so as there are characters that could be using the space like Á and j which have different heights and line placement.
You might have better default layouting experience with fonts that are monospaced like Consolas which for HELLO WORLD! prints pretty much to the middle of the border.
Related
I'd like to have everything in my WinUI 3 (v1.2) desktop app UI (MainWindow) scale up in size as the MainWindow changes in size. I'd also like to maintain the relative positioning of everything in the MainWindow. The purpose is to allow elderly users a quick and easy way to "enlarge" content by simply expanding the size of the window.
For example, take a vanilla Template Studio WinUI 3 desktop app with menu bar style navigation and a single page (call it MainPage). Replace MainPage.xaml with
<Page
x:Class="TestScale.Views.MainPage"
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"
mc:Ignorable="d">
<Grid Grid.Row="0" Grid.RowSpan="4">
<Border x:Name="Border" Width="300" Height="200" BorderThickness="2" BorderBrush="Red">
<TextBlock Text="The quick brown fox." HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</Grid>
</Page>
which just draws a red rectangle with a TextBlock in the middle of the page (ignoring space used by ShellPage.xaml).
I'd like a straightforward way to scale everything, if possible, so that the rectangle and text increase in size (x and y) in the same proportions (dx and dy) that MainPage does when MainWindow changes, but also maintain their relative positions in the xy plane. I've tried using Scale and various Translations, but it always seems certain elements respond differently or only one dimension responds while the other stays fixed.
For example, adding
Scale="{x:Bind ((app:App)app:App.Current).ScaleToInitialSize, Mode=OneWay}"
to the definition of ShellPage.xaml almost does the trick except the position of the rectangle changes because the actual size of MainPage changes to reflect pixels used but the rectangle size reflects "scaled" sizes.
Is there a good discussion of scaling in WinUI 3 or UWP I've missed? I currently achieve this by binding everything to a Ratio property (Vector2 or Size) in my App class that changes whenever MainWindow.SizeChanged fires. Unfortunately, this means I also have to bind things like XAML Thickness, FontSize, and even CornerRadius properties to maintain the look and layout of the UI.
I expect this is a noob question but I can't seem to find any discussion anywhere. Any help gratefully appreciated.
You can use the ViewBox. The ViewBox scales its content automatically.
<Viewbox>
<Grid
Grid.Row="0"
Grid.RowSpan="4">
<Border
x:Name="Border"
Width="300"
Height="200"
BorderBrush="Red"
BorderThickness="2">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="The quick brown fox." />
</Border>
</Grid>
</Viewbox>
ViewBox seems to be the go to tool if you want your application to be re-sizable, however, I still cannot get my head around on how to properly use it.
Here's my current code (this approach was recommended by a colleague)
<Window x:Class="WpfApp3.MainWindow"
WindowState="Maximized"
Width="{DynamicResource {x:Static SystemParameters.MaximizedPrimaryScreenWidthKey}}"
Height="{DynamicResource {x:Static SystemParameters.MaximizedPrimaryScreenHeightKey}}">
<Viewbox Stretch="UniformToFill">
<Grid Background="Peru"
Height="1080"
Width="15000">
<Grid Background="Bisque"
HorizontalAlignment="Left"
Width="{DynamicResource {x:Static SystemParameters.MaximizedPrimaryScreenWidthKey}}" >
</Grid>
</Grid>
</Viewbox>
</Window>
The approach is the following:
Wrap everything in a ViewBox with Stretch property set to UniformToFill, such that the aspect ratio of inner-elements in preserved
For the outer most grid, set the Width to some arbitrary huge number and Height to some arbitrary small number
We now have a huge rectangle going off screen to the right, while the height is the height of the window
Create a second grid and horizontally align it the the left
Put all other elements in this grid
Problems
The width of the second grid is set to the width of the primary screen, but because of the ViewBox and its stretch property the width if cut off, so I cannot really use it, as all the elements will be slightly-aligned to the left of the screen
Current layout
Questions
Is this the recommended way of creating dynamic / re-sizable applications in WPF?
Is this the correct way of using the ViewBox control?
How can I fix my problem?
Are there other solutions to using the ViewBox control?
I had this issue when I was trying to make a telerik grid re-sizable. Using a viewbox is the recommended way of creating re-sizable applications in WPF. I've found that using a dock panel is better than margins because it holds the control in place, while the viewbox controls the sizing. You can also add a grid with rows / columns if you need multiple controls. I'm very new to development, so this may not be best practice, however it works for our applications.
<Viewbox Stretch="Fill"
Grid.Row="1"
Grid.Column="1">
<DockPanel Height="300">
<Grid>
*User controls*
</Grid>
</DockPanel>
</Viewbox>
I have a C# desktop application, GUI is in WPF.
I have all kind of controls, such as: buttons, radio buttons that have text in them, in a specified font size. All looks great in English.
But, when I change the language of my app to be something else (I have localization on my app), for example: French, German, Italian... The text is cut, because it's too long.
I would like to change the font size of the control to be automatically fitted to the text length in the specific current language. Not just to change the font to be small enough by default for all languages.
Is there a way to do that in WPF?
Thanks!!!
If you insist on setting the Width of the Button, one option is to simply wrap the Button in a ViewBox:
<Viewbox Width = "100" >
<Button Content="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA">
</Button>
</Viewbox>
However, you might want to consider retemplating and wrapping the ContentPresenter in a ViewBox:
<Button Width = "100" Content="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA">
<Button.Template>
<ControlTemplate TargetType="Button">
<Viewbox x:Name="ViewBoxInternal">
<ContentPresenter />
</Viewbox>
</ControlTemplate>
</Button.Template>
</Button>
you can use its Style to add other animations/effects.
I’m trying to use a Wingdings symbol as a graphic in a control and am trying to make it vertically centered within a textbox (UWP app.) I’m putting a visible boarder around it and the fact that the symbol is not vertically centered is noticeable and ruining what I’m going for. If it’s possible it saves me from having to do custom art and the since the Wingdings are resizable my graphic could be somewhat easily rescaled. That's why I don't want to manually adjust the height until it looks centered.
Most the Wingdings aren’t vertically centered but are sometimes used as graphics so I’m wondering if this is doable w/ reasonable effort. A slick xaml way to do this would be ideal but a font metric measuring and then textblock height adjusting tack would be good.
Here’s an example of the problem. The hard drive symbol is not vertically centered in the border.
<Border BorderBrush="Black" BorderThickness="10" Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text=";" FontFamily="Wingdings" FontSize="230"/>
</Border>
EDIT - changed example to declutter and to use Wingdings hard drive symbol because the skull&bones is close enough to vertically centered to confuse the question. The drive symbol is very clearly not vertically centered. My goal to automatically vertically center it even as the font size changes. I can see how XAML may not be able to do this but I'm wondering if some font/text metrics querying exists that I could use to do it.
EDIT 2 - Adding a picture (from above XAML which has the same issues as all the suggested XAML(s):
I'm trying to get the center of the symbol to be at the center of the textblock
The skull & bones is not vertically centered in the border.
Actually by default the skull&bones text should be vertically center. The reason for why your code make it looks not vertically is that the font size is too larger to be inside the border, since Border's height is restricted to 200. So the exceed parts of TextBlock you will not seen which may looks like it is not vertically center.
How to vertically center a wingding character in textblock xaml / C# / UWP
There are several ways to do this, choose which way depend on your prefer.
Remove the height and width properties for the Border control you will see the text vertically center.
<Border BorderBrush="Black" BorderThickness="10" Background="White" HorizontalAlignment="Center">
<TextBlock x:Name="textBlock" Text="N" FontFamily="Wingdings" FontSize="230" />
</Border>
Add a ViewBox control outside the TextBlockcontrol. ViewBox can stretch and scale a single child to fill the available space. This will let your text looks always be center no matter how large is the font size. The text size will depend on the size of Border control. Code as follows:
<Border BorderBrush="Black" BorderThickness="10" Height="200" Width="175" Background="White" >
<Viewbox>
<TextBlock x:Name="textBlock" Text="N" FontFamily="Wingdings" FontSize="230" />
</Viewbox>
</Border>
Just use a TextBox control instead of the component of Border and TextBlock. This will reach the same effects that make the text always center and no matter what is the font size. Pay attention that don't set fixed height and width for the TextBox and also make the TextBox read only. Code as follows:
<TextBox
x:Name="textBox"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="Black"
BorderThickness="10"
FontFamily="Wingdings"
FontSize="230"
IsReadOnly="True"
Text="N"
TextAlignment="Center" />
<Border CornerRadius="3" BorderBrush="#fff" BorderThickness="3px" Width="100" Height="100">
<Image Source="test.jpg" Width="100" Height="100"/>
</Border>
As shown in the code above, I've forced the Image to have 100 for both width and height as well as the border. My intention was so that the border can wrap the image without any unnecessary spaces. However please take a look at the result below:
There are still unnecessary spaces between the border and image? The problem can be solved by reducing the width and height of border but I just don't understand why. Below is my original image where width and height larger than 100:
You have set the BorderBrush property to White and the BorderThickness property to 3px on your Border. I can only imagine that that explains the white line around the edge of the Border. Just remove these properties to remove the white surrounding line.
UPDATE >>>
I would agree with #GazTheDestroyer. If your image is actually wider than 100px, then it will be automatically resized to fit into the 94px. If your image is wider than it is tall, then that would account for the gap at the top and bottom. try this:
<Image Source="test.jpg" Stretch="None" />
You can also experiment with the other possible values for the Stretch property.
A <Border> does not overlay an element, it contains an element. Therefore if your border is 100px with a 3px border, there are only 94px of space left inside.
Setting an explicit size of 100 on the image means that some of it will be chopped off since the border is not big enough to show all of it. Also I see you image is not square (120x103px), meaning it will be scaled with a strange aspect ratio too.
If you really want the border to overlay on top of the same exact square as the image, then put them both in a <Grid> or <Canvas> at the same position. eg
<Grid>
<Image Source="test.jpg" Width="100" Height="100"/>
<Border CornerRadius="3" BorderBrush="#fff" BorderThickness="3px" Width="100" Height="100" Background="Transparent">
</Grid>