How to programmatically maintain aspect ratio of object in wpf - c#

I programmatically add a Border with a certain width and height to a grid. However, I want to get either one of the following:
Make the border keep aspect ratio and fill make it as big as possible inside the grid
Make the border scale whenever the grid scales down or up (so not particularily the biggest possible, more like a percentage of the grid)
At the moment this is the situation when I resize my window:
Color borderColor = (Color)ColorConverter.ConvertFromString(BorderColor);
Color backgroundColor = (Color)ColorConverter.ConvertFromString(BackgroundColor);
Border border = new Border();
border.BorderThickness = new Thickness(BorderSize);
border.CornerRadius = new CornerRadius(TopLeftCornerRadius, TopRightCornerRadius, BottomRightCornerRadius, BottomLeftCornerRadius);
border.BorderBrush = (SolidColorBrush)(new BrushConverter().ConvertFrom(BorderColor));
border.Background = (SolidColorBrush)(new BrushConverter().ConvertFrom(BackgroundColor));
border.Width = Width;
border.Height = Height;
border.Margin = new Thickness(10);
previewgrid.Children.Add(border);
The normal situation:
The scaled situation:
So I would like it to resize properly and stay inside the white rectangle. By the way, the white grid has a margin as you can see ;-)
Thanks in advance!

As lerthe61 suggested, just use a Viewbox with its Stretch property set to Uniform:
Color borderColor = (Color)ColorConverter.ConvertFromString(BorderColor);
Color backgroundColor = (Color)ColorConverter.ConvertFromString(BackgroundColor);
Border border = new Border();
border.BorderThickness = new Thickness(BorderSize);
border.CornerRadius = new CornerRadius(TopLeftCornerRadius, TopRightCornerRadius, BottomRightCornerRadius, BottomLeftCornerRadius);
border.BorderBrush = (SolidColorBrush)(new BrushConverter().ConvertFrom(BorderColor));
border.Background = (SolidColorBrush)(new BrushConverter().ConvertFrom(BackgroundColor));
border.Width = Width;
border.Height = Height;
border.Margin = new Thickness(10);
Viewbox viewBox = new Viewbox();
viewBox.Stretch = Stretch.Uniform;
viewBox.Child = border;
previewgrid.Children.Add(viewBox);
Please, note that this solution does not work if previewgrid is a Canvas.
I hope it can help you.

The simplest way:
<Grid Margin="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Border CornerRadius="50,0,0,50"
Background="Green" />
<Border CornerRadius="0"
Grid.Column="1"
Background="Green" />
<Border CornerRadius="0,50,50,0"
Grid.Column="2"
Background="Green" />
</Grid>
By C#:
myGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
myGrid.ColumnDefinitions.Add(new ColumnDefinition());
myGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
Border b1 = new Border
{
Background = new SolidColorBrush(Colors.Blue),
CornerRadius = new CornerRadius(100, 0, 0, 100)
};
Grid.SetColumn(b1, 0);
Border b2 = new Border
{
Background = new SolidColorBrush(Colors.Blue),
};
Grid.SetColumn(b2, 1);
Border b3 = new Border
{
Background = new SolidColorBrush(Colors.Blue),
CornerRadius = new CornerRadius(0, 100, 100, 0),
};
Grid.SetColumn(b3, 2);
myGrid.Children.Add(b1);
myGrid.Children.Add(b2);
myGrid.Children.Add(b3);
Normal:
Resized:
Is it good enough for you?

Related

How to create grid layout dynamically for XAML

