Gridsplitter ignores minwidth of columns - wpf

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>

Related

WPF How to make control resize relative to next control

I have defined the following XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="200" />
<ColumnDefinition MinWidth="200" />
<ColumnDefinition MinWidth="500" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="2,2,5,2">
<GroupBox Header="Computer">
<DockPanel>
<ComboBox MinWidth="100" Name="cmbComputerNames" IsEditable="True" DockPanel.Dock="Left" HorizontalAlignment="Stretch" Width="auto" />
<Button Content="Connect" Name="bConnect" Width="65" HorizontalAlignment="Right" />
</DockPanel>
</GroupBox>
</StackPanel>
<Button Grid.Column="1" Content="Two" Margin="1,2,5,2" />
<Button Grid.Column="2" Content="Three" Margin="1,2,2,2" />
<GridSplitter Height="100" Width="4" Grid.Column="0"/>
<GridSplitter Height="100" Width="4" Grid.Column="1"/>
</Grid>
So, the left grid column is resizable. I want the "Connect" button to remain right-aligned and with same width. The combobox however, should be left-aligned and the width should grow as the column is resized, so the distance to the connect button remains the same.
Doesn't work:
Can anyone tell me how I can achieve that?
Since this is too long for a comment
Replace DockPanel with Grid and try this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<GroupBox Header="Some text here">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ComboBox MinWidth="100"/>
<Button Grid.Column="1" Content="A button" Margin="5"/>
</Grid>
</GroupBox>
<GridSplitter Grid.Column="1" Grid.RowSpan="2" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext" Width="10"/>
<Button Content="some button" Grid.Column="2"/>
</Grid>
#Andy, if you could produce an answer then I will delete mine.

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.

Why doesn't a textbox stretch inside stackpanel WPF?

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="49*" />
<ColumnDefinition Width="25*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Margin="30" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,5,0" Text="Username:" />
<TextBox HorizontalAlignment="Stretch"/>
</StackPanel>
</StackPanel>
--Result image--
Im trying to make it so that the textbox will fill the rest of the space inside the current StackPanel.
however the "Stretch" propety doesn't seem to work - why is that?
Is there a different way do it or what am I doing wrong?
A StackPanel always tries to achieve the minimum possible height/width, depending on orientation; therefore, Stretch has no effect. You might want to use a DockPanel instead, which allows children to stretch:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="49*" />
<ColumnDefinition Width="25*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1"
Margin="30"
VerticalAlignment="Center">
<DockPanel>
<TextBlock DockPanel.Dock="Left" Margin="0,0,5,0"
Text="Username:" />
<TextBox HorizontalAlignment="Stretch"/>
</DockPanel>
</StackPanel>
</Grid>

Grid + splitter

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas Grid.Column="0" HorizontalAlignment="Stretch" Background="Orange"/>
<GridSplitter Grid.Column="1" Width="4" Background="Black" />
<Grid Grid.Column="2" />
When I resize the Canvas in column 0, the canvas is not stretched to fill its column.
The stretch doesn't seem to work.
When I use Width="*" (which I actually do not want) for the first column I canot move the spliter to the left.
My requirement is that the first column is resizable (with a minimum) and that the canvas fills the first column.
Try this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas Grid.Column="0" Grid.ColumnSpan="2" Background="Orange" />
<GridSplitter Grid.Column="1" Width="4" Background="Black" />
<Grid Grid.Column="2" Background="Green"/>
</Grid>
Grid.ColumnSpan="2" is the key.
You need to set HorizontalAlignment="Stretch" on Grid Splitter to get it work.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas Grid.Column="0" HorizontalAlignment="Stretch" Background="Orange"/>
<GridSplitter Grid.Column="1" Width="4" Background="Black"
HorizontalAlignment="Stretch" /> <-- HERE
<Grid Grid.Column="2" />

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

Resources