How to vertically center a wingding character in textblock xaml / C# / UWP - c#

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" />

Related

How to efficiently scale all elements in a WinUI 3 desktop app when Window size changes?

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>

How to make use of the ViewBox control to make the application re-sizable?

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>

WPF border failed to wrap Image nicely?

<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>

wpf canvas won't resize

I am trying to learn WPF, but I have reached an impasse. The problem is that I have a control derived from UIControl, relevant parts:
<Grid>
<Border x:Name="OuterBorder" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderThickness="2" BorderBrush="Black">
<Canvas x:Name ="InternalCanvas" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Ivory">
</Canvas>
</Border>
</Grid>
This gives me a little black dot, when I render the control; I assume this is the border.
I then add code to the constructor after InitizializeComponents:
Label l = new Label();
l.Content = "HELLO";
l.BorderThickness = new Thickness(2);
l.BorderBrush = Brushes.Bisque;
if (this.GetType() == typeof(SO.SOGraphNode))
this.InternalCanvas.Children.Add(l);
The intent of the code is that if the class is not inherited, it should show some kind of placeholder. Which it does.
The problem is that InternalCanvas and it's ecplipsing OuterBorder won't resize around the newly created nice label.
The border remains a dot-border and InternalCanvas' Ivory background is not seen behind the label.
I have googled this alot, beliving that I needed to refresh or update the canvas/control elements, but I'm not so sure anymore. Mainly through watching a lot of Dispatcher.Invoke variations, which I have applied very liberally through out the code at different points, every time with no change in behavior.
WPF is a bit oblique to me still, if anyone knows how I could resolve this problem I do indeed have a shiny "Correct Answer" to dole out. :)
Edit 1 - Screenshot of the results:
Notice the general lack of Ivory background and OuterBorder still remains a small artifact in the topright corner of the control while the childelement is obviously much larger.
Is it important for you that the "InternalCanvas" element is type of canvas?
Because if you use for example a Grid instead, the sample works fine:
<Border x:Name="OuterBorder" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderThickness="2" BorderBrush="Black">
<Grid x:Name ="InternalGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Ivory">
</Grid>
</Border>
edit:
The reason for this behaviour you can read in the remarks section in MSDN:
Canvas is the only panel element that has no inherent layout characteristics. A Canvas has default Height and Width properties of zero, unless it is the child of an element that automatically sizes its child elements. Child elements of a Canvas are never resized, they are just positioned at their designated coordinates. This provides flexibility for situations in which inherent sizing constraints or alignment are not needed or wanted. For cases in which you want child content to be automatically resized and aligned, it is usually best to use a Grid element.
Can you show us how it rendered? I tried your xaml in a new project and I can't figure out what the problem is

How do I control clipping in C# or XAML when using UniformToFill with an image

I have an image control in a resizable window with its stretch property set to UniformToFill.
<Image Name="some_image" Stretch="UniformToFill" Margin="0,0,0,0" />
The clipping window is pegged to the top left of the image; resizing chops off the right and bottom of the image.
I want the image to be clipped equally on all sides. Am I being dense and overlooking an obvious solution?
How do I control how the image gets clipped?
(Unrelated: This is my first post to stackoverflow. I just wanted to start off saying, thanks, this site has been amazing resource for me)
The HorizontalAlignment and VerticalAlignment property determine this behavior with an image control.
<Image Name="some_image" Stretch="UniformToFill" Margin="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
Guess i was being dense!

Categories