Is there any shorthand for WPF column and row definitions? - wpf

I have a simple grid layout which is just hosting several labels and textboxes. Labels in the first column, boxes in the second.
Whenever I add a new box, I have to add an empty <RowDefinition /> in to my <Grid.RowDefinitions> block to allow it to occupy a new row. Since I don't have any style attached to these rows, is there some sort of shorthand that would prevent having to to this?
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

No, there isn't a short hand method for this, but you could write your own solution, or use a framework where someone already has.
For example, the CODE framework allows you to define markup as shown in Listing 6 here. This uses a custom panel to greatly simplify the definition of common editing forms.
You could download the source and have a look at their implementation and tailor it for your needs.

You could use an Attached Property to create a shorthand syntax on your own.
I've created a sample here: https://github.com/thomasclaudiushuber/Wpf-Grid-Extensions
It allows you to write this:
<Grid local:GridExtensions.Structure="*,100|200,*">
</Grid>
And behind the scenes it creates this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>

You can subclass Grid and add any behavior you need.
Here is an implementation of AutoGrid that automatically inserts new rows for any AutoGridEndRow object as well as whenever Grid.Row is larger than current definitions count.
Usage as below:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<my:AutoGrid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Content="Label1" />
<TextBox Grid.Column="1" />
<my:AutoGridEndRow />
<Label Content="Label1" />
<TextBox Grid.Column="1" />
</my:AutoGrid>
</Window>

Related

How to build a 3x3 grid with squared center cell in XAML

I am trying to build a 3x3 grid with XAML (for a Windows Phone application) where the center cell should be a square. I have tried the following but it does not work:
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5*" x:Name="centerColumnDefinition" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="{Binding ElementName=centerColumnDefinition, Path=ActualWidth}" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Canvas Grid.Row="1" Grid.Column="1">
...
</Canvas>
</Grid>
Any suggestions for a working solution?
Greetings from Germany,
Tobias
Try this
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition x:Name="centerColumnDefinition"
Width="5*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Rectangle x:Name="CenterRect"
Grid.Row="1"
Grid.Column="1"
Height="{Binding ElementName=CenterRect,
Path=ActualWidth}"
HorizontalAlignment="Stretch" />
</Grid>
It can be tricky to reference column and row definitions because they are not "real" objects in the visual tree. This method avoids the problem by using a separate object in the center cell that can be used to get the proper sizes.
You should be able to replace the rectangle with another type of control if you want, or just leave it and embed your content inside the rectangle.
ActualHeight and ActualWidth are not set until the control is measured and arranged. Usually there is nothing in InitializeComponent() that causes a measure, so you will need to set the Height of your rows after it's calculated. You can do the re-sizing on Loaded event.
Source: https://stackoverflow.com/a/1695518/546896

WPF: Rectangle in Grid ignores margin