In my app I am trying to create a grid layout dynamically but not getting expected output:
Below is the code that I tried:
Grid LayoutGrid = new Grid();
//Created Two Columns
ColumnDefinition gridCol1 = new ColumnDefinition();
ColumnDefinition gridCol2 = new ColumnDefinition();
LayoutGrid.ColumnDefinitions.Add(gridCol1);
LayoutGrid.ColumnDefinitions.Add(gridCol2);
Grid Col1Grid = new Grid();
//Create Two Rows
RowDefinition gridRow1 = new RowDefinition();
RowDefinition gridRow2 = new RowDefinition();
Col1Grid.RowDefinitions.Add(gridRow1);
Col1Grid.RowDefinitions.Add(gridRow2);
Grid.SetColumn(Col1Grid, 1);
return LayoutGrid;
The layout I am trying to create is like this:
I added some colors to be easier to understand
private Grid CreateGrid()
{
var LayoutGrid = new Grid { Background = new SolidColorBrush(Colors.Yellow) };
//Created Two Columns
LayoutGrid.ColumnDefinitions.Add(new ColumnDefinition());
LayoutGrid.ColumnDefinitions.Add(new ColumnDefinition());
//Created Two Rows
LayoutGrid.RowDefinitions.Add(new RowDefinition());
LayoutGrid.RowDefinitions.Add(new RowDefinition());
// region 1 - vertical left
var stack1 = new StackPanel {
Background = new SolidColorBrush(Colors.Red)
};
Grid.SetColumn(stack1, 0);
Grid.SetRowSpan(stack1, 2);
LayoutGrid.Children.Add(stack1);
// region 2 - top right
var stack2 = new StackPanel
{
Background = new SolidColorBrush(Colors.Green)
};
Grid.SetColumn(stack2, 1);
LayoutGrid.Children.Add(stack2);
// region 3 - bottom right
var stack3 = new StackPanel
{
Background = new SolidColorBrush(Colors.Blue)
};
Grid.SetColumn(stack3, 1);
Grid.SetRow(stack3, 1);
LayoutGrid.Children.Add(stack3);
return LayoutGrid;
}
Xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Background="Red" Grid.RowSpan="2"></StackPanel>
<StackPanel Background="Blue" Grid.Column="1"></StackPanel>
<StackPanel Background="Green" Grid.Column="1" Grid.Row="1"></StackPanel>
</Grid>

Set minimum or maximum Height of Row of Grid in Xaml (Xamarin.Forms)

I need to set minimum height of a RowDefinition of Gridin Xamarin.Forms using Xaml or code behind. I didn't find any property like MinHeight or MaxHeight. There is only Height property for RowDefinition.
<Grid ColumnSpacing="10" Padding="20">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>
You can do this to set your MinimumHeight:
<Grid ColumnSpacing="10" Padding="20">
<Grid.RowDefinitions>
<RowDefinition Height= "Auto"/>
</Grid.RowDefinitions>
<ContentView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" MinimumHeightRequest="20">
...
</ContentView>
</Grid>
Note: The MinimumHeightRequest will chose the minimum between your requested height and your requested minimum height. Source
I solved the problem the same or similar way as Akash Amin.
In my custom control i added an empty boxview with a fixed height to set the minimum height of the row. The importent label was placed above the transparant boxview. So i did not place anything in the boxview.
I did the code in codebehind in my customcontrol.
var grid = new Grid();
grid.HorizontalOptions = LayoutOptions.Fill;
grid.VerticalOptions = LayoutOptions.Start;
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto, });
var minSizer = new BoxView();
minSizer.HeightRequest = 30;
grid.Children.Add(minSizer, 0, 0);
_label = new Label();
_label.VerticalTextAlignment = TextAlignment.Center;
_label.VerticalOptions = LayoutOptions.Center;
grid.Children.Add(_label, 0, 0);
...
(I think it is annoying that the MinimumWidthRequest and MinimumHeightRequest dont work as the most people expects them to do. In xamarin i mean.)

How to center TextBox element inside Grid

