My question is simple. What is the best way to achieve what you see the pic below in WPF?
At the moment this is a horizontal StackPanel, with the right padding of the checkbox set to 90. This works okay, but if you resize the window it's no good anymore, unless maybe you re-adjust the padding in the window's resize event, but that seems clunky when using a layout manager.
I am coming from a Qt background, and in Qt I would use a "stretch" element between the buttons and the checkbox to push them apart dynamically. Is there a similar concept in WPF? If not, how do I achieve this so that it will support dynamic resizing?
Thanks!
Use the corrent Panel implementation, in this case a Grid would work best:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox>Details</CheckBox>
<Button Grid.Column="1">Exit</Button>
<Button Grid.Column="2">Reset</Button>
</Grid>
Related
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.
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".
I'm trying to resolve some layout problems in my Xamarin.Forms application. For example, when height of content is higher than body content height, then lists will collapse.
I have undefined amount of lists with custom item templates. I want to remain all height of each list and have possibility of scrolling them.
I tried use StackLayout but it doesn't support scrolling. When I use ScrollView, the Auto property doesn't work correctly (there is ambigous space between each of lists).
My code looks like this:
<Grid>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0"> //Header
...
</Grid>
<StackLayout Grid.Row="1"> //Group of lists
<ListView x:Name="firstList" ItemTemplate="..." ItemsSource="...">
</ListView>
<ListView x:Name="secondList" ItemTemplate="..." ItemsSource="...">
</ListView>
...
</StackLayout>
</Grid>
How can I position these lists on full height?
What you try to achieve is very ambiguous from the mobile app perspective. Think the other way around: While your screen is full of stacked ListViews, how would the system know it has to scroll down the page or scroll down the current ListView?
Also nesting ListView into ScrollView is a very bad practice because:
ListView implements its own scrolling.
ListView will not receive any gestures -> they will be handled by the parent ScrollView.
also ListView can have customized header and footer that scrolls with the elements of the list, potentially offering the functionality that the ScrollView was used for.
If you want to stick to this layout, your option here would be to design your own implementation of your control using custom renderers and manage the gesture.
Hope it helps and happy coding!
I have the problem, that my Grid is not filling the space as I want it.
Here some code:
<HubSection>
<Grid Width="850">
<Grid.RowDefinitions>
<RowDefinition Height="35"/>
<RowDefinition Height="*"/>
<RowDefinition Height="310"/>
</Grid.RowDefinitions>
<Input:RadDatePicker Grid.Row="0" Value="{Binding CurrentDate, Mode=TwoWay}" />
<ListView
Grid.Row="1">...
</ListView>
<Grid Height="310"
Grid.Row="2">...
</Grid>
...
I want that the middle row is filling the space up of the hubsection. Instead it now just fills up when the listview contains enough items.
Any idea?
Now the filled ListView:
I would try setting the VerticalContentAlignment of the HubSection to Stretch as well as setting the VCA of the outer grid to that option. I'm suspecting the default might be Center or Top and so the minimizing vertical alignment control from the parent control and the expanding star-sized row setting of the inner grid come in a little bit of a conflict that some layout prioritizing rules probably resolve in getting the VCA rule to win.
For similar layout issues it is usually best to analyze with a visual tree debugger such as the XAML Spy or WinRT XAML Toolkit. You can also try tracing these various properties by walking the visual tree with the VisualTreeHelper class yourself.
I hope you can help me with my problem. It's about a custom designer for a WF 4.0 activity, but the problem is essentially in the WPF of the designer.
Some background
I've created a custom WorkFlow activity to send e-mails. For the custom designer for the activity, I've previously been using regular Textboxes for the "Subject" and "Body" of the e-mail, but I'd like to use the ExpressionTextBox to easily bind it to the InArguments of the activity. The ExpressionTextBoxes are in a grid, and this grid is on a StackPanel.
I've set the the MinWidth, MaxWidth and Margin of the ExpressionTextBoxes to fit with the other controls, and in the Visual Studio Designer (viewing the custom activity designer, not the actual WorkFlow) everything looks as it should.
<sapv:ExpressionTextBox Grid.Column="1" Grid.Row="2" Height="Auto" HorizontalAlignment="Right" Margin="4, 4, 4, 4"
Expression="{Binding Path=ModelItem.Subject, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
ExpressionType="{x:Type TypeName=sys:String}" OwnerActivity="{Binding Path=ModelItem}" VerticalAlignment="Center" MaxWidth="176" MinWidth="175" />
The problem
When used, initially it also looks as it should, but when the ExpressionTextBoxes are edited, they shrink into being really small. When text is entered, the control expands to fit the text, until it reaches its MaxWidth. When the editing ends, it goes back to it's MaxWidth. I'd prefer if it stayed the same size, regardless of being in edit-mode or not.
If you can't see it, open the image here
What I've tried
I've mostly been doing WinForms, and I'm pretty inexperienced with WPF, so I don't know if there are some funky properties or other settings that I've missed. I've tried setting width-properties of the parent controls (StackPanel and Grid), I've tried setting just the width (no min/max), but it seems to shrink regardless of what I set.
If you would like more information or code, please don't hesitate to ask.
Update
As you can see in the comments to Maurices answer, I figured out how to avoid the problem by removing the horizontalAlignment property, and then using margins to align it to the right. But I'm not going to mark an answer, until there's an explanation of why this behaviour happened in the first place. My XAML was almost identical to what Maurice posted, so there must be something wrong elsewhere.
The XAML for the ExpressionTextBox looks fine to me and when I try the following designer it works just fine.
<sap:ActivityDesigner x:Class="WorkflowConsoleApplication2.MyActivityDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation">
<sap:ActivityDesigner.Resources>
<sapc:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />
</sap:ActivityDesigner.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Label Content="Subject"
Grid.Row="2"
Grid.Column="0"/>
<sapv:ExpressionTextBox Grid.Column="1"
Grid.Row="2"
Height="Auto"
HorizontalAlignment="Right"
Margin="4, 4, 4, 4"
Expression="{Binding Path=ModelItem.Subject, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
ExpressionType="{x:Type TypeName=sys:String}"
OwnerActivity="{Binding Path=ModelItem}"
VerticalAlignment="Center"
MaxWidth="176"
MinWidth="175" />
</Grid>
</sap:ActivityDesigner>
So I suspect the problem is possibly in your grid definition.
Is it possible to set the width of a column for Grid within Silverlight? I have a grid (not a grid view) with two columns. ColumnA and ColumnB. What I am trying to accomplish is when a user clicks on a button within ColumnA the width of ColumnA is set to .01. ColumnB should then expand the entire width of the grid to fill the remaining area. Similar to how you pin or un-pin a dock panel?
Is this the best approach or should I revert back to a dockpanel and let SL handle it? I'd prefer to manage it myself vs. using a RAD control as I think it is a little bloated for such a small and seemingly simple task.
Another thought I had was to use a gridsplitter but I was unsure as to how to programmatically collapse or expand the column using the gridsplitter? Hence my current predicament. Any suggestions would be greatly appreciated.
Thanks in advance
Give your ColumnDefinition a name via the Name attribute, e.g.:
<ColumnDefinition Width="100" Name="FooColumn"/>
Then you can assign it a new Width in code whenever you want:
FooColumn.Width = new GridLength(1);
(edit: should have used the same name in both places... oops.. you get the idea though)
Try this
<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<sdk:GridSplitter />
</Grid>
LayoutRoot.ColumnDefinitions.First().Width = new GridLength();