In a user control, which I'm embedding in my main view,
I've defined the following layout:
<Grid x:Name="RootGrid" Margin="0,10,0,0" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="20*" />
<ColumnDefinition Width="20*" />
<ColumnDefinition Width="30*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Rectangle Margin="5,0,5,0"
Grid.RowSpan="5"
Grid.ColumnSpan="4"
Panel.ZIndex="-1"
Stroke="Blue"
Fill ="Black"
StrokeThickness="2"
/>
In the preview in Visual Studio, it looks like expected:
- that is the margin 5(for right adjustment) is taken into account.
Unfortunately, during runtime it is another story. I can set the right adjustment (margin) as high as I want, the right border of the rectangle is missing.
Can somebody tell me, what I am doing wrong here? I do not want to work with absolute width for the rectangle (that's working).
Update:
According to the proposal of Erno, I've used a border (and this is indeed much simpler):
<Border HorizontalAlignment="Stretch" Margin="10,0,10,0" Style="{StaticResource StatusPanelBorder}">
<Grid x:Name="RootGrid" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="20*" />
<ColumnDefinition Width="20*" />
<ColumnDefinition Width="30*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
But the issue is still the same.
I'm embedding this view in a main view, which has the following layout:
<Grid Width="1600" Height="Auto" HorizontalAlignment="Stretch" Background="{StaticResource NoiseBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="40*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="600" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
The subview is embedded into the last column of the grid.
If I do not use the 'Stretch' alignment it works, but I want to 'stretch' the UI elements.
Second Update:
The issue was just that the shell view had a smaller width. Problem solved!
The best way to add a border to a grid is to take a border and nest a grid inside of it:
<Border>
<Grid>
...
</Grid>
</Border>
This way the grid and the border will resize the way you probably want, you can control the margins and you do not have to keep the textblocks' margins in sync with the rectangle's border.
EDIT
Looking at the xaml you added to the question I guess you set the width of the window to 1600. If so, the width of the Grid that you also set to 1600 doesn't fit because the width of the window INCLUDES the left and right borders. So forcing the grid's width to 1600 will cut it off at the right.
My advice: do not use hard-coded sizes, use star-sizes for columns and rows and use maximized for windows; Grids will stretch their contents automatically.

Define Column Width as a rest of unused pixels

I would like to define two columns. Second one 1280px wide and the first one the rest of unused pixels. How to do it?
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="9*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="REST OF THE WIDHT" />
<ColumnDefinition Width="1280" />
</Grid.ColumnDefinitions>
</Grid>
You were on to the right idea with your RowDefinition
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="9*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="1280" />
</Grid.ColumnDefinitions>
</Grid>
Star sizing basically tells the layout engine how you would like to divide up the space available to the parent element amount the children, in terms of proportions.
Here are a couple articles that may help:
Star Sizing
WPF Tutorial
Are you sure you want hard coded widths? Resize your browser while running it and see how it looks. If you use "Auto" for one column or row and then "1*" for the other, it will fill the "Auto" with what is needed and then the rest goes to the second one.
I would think this might work better for you:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
</Grid>
Then you start to make use of ScrollViewers for the content that might be bigger than its container.

WPF AutoCompleteBox Width based on Content

I have an System.Windows.Controls.AutoCompleteBox with a fixed width.
The width should dynamically grow based on the content.
How can I achieve this.
Thanks for your help
You can achieve it by placing the AutoCompleteBox in a Grid.Column with Width="Auto". Here's an example:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="30" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<toolkit:AutoCompleteBox />
</Grid>

Grid inside Grid in XAML

I want to have a childGrid in second column of parentGrid (in childGrid I want to have two columns: first for label, second for textbox)
How can I do Something like that? I tried the following code:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Height="*"/>
<ColumnDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column=1>
<Grid.ColumnDefinitions>
<ColumnDefinition Height="*"/>
<ColumnDefinition Height="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>
</Grid>
Based on your code, just fixed up a little:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>
</Grid>
Note that ColumnDefinition don't have a Height - they have a Width. You also need to define the ColumnDefinitions and RowDefinitions separately - you have them mixed together in your outer grid. I removed the RowDefinitions from the outer grid because you don't appear to be using them. Your inner grid has two columns and four rows.
You might find this useful. Try pasting this into a page using Kaxaml and playing around with the various parameters of the objects in the outer Grid. I find using Kaxaml for prototyping and experimenting with XAML layouts indispensable.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--
When I'm composing grids in XAML, I group things together by type, not by where
they live in the grid. This turns out to make a lot of maintenance tasks
easier.
Also, since Grid.Row and Grid.Column default to 0, a lot of people (and tools)
omit them if that's their value. Not me. It lets me quickly check to make
sure that content is where I think it is, just by looking at how it's organized
in the XAML.
-->
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Background="Lavender" Padding="10" HorizontalAlignment="Stretch">Here's the first row of the outer grid.</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Background="Lavender" Padding="10" HorizontalAlignment="Stretch">Here's the third row of the outer grid.</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" Background="AliceBlue" Padding="10">Here's the first column of the second row.</TextBlock>
<Grid Grid.Row="1" Grid.Column="1">
<Grid.ColumnDefinitions>
<!--
This part's pretty important. Setting up the SharedSizeGroups for these
two columns keeps the labels and text boxes neatly arranged irrespective of
their length.
-->
<ColumnDefinition SharedSizeGroup="Label"/>
<ColumnDefinition SharedSizeGroup="TextBox"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0">First label</Label>
<Label Grid.Row="1" Grid.Column="0">Second label</Label>
<Label Grid.Row="2" Grid.Column="0">Third label, containing unusually long content</Label>
<TextBox Grid.Row="0" Grid.Column="1">First text box, containing unusually long content</TextBox>
<TextBox Grid.Row="1" Grid.Column="1">Second text box</TextBox>
<TextBox Grid.Row="2" Grid.Column="1">Third text box</TextBox>
</Grid>
</Grid>
It might come a little confusing how to put controls in sub grids. Here is an example.
We have 3 * 3 cell grid. And then center cell is further divided in 3 rows where each row has a button.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Button1"/>
<Button Grid.Row="1" Content="Button2"/>
<Button Grid.Row="2" Content="Button3"/>
</Grid>
</Grid>
Result:
Phenevo, I've done XAML UI design extensively this year. Try this out, you can easily migrate the code to either a Window or a UserControl. I color-coded the grids and panels so that you could affirm their layout in real time -- blow away the background parameters when you're satisfied.
<UserControl
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"
x:Class="UatControlLibrary.sampleChilGrid"
x:Name="UserControl"
MinWidth="400"
MinHeight="300"
Width="auto"
Height="auto">
<Grid
x:Name="LayoutRoot">
<Grid
x:Name="parentGrid"
Width="auto"
Height="auto"
Background="Red">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="1*" />
<ColumnDefinition
Width="1*" />
</Grid.ColumnDefinitions>
<Grid
x:Name="chilGrid"
Width="auto"
Height="auto"
Background="Black"
Grid.Column="1"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="1*" />
<ColumnDefinition
Width="1*" />
</Grid.ColumnDefinitions>
<StackPanel
x:Name="stkpnlLabels"
Background="White"
Grid.Column="0"
Grid.Row="0" />
<StackPanel
x:Name="stkpnlTextboxes"
Background="Blue"
Grid.Column="1"
Grid.Row="0" />
</Grid>
</Grid>
</Grid>
</UserControl>

Resources