Basically, I want to emulate the GridSplitter.FixedPanel
feature available in WinForms
.
XAML :
<UserControl ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" />
<GridSplitter
Grid.Column="1" Width="3" VerticalAlignment="Stretch"
Background="Transparent"
ResizeDirection="Columns" ResizeBehavior="PreviousAndNext" />
<ListBox Grid.Column="2" />
</Grid>
</UserControl>
This works great and resizes each side accordingly. But suppose we resize the (not maximized) window containing this UserControl, now both grid columns on each side of the splitter (auto) resizes. The 4/5 and 1/5 column width ratios are required for space distribution upon start, but practical space allocation depends on the displayed data, hence the grid splitter.
How to make one column retain its width (the one on the right for instance as it hosts properties, tools, etc.) while the window gets resized around, hence only making the left column resize.
I have some ideas :
- Just code behind to emulate FixedPanel like in WinForms : DragStarted, DragCompleted and some private fields for eg.
- Use a
Behavior
like suggested in this SO topic (I have not used Behaviors for years, have some refreshing to do - To be honest, I really hope there is an XAML-only way, but if there isn't, I prefer the code behind way where I expose new dependency propertie(s) rather than a behavior) - I believe I'm missing one feature of WPF to achieve this the WPF way. Almost all times I thought "well I guess I have to code behind this...", there were the WPF way, usually simplier, safer, easy to design and better, performance wise. That's why I'm asking directly, and maybe would help someone else looking for the feature.
Programming language (for that matter) : C#
Edit : after Léo Savador's answer :
See : there were a WPF way (toying with XAML ColumnDefinition
Width
properties) and little code :
bool p_layoutInitialized = false;
void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) {
if (e.NewSize.Width > 1) { // optional : && e.NewSize.Height > 1
if (!p_layoutInitialized) {
RightColumn.Width = new GridLength(MainGrid.ActualWidth / 5);
p_layoutInitialized = true;
}
}
}
where RightColumn
is the name of the ColumnDefinition
on the right, and MainGrid
the name of the Grid
.
Thanks you so much, was in the process of writing heavy code behind. You saved me so much time :D
PS : Please do not assume I'm a WinForm fanboy. I'm only mentionning WinForms to give a comparative example of the desired feature, could have used CSS and JS, but much harder to describe.
CodePudding user response:
Here is a simple solution that I can recommend to you for your need:
For your right column, instead of using a dynamic width (1*), use a fixed width:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="160" />
</Grid.ColumnDefinitions>
If you set a fixed width of 160:
- You will get the same initial result (1/5 of the initial width of your window)
- You will be still able to resize your grid
- On resize, your right column will keep it's width
And you have also the possibility to use code behind to calculate the desired fixed width at startup, according to the window initial width, to be more "dynamic".