Specify a width for a grid column - wpf

I'm using a grid to define a form with this column template :
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
But I need for a specific row to use another column template :
<Label Grid.Column="0" Grid.Row="4">N°</Label>
<TextBox Grid.Column="1" Grid.Row="4" Name="idNum"></TextBox>
<ComboBox Grid.Column="2" Grid.Row="4" Name="idVoie" SelectedValuePath="Key" DisplayMemberPath="Value" SelectedValue="."></ComboBox>
<TextBox Grid.Column="3" Grid.Row="4" Name="idAdr"></TextBox>
with the first three field being 1* and the last field using the free space.
Of course, I can't specify the width directly in the field with percent.
Thanks for your help

You can use a nested grid for that particular row, which spans all four columns of your outer grid:
<Grid Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0">N°</Label>
<TextBox Grid.Column="1" Grid.Row="0" Name="idNum"></TextBox>
<ComboBox Grid.Column="2" Grid.Row="0" Name="idVoie" SelectedValuePath="Key" DisplayMemberPath="Value" SelectedValue="."></ComboBox>
<TextBox Grid.Column="3" Grid.Row="0" Name="idAdr"></TextBox>
</Grid>
Note I'm assuming when you refer to 1* you mean as relative to the grid you already have, i.e. the same size as the first and third columns. Therefore you have a total of 8* across the row, and I've calculated the relative widths for your row to be 1*, 1*, 1*, 5*.

Related

Sharing column widths between multiple grids

I have the following XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Header 1" />
<TextBlock Grid.Column="1" Text="Header 2" />
</Grid>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding SomeList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding Value1}" />
<TextBox Grid.Column="1" Text="{Binding Value2}" />
<Button Grid.Column="2" Content="Button" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
and I want to achieve something like that:
Header 1 |Header 2 | <-- this is the top grid
------------------------------------------------------
Value 1.1 |Value 1.2 |[Button] |
Value 2.1 |Value 2.2 |[Button] <-- | this is the scroll viewer
Value 3.1 |Value 3.2 |[Button] |
which looks similar to a data grid with the fixed header row. I can't use an actual DataGrid because in the real app "Header 1" and "Header 2" are actually not simple grid text headers but rather interactable elements with quite complex markup. The main question is how to achieve the width synchronization for all three columns? The last column should size itself to the widest button in that column while the first two columns should share the remaining space in 50/50 proportion. It feels like this can be achieved using the SharedSizeGroup property but I cannot figure out how exactly.
I think I figured out how to do it:
<Grid Grid.IsSharedSizeScope="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Width="{Binding ActualWidth, ElementName=itemsControl}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" SharedSizeGroup="ButtonColumn" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Header 1" />
<TextBlock Grid.Column="1" Text="Header 2" />
</Grid>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<ItemsControl Name="itemsControl" ItemsSource="{Binding SomeList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" SharedSizeGroup="ButtonColumn" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding Value1}" />
<TextBox Grid.Column="1" Text="{Binding Value2}" />
<Button Grid.Column="2" Content="Button" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
Grid.IsSharedSizeScope="True" and SharedSizeGroup="ButtonColumn" synchronize the last columns.
Width="*" splits the remaining space between first two columns in 50/50 proportion.
Width="{Binding ActualWidth, ElementName=itemsControl}" synchronizes the width of the top header grid with the width of the ItemsControl below which can change when the scroll bar is shown or hidden.
HorizontalAlignment="Left" pushes the header grid to the left to align it with the ItemsControl below.

Lock element on the right

I have two textboxes in my app, with a variable lenght. One is on the left, the other one on the right. By default their width is pretty little, 30 px. But as they contain a lot of numbers, the textbox on the left shifts the right one and enlarges the window (same thing when the right textbw contains too many numbers). To avoid this, I would like to stabilize the right textbox on the right, even if its width rises.
I've tried to play with the columns size, but not.
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="170" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="1" MinWidth="30" Margin="0,0,0,0" Name="maxGmapWest" Text="{Binding Path=Options.MaxGmapWest, ElementName=Window, Mode=OneWay, Converter={StaticResource StringToDoubleConverter}}" PreviewTextInput="Tab1_PreviewTextInput" Width="auto" />
<TextBox Grid.Column="3" MinWidth="30" Margin="230,0,0,0" Name="maxGmapEast" Text="{Binding Path=Options.MaxGmapEast, ElementName=Window, Mode=OneWay, Converter={StaticResource StringToDoubleConverter}}" PreviewTextInput="Tab1_PreviewTextInput" Width="auto" HorizontalAlignment="Left" />
</Grid>
Try something like that markup
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="0" Width="auto" MinWidth="50" VerticalScrollBarVisibility="Auto" Margin="0,0,0,0" HorizontalAlignment="Left" MaxHeight="40" >
<TextBox Name="maxGmapWest" TextWrapping="Wrap" />
</ScrollViewer>
<ScrollViewer Grid.Column="1" HorizontalAlignment="Right" VerticalScrollBarVisibility="Auto" MinWidth="50" Margin="0,0,20,0" MaxHeight="40">
<TextBox Name="maxGmapEast" TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
maxwidth for textbox=width of column, fixed max height and using ScrollViewer for large text

