WPF: How do I create a Grid dynamically that scales? - c#

I am working on a demo app, and I'm trying to set the grid size base on a selection from a combo box. The problem I am having is when a do a 2x2 grid, for example. It doesn't fill the grid; just a quarter of it. I've tried messing with the size of the rows and columns and also the control that goes inside but I can't get it to behave the way I want it to. The behavior I'm looking for is too evenly divide up space for the rows and columns; and then have a control fill the cell. When I resize the window I want the grid and the controls in each cell too resize with the window.
Here is my code:
int row = 0;
int col = 0;
short cam = 0;
for (int i = 0; i < (_length * _length); i++)
{
RowDefinition rowDef = new RowDefinition();
ColumnDefinition colDef = new ColumnDefinition();
//rowDef.Height = GridLength.Auto;
//colDef.Width = GridLength.Auto;
//rowDef.Height = new GridLength((this.ActualHeight / length) - 7, GridUnitType.Star);
//colDef.Width = new GridLength((this.ActualWidth / length) - 1, GridUnitType.Star);
//var converter = new GridLengthConverter();
//rowDef.Height = (GridLength)converter.ConvertFromString("*");
//colDef.Width = (GridLength)converter.ConvertFromString("*");
Border border = new Border();
border.BorderBrush = Brushes.White;
border.BorderThickness = new Thickness(2);
//rowDef.MinHeight = (this.ActualHeight / _length) - 7;
//colDef.MinWidth = (this.ActualWidth / _length) - 1;
rendererGrid.RowDefinitions.Add(rowDef);
rendererGrid.ColumnDefinitions.Add(colDef);
AxCVClientControlLib.AxCVVideo axCVVideo = new AxCVClientControlLib.AxCVVideo();
_hosts.Add(new System.Windows.Forms.Integration.WindowsFormsHost());
_hosts[i].Child = axCVVideo;
_hosts[i].HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
_hosts[i].VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
border.Child = _hosts[i];
//hosts[i].Width = (this.ActualWidth / length) - 1;
//hosts[i].Height = (this.ActualHeight / length) - 7;
axCVVideo.CreateControl();
axCVVideo.Camera = Convert.ToInt16(camCombo.SelectedIndex);
axCVVideo.XResolution = 640;
axCVVideo.YResolution = 480;
//System.Drawing.Rectangle rect = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
//axCVVideo.XResolution = (int)rect.Height;
//axCVVideo.YResolution = (int)rect.Width;
if (axCVVideo.ConnectSync())
{
axCVVideo.Connect();
}
_axCVs.Add(axCVVideo);
if (col == _length)
{
col = 0;
row++;
}
Grid.SetRow(border, row);
Grid.SetColumn(border, col);
rendererGrid.Children.Add(border);
//Grid.SetRow(hosts[i], row);
//Grid.SetColumn(hosts[i], col);
//rendererGrid.Children.Add(hosts[i]);
col++;

<Grid x:Name="someRandomGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
This will cause the grid to have two rows and two columns. The rows will always be half the ActualHeight and the columns will always be half the ActualWidth.
You can do this in codebehind if you really insist on it:
grid.RowDefinitions.Add(new RowDefinition() {
Height = new GridLength(1, GridUnitType.Star)
});
Etc. The number determines how the grid size is divided up. If one column is 1* and the other is 2*, the first one will get one third of the width and the second will get two thirds. If they're both 2*, they'll both get 2/4 of the width (a.k.a. 1/2). It adds up all the numbers and divides. A star without a number in XAML means "1*". If you add a dozen 1* rows, you'll get a dozen rows each of which will dynamically resize to 1/12 the actual height of the whole grid at runtime.
This is not exactly intuitive, but once you learn it, it makes adequate sense.

Related

Dynamically add BoxViews to Grid [Xamarin.Forms]

I am trying to add BoxViews in a Grid format using 3 columns and multiple rows. I have defined the grid using xaml and the behaviour
in the c# file. What should happen is a BoxView should be created for the same number of images with 3 images per column.
Thanks,
XAML
<Grid RowSpacing="0" x:Name="scrollBarGrid">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--Where the search bar will go-->
<BoxView BackgroundColor="Aqua" Grid.Row="0"/>
<SearchBar ></SearchBar>
<!--Where the images will go-->
<BoxView BackgroundColor="Gray" Grid.Row="1"/>
<Grid x:Name="imageGrid" RowSpacing="0" Grid.Row="1">
</Grid>
</Grid>
C#
public MainPage()
{
InitializeComponent();
int colMaximum = 3;
int numberOfImages = 15;
//To add three columns
for (int i = 0; i < colMaximum; i++)
{
imageGrid.ColumnDefinitions.Add(new ColumnDefinition()
{
Width = new GridLength(120, GridUnitType.Absolute)
});
}
//To add an array of rows
imageGrid.RowDefinitions = new RowDefinitionCollection();
for (int myCount = 0; myCount <= numberOfImages / colMaximum; myCount++)
{
imageGrid.RowDefinitions.Add(new RowDefinition()
{
Height = new GridLength(120, GridUnitType.Absolute)
});
//To add a new box view for each
for (int newcol = 0; newcol <= colMaximum; newcol++)
{
for (int newrow = 0; newrow <= numberOfImages / colMaximum; newrow++)
{
imageGrid.Children.Add(new BoxView() { BackgroundColor = Color.Red });
}
}
}
}
When you add children to a grid, you have to specify the Row and Col, otherwise they will be added at 0,0.
imageGrid.Children.Add(new BoxView() { BackgroundColor = Color.Red }, newrow, newcol);

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

Programmatical grid Row definition not working

I have a window with that structure:
Then in the code behind of the window in the constructor I add the following code:
int numRow = 2;
int numColumn = 3;
for (int row = 0; row < numRow; row++)
{
var rd = new RowDefinition();
rd.Height = new GridLength(1.0, GridUnitType.Star);
grdMain.RowDefinitions.Add(rd);
}
for (int column = 0; column < numColumn; column++)
{
var cd = new ColumnDefinition();
cd.Width = new GridLength(1.0, GridUnitType.Star);
grdMain.ColumnDefinitions.Add(cd);
}
for (int row = 0; row < numRow; row++)
{
for (int column = 0; column < numColumn; column++)
{
//var borderImage = new Border();
//borderImage.BorderThickness = new Thickness(1);
//borderImage.BorderBrush = new SolidColorBrush(Colors.Red);
var finalImage = new Image();
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/EasyRun;component/Resources/Images/ITA.png");
logo.EndInit();
finalImage.Source = logo;
//borderImage.Child = finalImage;
Grid.SetRow(finalImage, row);
Grid.SetColumn(finalImage, column);
grdMain.Children.Add(finalImage);
}
by doing so I expect the window to resize rows and columns accordin to the size of the parent window. But what happens is that while the horizontal stretch works the vertical doesn't.
So in short what I'd like is the grid to stretch columns/rows according to its parent window size
Try using a dockpanel instead then a stack panel
<DockPanel Name="stpMain">
<Button DockPanel.Dock="Bottom" Content="AAA" Width="100" Click="Button_Click"></Button>
<Border BorderThickness="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0" BorderBrush="Red">
<Grid Name="grdMain"></Grid>
</Border>

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.

Categories

Resources