How to force text into a specific width? - c#

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.

Related

C# WPF how to draw a circle which extends to fill its parent and remains a circle in code behind

I have to draw a circle in a grid. That grid has to adapt proportionally to height and width defined by the Column/Row definition of its parent grid.
Now if I put stretch it will fill all the space and become an ellipsis while I want it to be a circle.
Ok in short the parent grid adapts proportionally like that
then in a routine I add the following code:
public void RadialPercentage(Grid grd )
{
Ellipse elpExt = new Ellipse();
elpExt.Stroke = Brushes.Green;
elpExt.StrokeThickness = 4;
//elpExt.Margin = new Thickness(0);
//elpExt.HorizontalAlignment = HorizontalAlignment.Center;
elpExt.VerticalAlignment = VerticalAlignment.Stretch;
grd.Children.Add(elpExt);
Ellipse elpInt = new Ellipse();
elpInt.Stroke = Brushes.Blue;
elpInt.StrokeThickness = 4;
elpInt.Margin = new Thickness(20);
//elpInt.Width = elpInt.Height = dim-20;
//elpInt.HorizontalAlignment = HorizontalAlignment.Center;
elpInt.VerticalAlignment = VerticalAlignment.Stretch;
grd.Children.Add(elpInt);
return;
}
but the effect is the following:
so it stretches both vertically and horizontally even if I only put the vertical and not the horizontal constraint. If I set it to center the ellipse collapses.
To solve the problem even I am not sure that this is the right thing to do I tried to take a look of the weight/heigth of the parent grid but obviously both those values and the actual values are set to zero.
thanks for helping
Patrick
What about setting Width's binding to ActualHeight of the ellipse and set HorizontalAlignment to Center? Something like this:
var ellipse = new Ellipse();
var binding = new Binding(Ellipse.ActualHeightProperty.Name)
{
RelativeSource = new RelativeSource(RelativeSourceMode.Self),
Mode = BindingMode.OneWay
};
ellipse.VerticalAlignment = VerticalAlignment.Stretch;
ellipse.HorizontalAlignment = HorizontalAlignment.Center;
BindingOperations.SetBinding(ellipse, Ellipse.WidthProperty, binding);
You can update the size of your Ellipse each time the parent Grid is resized.
You should add to your Grid the SizeChanged Event. XAML example:
<Grid Name = "MyGrid"
SizeChanged = "MyGridSizeChanged">
<!-- rows and columns definitions -->
<Ellipse Name = "MyEllipse"
Grid.Row = "i"
Grid.Column = "j" />
</Grid>
Now, each time the Grid is resized the function MyGridSizeChanged will executed. You should add into it code, which set sizes of your Ellipse equal to smallest side of contained cell. C# example:
void MyGridSizeChanged(object sender, SizeChangedEventArgs e) {
if (sender is Grid myGrid) {
var cellHeight = myGrid.RowDefinitions[Grid.GetRow(MyEllipse)].ActualHeight;
var cellWidth = myGrid.ColumnDefinitions[Grid.GetColumn(MyEllipse)].ActualWidth;
var newSize = Math.Min(cellHeight, cellWidth);
MyEllipse.Height = newSize;
MyEllipse.Width = newSize;
}
}

How to programmatically maintain aspect ratio of object in wpf

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?

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.

Rotated textblock doesn't have the correct length

I am trying to fill a Grid in a WPF application dynamically.
I'm creating a row and then some columns. in each column I am adding a textblock, like this:
GrdMainGrid.RowDefinitions.Add(new RowDefinition(Height = new GridLength(150, GridUnitType.Pixel);
GrdMainGrid.RowDefinitions.Add(new RowDefinition(Height = new GridLength(1, GridUnitType.Star);
for(var i=0; i<4; i++)
{
GrdMainGrid.ColumnDefinitions.Add(new ColumnDefinition {With = new GridLength(25, GridUnitType.Pixel)});
}
var header = new TextBlock {Text = "Header1", RenderTransform = new RotateTransform(-90), Width = 150, Margin = new Thickness(0), VerticalAlignment = VerticalAlignment.Bottom, HorizontalAlignment = HorizontalAlignment.Left};
.
.
.
Grid.SetColumn(header, 0);
Grid.SetRow(header, 0);
.
.
.
GrdMainGrid.Children.Add(header);
The textblock is rotated -90 degree.
While the size of the column is set to 25 pixel i doesn't show all text, when I increase the size of the column the text in textblock is also increased. see pic
I could understand this if the textblock wasn't rotated and it didn't fit in the column. But what has it to do with the size of the column when it's rotated.
And is it possible somehow to decrease the width of the column without decreasing size of text ?
Tnx in advance.
Use a LayoutTransform instead of a RenderTransform.
var header = new TextBlock { Text = "Header1", LayoutTransform = new RotateTransform(-90), Width = 150, Margin = new Thickness(0), VerticalAlignment = VerticalAlignment.Bottom, HorizontalAlignment = HorizontalAlignment.Left };

how to add text in rectangle with code behind wpf

I want to add textblock or label inside rectangle which is creating with code behind
Can anyone help me?
for (int i = 0; i < _RoomX.Count; i++)
{
_RoomX[i] = (Convert.ToDouble(_RoomX[i]) * 20).ToString();
_RoomY[i] = (Convert.ToDouble(_RoomY[i]) * 20).ToString();
var rectangle = new Rectangle()
{
Stroke = Brushes.Black,
Fill = brush,
Width = Convert.ToDouble(_RoomX[i]),
Height = Convert.ToDouble(_RoomY[i]),
Margin = new Thickness(
left: 15,
top: 50,
right: 0,
bottom: 0),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
mainCanvas.Children.Add(rectangle);
}
well rectangle is not a content control it is derived from shape object... we cannot use it as a panel.
instead of rectangle you can use a border..
if your requirement demands a Rectangle then what you can do is... create a Grid> then add rectangle to that Grid> and create a textblock and add it to same grid... since grid is not physically visible it appears like text added to rectangle ..
i will try to post a sample
Edit:
following code will help you to understand it better
for (int i = 0; i < _RoomX.Count; i++)
{
_RoomX[i] = (Convert.ToDouble(_RoomX[i]) * 20).ToString();
_RoomY[i] = (Convert.ToDouble(_RoomY[i]) * 20).ToString();
var rectangle = new Rectangle()
{
Stroke = Brushes.Black,
Fill = brush,
Width = Convert.ToDouble(_RoomX[i]),
Height = Convert.ToDouble(_RoomY[i]),
Margin = new Thickness(
left: 15,
top: 50,
right: 0,
bottom: 0),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
Grid grid = new Grid();
grid.Children.Add(rectangle);
TextBlock textblock = new TextBlock();
textblock.Text = "Text to add";
grid.Children.Add(textblock);
mainCanvas.Children.Add(grid);
}

Categories

Resources