I'm developing WP8 app for my own needs and want it to have small live tile with text.
Since small tile cannot display text, I'm generating appropriate image with needed text.
Here is the code:
WriteableBitmap bmpSmall = new WriteableBitmap(159, 159);
var grid = new Grid();
grid.Width = bmpSmall.PixelWidth;
grid.Height = bmpSmall.PixelHeight;
var background = new Canvas();
background.Width = bmpSmall.PixelWidth;
background.Height = bmpSmall.PixelHeight;
SolidColorBrush backColor = new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]);
background.Background = backColor;
var textBlock = new TextBlock();
textBlock.Text = "qwerty";
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = new SolidColorBrush(Colors.White);
grid.Children.Add(textBlock);
bmpSmall.Render(background, null);
bmpSmall.Render(grid, null);
bmpSmall.Invalidate();
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream imageStream = new IsolatedStorageFileStream("/Shared/ShellContent/smallTile.jpg", System.IO.FileMode.Create, isf))
{
bmpSmall.SaveJpeg(imageStream, 159, 159, 0, 100);
}
}
ShellTile tile = ShellTile.ActiveTiles.First();
FlipTileData tileData = new FlipTileData();
tileData.SmallBackgroundImage = new Uri(#"isostore:/Shared/ShellContent/smallTile.jpg", UriKind.Absolute);
tile.Update(tileData);
And result looks like:
As you see, text is aligned to top left corner. The question is "Why"? Since I'd set textBlock.HorizontalAlignment and textBlock.VerticalAlignment - I expect it in the center of the image.
For example the following XAML looks like you can expect and like I need:
<Grid Width="159" Height="159">
<Grid.Background>
<SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
</Grid.Background>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontSize="28" Foreground="White">qwerty</TextBlock>
</Grid>
What did I miss? How can I center text?
Give the following code a try:
WriteableBitmap bmpSmall = new WriteableBitmap(159, 159);
var grid = new Grid();
grid.Width = bmpSmall.PixelWidth;
grid.Height = bmpSmall.PixelHeight;
var background = new Canvas();
background.Width = bmpSmall.PixelWidth;
background.Height = bmpSmall.PixelHeight;
SolidColorBrush backColor = new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]);
background.Background = backColor;
var textBlock = new TextBlock();
textBlock.Width = bmpSmall.PixelWidth;
textBlock.Text = "qwerty";
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Stretch;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = new SolidColorBrush(Colors.White);
textBlock.TextAlignment = TextAlignment.Center;
grid.Children.Add(background);
grid.Children.Add(textBlock);
grid.Measure(new Size(bmpSmall.PixelWidth, bmpSmall.PixelHeight));
grid.Arrange(new Rect(0,0,bmpSmall.PixelWidth, bmpSmall.PixelHeight));
grid.UpdateLayout();
bmpSmall.Render(grid, null);
bmpSmall.Invalidate();
I set the TextBlock width to the same as the rest of the tile, and set HorizontalAlignment to stretch, so that control would take up the whole width of the tile. Then I set the TextAlignment property to TextAlignment.Center, in order to center the text. Hope that helps!
Edit: Apparently for writable bitmaps, you must do the measure/arrange/layout steps yourself in order to render controls as you would think they should be rendered. Give this updated code a try, it should work this time!
You will have to set the HorizontalAlignment="Stretch" VerticalAlignment="Stretch" for grid also. Currently grid is only of size of its content i.e textblock.
After copying your code into an empty WPF application, I'm afraid to tell you that your code works just fine:
All I did was to set the Grid.Background to red and the TextBlock.Background to black to clarify the situation:
<Grid Width="159" Height="159">
<Grid.Background>
<SolidColorBrush Color="Red"/>
</Grid.Background>
<TextBlock Background="Black" HorizontalAlignment="Center"
VerticalAlignment="Center" FontWeight="Bold" FontSize="28"
Foreground="White">qwerty</TextBlock>
Therefore, I can only assume that you have a problem elsewhere in your code.
UPDATE >>>
Sorry, you're right, I did misunderstand you. However, after testing your C# code, the story is just the same:
This might look like the same image, but it actually comes from your C# code... I made a couple of little changes, but nothing that affected the position of the TextBlock:
Grid grid = new Grid();
grid.Background = Brushes.Red;
grid.Width = grid.Height = 159.0;
TextBlock textBlock = new TextBlock();
textBlock.Text = "qwerty";
textBlock.Background = Brushes.Black;
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = Brushes.White;
grid.Children.Add(textBlock);
this.Content = grid;
If you put this code into a new WPF project, you'll see that it works just fine, so that only leaves your WriteableBitmap object as the culprit of this problem... what are you using that for? If you're just adding it to your UI, then you can simply add the controls to the Window directly.

How to force text into a specific width?

