How to layout controls and make it resizable - wpf

I would like to place the controls as listed below in WPF. Please given an example to do the same.

<Grid x:Name="ContentRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" .../>
<TextBox Grid.Column="1" .../>
<Button Grid.Column="2" .../>
<Button Grid.Column="3" .../>
</Grid>
Assuming that ContentRoot is placed directly in your Window, it'll inherit it's Width and Height from the Window. Then it'll assign 200px to the 0th column, and 100px each to the 2nd and 3rd columns. And any leftover space will be assigned to the 1st column.
Of course, you can change 200, 100, and 100 to whatever you want.
If needed, add MinWidth="<value>" (replace <value> with a number) in the 1st ColumnDefnition to specify a minimum width that column must have.

Related

Autosizing a grid column to take up remaining space in parent

In WPF, I am having a heck of a time trying to get a grid to size properly.
I have the following layout for my grid:
<ItemsControl HorizontalContentAlignment="Stretch">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" />
<Label Grid.Column="1"/>
<TextBox Grid.Column="2"/>
<Button Grid.Column="3"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The problem is that Width="Auto" seems to be sizing that column to the width of the content, and not filling out the extra space in the parent container. This leaves the rest of the columns all unaligned, and ugly blank space at the end of each row.
I'm probably missing something simple, but I can't seem to find a method to fit the column appropriately.
Or is there a better control for the job?
* means fill or share. If you had two with * then they would share the width evenly.
<ColumnDefinition Width="*"/>
Seems I found a solution after a bit more tinkering around.
The problem was: <ColumnDefinition Width="Auto"/>
This was causing the column to fit to the content. I changed it to: <ColumnDefinition />
This causes the column to fit to the empty space left in the parent container, regardless of content size.

Within a Grid, how to set a textblock's width

I have a Grid, there are two columns, here is the definition.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Name="nText" Text="{Binding Name}" Grid.Column="0" />
<TextBlock Name="vText" Text="{Binding Value}" Grid.Column="1" HorizontalAlignment="Left" TextWrapping="Wrap"/>
</Grid>
My question is, for the vText, when the Text is too long, the text can not be wrapped, no matter the columndefinition width is auto or *. But if I set a definited value to the column 2 's width or to the vText 's width, the text will be wrapped.
How can I set the textblock's width so that the text content can be wrapped?
I have tried to bind to columnDefinition's width/ActualWidth, but also failed.
Great thanks.
To elaborate on BalamBalam's answer, changing
<ColumnDefinition Width="auto"></ColumnDefinition>
to
<ColumnDefinition Width="*"></ColumnDefinition>
will do what you want because "auto" mode expects to infer its size based on the child elements. In this case, your TextBlock doesn't have a Width defined, so there's no way for the ColumnDefinition to infer the width.
Because neither the ColumnDefinition nor the TextBlock have a width defined, the TextBlock's width will default to infinite, and the word wrap algorithm will never clip the text.
By contrast, "*" means to fill remaining space, which will either be defined by the grid (if you set a width on it), or one of its parents. Worst case, the "*" will be able to find a value at the top level, because a window always has a width/height set.
Hopefully this sheds a bit more light on how the layout engine does its magic with sizes!
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Name="nText" Text="nText"/>
<TextBlock Grid.Column="1" Grid.Row="0" Name="vText" TextWrapping="Wrap">
vText vTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvText
vTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvText
vTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvTextvText
</TextBlock>
</Grid>

WPF - Resizing Children to Fill a Parent

In WPF, I simply want to have a 'container' which has 3 textblocks. I would like these 3 textblocks to be sized so they each take up 1/3 of the parent's width. I noticed that the stackpanel sizes the last child automatically, but is there a way to size each child automatically?
Use a Grid or a UniformGrid
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="1" Grid.Column="0"/>
<TextBlock Text="2" Grid.Column="1"/>
<TextBlock Text="3" Grid.Column="2"/>
</Grid>
The grid is very common and in every WPF-App used a lot. However also the UniformGrid is very handy but not so well known.

Silverlight - Auto-resize textbox to fill up empty space

Ok this is what I wish to do.
I have a resizeable window which has 3 controls in same row in flowing order: textBlock, textBox and button.
textBlock and button have dynamic texts. So theirs size depends upon text inside.
Now what I wish to do is that textBox in the middle is always filling up all empty space between textBlock and button.
How do I do that?
I tried with the following code but it doesn't work because of fixed width in 1. and 3. column.
<Grid Margin="0,0,5,0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Left" Text="Text1"/>
<TextBox Grid.Column="1"/>
<Button Grid.Column="2" Content="Button1" HorizontalAlignment="Center"/>
</Grid>
You can use Auto for the two outer column widths instead of specifying the width
<Grid Margin="0,0,5,0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Text1" />
<TextBox Grid.Column="1"/>
<Button Grid.Column="2" Content="Button1" />
</Grid>
You probably don't need the HorizontalAlignment in the columns either

Text wrapping expands the column to fit the text

I've got a grid defined simply:
<Grid Margin="0,5,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="48"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
Then I'm trying to bind some content like this:
<TextBlock TextWrapping="Wrap" Grid.Column="3" Text="{Binding Text}">
Set up like this, the text won't wrap. It simply expands the column to fit the text. If I set the Width to a fixed amount on the last column, wrapping works as expected. The problem there is that if the user widens the window, the column stays at a fixed size. How can I get the column to size dynamically with the width of the grid, but still wrap the text within it?
A width of "*" will split any remaining space evenly between the columns using "*". If you have a single column with Width="*", that column will get all remaining space. If you have 2 columns with Width="*", each will get 1/2 of the remaining space.
Here's a good article on grid sizing that includes star sizing.
There's one frustrating case I discovered that can break even with Width="*" and thats when you have IsSharedSizeScope= true.
<Border BorderBrush="Red" BorderThickness="1">
<StackPanel Grid.IsSharedSizeScope="True">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="G1"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="G2" />
<ColumnDefinition Width="*" SharedSizeGroup="G3" />
</Grid.ColumnDefinitions>
<TextBlock Text="Col0" Grid.Column="0" Margin="0,0,5,0"/>
<TextBlock Text="Col1" Grid.Column="1" Margin="0,0,5,0"/>
<TextBlock Text="A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" TextWrapping="Wrap" Grid.Column="2"/>
</Grid>
</StackPanel>
</Border>
This won't wrap, but if you change Grid.IsSharedScopeSize to false then it does.
Haven't found a solution yet, but this can be another reason it won't work.
Try this:
<Grid Margin="0,5,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="48"></ColumnDefinition>
<ColumnDefinition Name="ParentColumn" Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock TextWrapping="Wrap" Grid.Column="3" Text="{Binding Text}"
MaxWidth="{Binding ActualWidth, ElementName=ParentColumn}">
Set its width to "*"
You should use Auto only when you want to column/row to size depending on content in said column/row. If you want to "asign rest of space" use "*".
In your case, TextBlock needs to know how much space it has before acutal measure, so it can tell where to wrap the text.

Resources