PowerShell GUI Basics: Building Grids With WPF (Video Tutorial)PowerShell GUI Basics: Building Grids With WPF (Video Tutorial)
Learn how to build and customize grid-based GUIs in PowerShell using Windows Presentation Foundation.
February 5, 2025
This tutorial explains how to use PowerShell with the Windows Presentation Foundation (WPF) to create and manipulate a grid-based user interface.
We will cover defining rows and columns, positioning elements within grid cells, and adjusting row sizes dynamically. Additionally, you will learn how to fine-tune element placement using margins, providing greater control over UI layout and spacing.
Subscribe to ITPro Today’s YouTube channel for Linux tutorials and more.
The following transcript has been edited for length and clarity.
Transcript:
Brien Posey: Hello, greetings and welcome. I'm Brien Posey. In this video, I will show you some techniques for working with the grid in the Windows Presentation Framework using PowerShell.
One of the things that's somewhat unique about the Windows Presentation Framework is that when you arrange GUI objects on the screen or within a window, you do it using a grid. In other words, we create a series of rows and columns, like a spreadsheet, and then we insert GUI objects within the grid's "cells."
Building a Simple Grid in PowerShell With WPF
Let's look at how this works. Here is a simple PowerShell script that creates a three-by-three grid.
Add-Type -AssemblyName PresentationFramework
# Create the main WPF window
$Window = New-Object System.Windows.Window
$Window.Width = 800
$Window.Height = 600
# Create the grid
$Grid = New-Object System.Windows.Controls.Grid
# Define 3 rows and 3 columns
$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))
$Grid.RowDefinitions.Add((New-Obiect System.Windows.Controls.RowDefinition))
$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
# Add a label to Row 0, Column 0
$Label = New-Object System.Windows.Controls.Label
$Label.Content = "Hello World"
[System.Windows.Controls.Grid]::SetRow($Label, 0)
[System.Windows.Controls.Grid]::SetColumn($Label, 0)
$Grid.Children.Add($Label)
$Window.Content = $Grid
$Window.ShowDialog()
Let's step through this quickly.
Initially, I'm adding in the Windows Presentation Framework assembly:
Add-Type -AssemblyName PresentationFramework
I define the Windows Presentation Framework window. I do that by setting up a variable called $Window equal to New-Object of type System.Windows.Window. Then, I set the window width and height.
Next, we create the grid. I've created a variable called $Grid and set it equal to a New-Object of type System.Windows.Controls.Grid.
From there, we begin creating rows and columns. In this script, I set up the rows first, and you can see that I'm referencing the $Grid variable I just created. I have RowDefinitions.Add. I'm adding a RowDefinition, and then that RowDefinition will be New-Object of type System.Windows.Controls.RowDefinition. I repeat this line of code three times to create three separate rows within this grid.
Creating columns works the same way. I'm setting up three columns in this block of code. You can see I've got $Grid (the variable corresponding to my grid) and .ColumnDefinition.Add. For the ColumnDefinition, I've got New-Object of type System.Windows.Controls.ColumnDefinition.
Next, I need to create a label. A label is just a mechanism to display text on the screen. In this case, we've just got a block of text that says, "Hello World." $Label is a New-Object of type System.Windows.Controls.Label.
Then, I define the $Label.Content: the words "Hello World." I add the label to the grid by first specifying the row that that label will go in. For this RowDefinition, I'm inserting $Label (the name of our label) in Row 0. Row 0 will always be the first row, i.e., the row at the top of the grid. I do the same with the columns, inserting $Label in Column 0, the left-most column.
The last thing to do is add the grid to the window and display it. Let's see what this looks like when I run the script. We've created a label containing the words "Hello World" and put that label in Row 0, Column 0 (the upper-left corner of the grid).
Now, what if we wanted to move this label elsewhere? Well, that's easy enough to do. Let's put the label in Row 1, Column 1. I'll change the row to Row 1 and the column to Column 1.
Let me save my changes and run the script. Now you can see that our label has moved.
So, that's the basics of adding a label to a grid.
Visualizing Grid Layouts
Now that I've shown you the basics, I will show how you can manipulate this. I want to show you another script that I've created for the sake of illustration.
I'm not going to go through all the code on this one because I'm going to cover the highlights with two other scripts that I've got.
I'll run the script. We see a window that illustrates the various positions within the grid. The window size is smaller than earlier, but the script works essentially the same way. The only thing that I'm doing differently is creating multiple labels so that you can see the various positions.
Remember: Row 0 is the first row at the top of the grid, and Column 0 is the first column at the left-most portion of the grid. Here, we have Row 0, Column 0, Row 0, Column 1, Row 0, Column 2. Beneath that, we have Row 1, Column 0, Row 1, Column 1, Row 1, Column 2, and so forth.
If you think back to the earlier script, we initially placed the label at Row 0, Column 0, and the text appeared in the upper-left portion of the window. You can see Row 0, Column 0, and that's about where our text appeared. Then, I made a change to display the label in Row 1, Column 1. If you look right here, Row 1, Column 1, is in the center. So, that's why we saw that text label move. I wanted to give you a better feel for the positions within the grid.
Controlling Row and Column Sizes Dynamically
I have another script to show you:
Add-Type -AssemblyName PresentationFramework
# Create the main WPF window
$Window = New-Object System.Windows.Window
$Window.Width = 800
$Window.Height = 600
# Create the grid
$Grid = New-Object System.Windows.Controls.Grid
# Define 3 rows and 3 columns
# Absolute row (50px)
$Row0 = New-Object System.Windows.Controls.RowDefinition
$Row0.Height = "50"
$Grid.RowDefinitions.Add($Row)
# Star-sized row (shares remaining space proportionally)
$Row1 = New-Object System.Windows.Controls.RowDefinition
$Row1.Height = "1*"
$Grid.RowDefinitions.Add($Row1)
# Star-sized row (shares remaining space proportionally)
$Row2 = New-Object System.Windows.Controls.RowDefinition
$Row2.Height = "2*" # This row will get twice as much space as a
"1*" row
$Grid.RowDefinitions.Add($Row2)
# Auto-sized row adjusts to content size)
$Row3 = New-Object System.Windows.Controls.RowDefinition
$Row3.Height = "Auto"
§Grid.RowDefinitions.Add$Row3)
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows. Controls.ColumnDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
# Add a Rectangle to act as a background for Row 0
$Rectangle = New-Object System.Windows. Shapes.Rectangle
$Rectangle.Fill = "Pink" # Set background color
[System.Windows.Controls.Grid]::SetRow($Rectangle, 0)
[System.Windows.Controls.Grid]::SetColumnSpan($Rectangle, 1)
[System.Windows. Controls.Grid]:: SetColumnSpan($Rectangle, 2)
[System.Windows.Controls.Grid]::SetColumnSpan($Rectangle, 3)
$Grid.Children.Add($Rectangle)
# Add a Rectangle to act as a background for Row 2
$Rectangle = New-Object System.Windows.Shapes.Rectangle
$Rectangle.Fill = "LightBlue" # Set background color
[System.Windows.Controls.Grid]::SetRow($Rectangle, 1) [system.Windows.Controls.Grid]::SetColumn($Rectangle, 1)
$Grid.Children.Add($Rectangle)
We can use this script to play around with row sizes because sometimes you may want to have more control over the size of your rows based on the types of objects that you place in those rows.
I've got a few different methods that I will use to control the row sizes. Before I step you through that, let me run the script so that I can have the output on screen. Immediately, you can see that I added color to each one of the rows. You'll also notice that the rows are now of different sizes.
Adding color
Let me show you first how I added the color. I don't want to go too much into coloring because that's kind of beyond the scope of this video, but I at least want to show you how I did it.
You can see that I've got a section, "Add a Rectangle to act as a background for Row 0." I set up a variable called $Rectangle. I set it equal to New-Object of type System.Windows.Shapes.Rectangle. I'm creating a rectangle object. Then, I said $Rectangle.Fill and set the color equal to "Pink."
I had to specify where I wanted that rectangle to appear. We have System.Windows.Controls.Grid and SetRow. I place the $Rectangle on Row 0. Now, we also must specify a column, and I needed this rectangle to span the entire width of the window.
The window has three columns. So, I just duplicated the rectangle in each one of the columns. You can see SetColumnSpan($Rectangle, 1), then 2 and 3. I'm placing the rectangle in all three of my columns.
Lastly, I added that rectangle to the grid.
So, that's how I handled the different colors you see in the output.
Controlling row size
Having covered that, let's return to the subject at hand: How do we control the size of the rows?
It's worth noting that I'm only focusing on row sizes for this video, but you can do the same thing for column sizes. You can handle column sizes in the same way as what I'm about to show you. I'm focusing on rows for the sake of simplicity.
As you'll recall, when I showed you my very first script, I mentioned that I was defining rows on a single line of code. Later, I said I would break that out into multiple lines of code. That's what I've done here.
Let's look at Row 0. You will notice the row height is set to "50" (50 pixels). If you look at the pink row in my output, it is 50 pixels high. So, if you need to create a row of a specific size, that's how you would go about it.
I'm doing something slightly different for the green and the blue rows.
We have $Row1 that we're defining, and I set the RowDefinition up similarly. I add the row to the grid in the same way. The same could also be said for the next row, $Row2. I set up the RowDefinition and add the row to the grid.
But look at what I did for row height. Here, I have $Row1.Height equals 1*. Beneath that, I have $Row2.Heigh equals 2*. So, this is a dynamic way of defining rows, and the row sizes are relative. If you use two asterisks, the row will get twice as much space as if you had used one asterisk.
The green row's size gets generated dynamically based on the window size. So, this is a unit of one, for lack of a better word.
In the blue row, we told it to use two units instead of one, so the blue section will be twice the size of the green section.
We have one more row down here at the bottom: our gray row. For the gray row, I just set the row height to "Auto" to create a row with its height based on the object we're inserting into it. The object I inserted was a text label. You'll notice that the row was sized based on the size of that text label. That's how you adjust row height.
As I said earlier, column height works the same way. The only difference is that you apply the height to the ColumnDefinition instead of the RowDefinition.
Positioning Elements With Grid Margins
I have one more script to show you:
Add-Type -AssemblyName PresentationFramework
# Create the main WF window
$Window = New-Object System.Windows.Window
$Window.Width = 800
$Window.Height = 600
# Create the grid
$Grid = New-Object System.Windows.Controls.Grid
# Define 3 rows and 3 columns
$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))
$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))
$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
# Add a Rectangle to act as a background for Row 2
$Rectangle = New-Object System.Windows.Shapes.Rectangle
$Rectangle.Fill = "LightBlue" # Set background color
[System.Windows.Controls.Grid]::SetRow($Rectangle, 1) [system.Windows.Controls.Grid]::SetColumn($Rectangle, 1)
$Grid.Children.Add($Rectangle)
# Add a label to Row 0, Column 0
$Label = New-Object System.Windows.Controls. Label
$Label.Content = "Hello World"
# $Label.Margin = "50" # Uniform margin of 50 on all sides
# $Label.Margin = "20,10,30, 5" # Custom margins
# Left 20, Top 10, Right 30, Bottom 5
# $Label.Margin = "70,0,70,0" # Horizontal spacing only
[System.Windows.Controls.Grid]::SetRow($Label, 1)
[System.Windows.Controls.Grid]::SetColumn ($Label, 1) I
$Grid.children.Add($Label)
In this case, you'll notice a blue rectangle in the middle of the screen. The words "Hello World" appear in the upper-left portion of the rectangle. I created this script to show you how to place an object within a cell in the grid with more precision.
Let's look at what we're doing here. Once again, we are creating a three-by-three grid. The grid definition is like what I showed you in the initial script. We have one line of code for each row and one line of code for each column. So, we have three rows and three columns.
Next, I created a colored rectangle. This time, instead of spanning the entire width of the grid, I made one rectangle and placed it in a single cell. I put the rectangle in Row 1, Column 1. Remember, Row 0 is the top row, so Row 1 is the row beneath it. Column 0 is the left-most column, so Column 1 is the column just to the right of Column 0.
In the middle cell of the grid, you can see that the rectangle does indeed appear in the middle.
Now, let's look at the section where we create the label. I'm placing the label in Row 1 and Column 1, so the label appears in the same cell as the rectangle. However, you'll notice that the label appears in the upper-left corner of this rectangle. Even though we're telling PowerShell that we want this label to appear in the center cell within our grid, the label appears in the cell's upper-left corner. So, we're not centering the text here.
What could we do if we needed to center the text on the screen? Here is where the concept of margins comes into play. Margins don't just apply to labels. They apply to just about any GUI object you create using WPF. The margin controls the element's position within a cell in our grid.
I will show you a few examples of margins. We currently don't have a margin set up. As a result, the label is added to the upper-left portion of the cell we've designated. I will remove the comment symbol (#) for this line of code:
$Label.Margin = "50" # Uniform margin of 50 on all sides
"50" represents 50 pixels. This line will give us a margin of 50 pixels around that label.
If you look at the label again, it's in the upper-left corner of this cell. Pay attention to the positioning of the words "Hello World." Let me close this out, and I'll save my changes and rerun the script. And now you can see that my label has moved based on that margin I've set up. So, we have a buffer of 50 pixels from the top and 50 pixels from the left. Technically, there's also a buffer of 50 pixels from the right and the bottom, but because of the size of our label, those aren't coming into play.
With that said, let's look at another way to define a margin. I'm going to go ahead and add that comment symbol back in. If you look at the subsequent line of code, you can see that we have:
$Label.Margin = "20,10,30, 5" # Custom margins
This line is what's known as a custom margin. Incidentally, I picked the numbers off the top of my head. The numbers translate to a margin of 20 from the left, 10 from the top, 30 from the right, and five from the bottom. I will erase the comment symbol, save my changes, and show you what this looks like.
Here, we have a margin of 20 pixels from the left of the cell, 10 pixels from the top of the cell, 30 pixels from the right, and five pixels from the bottom.
So, that's how you define a custom margin.
There's one more margin type to show you. It is a variation of the technique that I just showed you. You can control margins purely horizontally or purely vertically. So, let me go ahead and remove this comment symbol for this line:
$Label.Margin = "70,0,70,0" # Horizontal spacing only
This line of code looks like the one I just showed you, except we have a left and a right margin of 70 and a top and bottom margin of zero. It will force the label to appear at the top of the cell, but we're going to have a buffer of 70 pixels on each side. When I save this and rerun the script, the "Hello World" label returns to the very top of the cell, but we have a 70-pixel buffer on the left and right.
So, those are some techniques you can use to experiment with an object's placement inside a grid cell. I'm Brien Posey. Thanks for watching.
About the Author
You May Also Like