I use a GridView to display my layout. To this GridView i manually add some RowDefinitions and in this RowDefinitions I add 1 Canvas containing 2 rectangles:
foreach (Method m in sourceFile.getMethods())
{
if (!m.getName().StartsWith("<") && !m.getName().EndsWith(">"))
{
RowDefinition row = new RowDefinition();
row.Height = GridLength.Auto;
MethodsContainer.RowDefinitions.Add(row);
Canvas c = new Canvas();
c.Width = width;
c.Height = height;
c.Tag = m;
Contacts.AddPreviewContactDownHandler(c, new ContactEventHandler(onContactDown));
Rectangle r1 = new Rectangle();
r1.Height = height;
r1.Width = m.getLoc() * (width / 1000);
Canvas.SetLeft(r1, 0);
Canvas.SetLeft(r1, 0);
r1.Fill = Brushes.Red;
Rectangle r2 = new Rectangle();
r2.Height = height;
r2.Width = width - r1.Width;
Canvas.SetTop(r2, 0);
Canvas.SetLeft(r2, r1.Width);
r2.Fill = Brushes.Blue;
c.Children.Add(r1);
c.Children.Add(r2);
Grid.SetRow(c, rowCounter);
MethodsContainer.Children.Add(c);
rowCounter++;
}
}
The canvas is 200px width and 30px height. Both rectangles fill the Canvas exactly. Now i want to add some text over this both Rectangles. But I don't know how long the text is. However I want to force that the text is always printed into this 200px. How can I achieve that?
Sounds like you could make use of a ViewBox. This will make your text stretch both horizontally and vertically. I assume that's what you want if I understood the question correctly. Example in xaml
<Canvas Width="200"
Height="30">
<Viewbox Width="200"
Height="30">
<TextBlock Text="Text that will fit in 200 Width"/>
</Viewbox>
</Canvas>
And in code behind it will be like
TextBlock textBlock = new TextBlock();
textBlock.Text = "Text that will fit in 200 Width";
Viewbox viewBox = new Viewbox();
viewBox.Width = width;
viewBox.Height = height;
viewBox.Child = textBlock;
c.Children.Add(viewBox);
var txt = new TextBlock();
txt.MaxWidth = 200;
// optionally you might want the text to wrap if too long
txt.TextWrapping = TextWrapping.Wrap;
By the way, it's not pixels in WPF, it's a device-independent unit (1/96th inch) measurement.

AccessText inside Label (XAML to C#)

The following code is part of a small XAML application that displays data in a tabular form. Basically I need to translate this code into C#.
<Grid Width="768" Height="1056">
<Grid.RowDefinitions>
<RowDefinition Height="114" />
<RowDefinition Height="906*" />
<RowDefinition Height="36" />
</Grid.RowDefinitions>
...
<Label Grid.Row="1" Width="40" Height="32" Margin="14,4,0,0" Padding="0" HorizontalAlignment="Left" VerticalAlignment="Top" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" BorderBrush="Black" BorderThickness="1" Name="label16">
<AccessText Margin="0,0,0,0" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Bold">
SEQ
</AccessText>
</Label>
...
</Grid>
I've been looking for an answer for a couple of days and I can't find anything specific to this. Can someone please give me an idea of how to do it?
Thank you
I constructed a sample Window for you. Here is the code-behind you are looking for:
public Window1()
{
InitializeComponent();
AccessText text = new AccessText()
{
Text = "SEQ",
Margin = new Thickness(0),
TextWrapping = TextWrapping.Wrap,
TextAlignment = TextAlignment.Center,
FontWeight = FontWeights.Bold
};
Label label = new Label()
{
Content = text,
Width = 40,
Height = 32,
Margin = new Thickness(14, 4, 0, 0),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalContentAlignment = VerticalAlignment.Center,
BorderBrush = Brushes.Black,
BorderThickness = new Thickness(1),
Name = "label16"
};
Grid grid = new Grid();
grid.Width = 768;
grid.Height = 1056;
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(114) });
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(906, GridUnitType.Star) });
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(36) });
Grid.SetRow(label, 1);
grid.Children.Add(label);
this.Content = grid;
}
This example nicely demonstrates how easy XAML is for constructing user interfaces. :)

Categories

Resources