Why does the WPF Grid not share space equally when the middle column has a MinWidth?

In this example the first column gets 100 and the next 2 columns get 50 each, which is the expected behaviour.
<Grid Width="200" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="100" />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Background="Red" Grid.Column="0" />
<Border Background="Yellow" Grid.Column="1" />
<Border Background="Blue" Grid.Column="2" />
</Grid>
If I move the MinWidth to the middle column ...
<Grid Width="200" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition MinWidth="100" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Background="Red" Grid.Column="0" />
<Border Background="Yellow" Grid.Column="1" />
<Border Background="Blue" Grid.Column="2" />
</Grid>
... then the first column gets 33.3 and the last column 66.6 which seems weird. Not sure why this should change the grid's behaviour. I would expect columns 0 and 2 to get 50 each.
Update: I understand why this happens, but was wondering if anyone thinks it is a bug (especially since the behaviour in Silverlight is different)
This issue only arises when you have a center column, which implies you have an odd number of columns defined for your grid. I'm not sure why this is happening nor do I think it's intentional behavior. But, another workaround is to always ensure you have an even number of columns defined even if you are only utilizing an odd number of them (hiding the extra column using MaxWidth=0).
<Grid Width="200" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" MinWidth="100"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" MaxWidth="0"/> <!--Workaround-->
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="Red"/>
<Border Grid.Column="1" Background="Yellow"/>
<Border Grid.Column="2" Background="Blue"/>
</Grid>
Disadvantage here is you have an empty column in your grid. The advantage is you get the expected space distribution behavior.
Just an update.. I have tried the XAML snippet with a combination of .NET 3.5/4.0 Silverlight 3/4 and still could not get equal width for the second example...
This XAML was the only way around that issue:
<Grid Width="200" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*" />
<ColumnDefinition MinWidth="100" />
<ColumnDefinition Width=".5*" />
</Grid.ColumnDefinitions>
<Border Background="Red" Grid.Column="0" />
<Border Background="Yellow" Grid.Column="1" />
<Border Background="Blue" Grid.Column="2" />
</Grid>
Any update on your side guys?
not sure exactly what the issue is, but these two grids behave the way you want them to. I like the second more than the first since it explicitly specifies that the first and third column should take up leftover space equally.
<Grid Width="200" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition MinWidth="100" Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Background="Red" Grid.Column="0" />
<Border Background="Yellow" Grid.Column="1" />
<Border Background="Blue" Grid.Column="2" />
</Grid>
<Grid Width="200" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition MinWidth="100" Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Border Background="Red" Grid.Column="0" />
<Border Background="Yellow" Grid.Column="1" />
<Border Background="Blue" Grid.Column="2" />
</Grid>
If you want equal width, you cannot use Auto. You must explicitly set the width of every column to the desired proportion, for 3 columns you want ".3*" for each.
MinWidth takes precedence if the calculated Width becomes smaller than MinWidth.

Gridsplitter ignores minwidth of columns

I want to have a simple 3 column grid with resizeable columns and a MinWidth of 80.
The code looks like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" MinWidth="80"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" MinWidth="80"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="120" MinWidth="80"/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Center" />
<GridSplitter Grid.Column="3" Width="5" HorizontalAlignment="Center" />
</Grid>
But it doesn't work in the way I want and expected. When the splitters are pushed to the left, all works fine. When the second splitter is pushed to the right all works fine. But if the first splitter is pushed to the right, it pushes the 3rd column and the second splitter out of the grid(or makes their width=0).
I used seperate columns for the gridsplitters, like it was done in the msdn example:
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
...
<GridSplitter Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Background="Black"
ShowsPreview="True"
Width="5"
/>
I also set the alignment to center as i read somewhere right alignment could be a problem
and tried different ResizeBehaviors.
Does anyone know, how to fix this issue, so that at all time the 3 columns are visible with at least 80px width?
Thanks for any help
Try this instead for three columns that have minwidth set to 80. Use * instead of specifying exact width when using gridsplitters.
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="80" />
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="80"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="80"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Column="2" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Column="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Column="4" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
</Grid>
</ScrollViewer>
Not able to post this as comments; So putting this in the Answer list.
If I put a Grid with GridSplitter as the content on the right side of the main Grid with GridSplitter, I'm able to push the right most pane out of bounds of the window. Any idea?
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="80" />
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="80"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<Grid Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="80" />
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="80"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Column="2" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
</Grid>
</Grid>

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

Resources