I am running into a layout issue which I am not sure how to solve. Here is how my xaml looks like,
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid x:Name="abc" Grid.Row="0" Grid.Column="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0"></Button>
<TextBox Grid.Row="0" Grid.Column="1"></TextBox>
</Grid>
</Grid>
<Grid Grid.Row="0" Grid.Column="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0"></Button>
<TextBox Grid.Row="0" Grid.Column="1"></TextBox>
</Grid>
</Grid>
</Grid>
Now the layout of the above xaml is exactly as what I want. However, I have one additional requirement. At runtime I need to make grid "abc" collapsable. And the other grid needs to fill the entire width. If I use star sizing width then if "abc" is collapsed it behaves more like hidden than collapsed. Collapse seems to work with Auto sized widths but then it doesn't give me propotional sizing as required. Is there a way to accomplish this. Note, I only have access to Grids, StackPanels, and Canvas for layout of my items (no DockPanel). Please let me know of any ideas along with any code snippets. Thanks.
Hard tell your intent in the layout, but here is a sample to get you started.
I changed the ColumnDefintion width from * to Auto in the Click event and set the Visibility to Collasped for "abc" Grid. I used the second button to change these values for test purposes, and I removed an extra level of Grid that is not needed.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnToCollapse" Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid x:Name="abc" Grid.Row="0" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0"></Button>
<TextBox Grid.Row="0" Grid.Column="1"></TextBox>
</Grid>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Click="Button_Click" />
<TextBox Grid.Row="0" Grid.Column="1"></TextBox>
</Grid>
</Grid>
Here is the button click event:
private bool _toggle = true;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (_toggle)
{
ColumnToCollapse.Width = GridLength.Auto;
abc.Visibility = Visibility.Collapsed;
_toggle = false;
}
else
{
ColumnToCollapse.Width = new GridLength(1, GridUnitType.Star);
abc.Visibility = Visibility.Visible;
_toggle = true;
}
}
Had the same problem, only made worse by having a splitter in a middle third column.
Basically I wound up binding the column widths (each of them) to properties that return auto in one mode and star in the other mode. Make sure you implement INotifyPropertyChange for the properties and call the onchange helper for both column property names when you change the flag controlling the layout.
Related
In my Xamarin Forms app I'm trying to place two labels on my mobile interface, one in the bottom left corner, one in the bottom right.
Here is my current attempt. It is a grid layout with one row and two columns, with a label in each cell, the left one with HorizontalTextAlightment="Start" and the right one with HorizontalTextAlightment="End"
...other unrelated controls...
<StackLayout Orientation="Horizontal" Spacing="0" Padding="15" VerticalOptions="End" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding DeviceId}" HorizontalTextAlignment="Start" Grid.Row="0" Grid.Column="0" />
<Label Text="{Binding Version}" HorizontalTextAlignment="End" Grid.Row="0" Grid.Column="1" />
</Grid>
</StackLayout>
</StackLayout>
This produces this unwanted result: (the v1.0-1 should be aligned to the right)
This is what I want:
Try this
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Text="{Binding DeviceId}" HorizontalTextAlignment="Start" Grid.Row="1" Grid.Column="0" />
<Label Text="{Binding Version}" HorizontalTextAlignment="End" Grid.Row="1" Grid.Column="2" />
</Grid>
Why are you wrapping the view in a StackLayout? A Stacklayout will allocate the minimum amount of space required. Which is why you are seeing the behavior you have shown in Screenshot 1.
If you just have:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding DeviceId}" HorizontalTextAlignment="Start" Grid.Row="0" Grid.Column="0" />
<Label Text="{Binding Version}" HorizontalTextAlignment="End" Grid.Row="0" Grid.Column="1" />
</Grid>
You will see the desired behavior.
You could also try using HorizontalOptions on the Label instead of HorizontalTextAlignment
If you really need to use a StackLayout you could try setting the HorizontalOptions of the StackLayout to FillAndExpand. which states:
FillAndExpand – places the view so that it has no padding and takes up
as much space as the layout will give it.
ref: https://developer.xamarin.com/guides/xamarin-forms/user-interface/layouts/stack-layout/#Sizing
Using "*" for width only makes the column as big as it needs to be in order to fit its contents. Instead, try making each column 50% of the total width.
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
I'm hoping someone can make this easy.
I have a grid with 5 columns, columns 1 and 3 contain splitters. What I want to happen is when I move one splitter have the other one move to match such that the effect is the first and last columns being sized together.
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" x:Name="col1"/>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="{Binding ElementName=col1, Path=ActualWidth}" />
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" Background="Red"/>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" Background="Red"/>
</Grid>
Needless to say the above doesn't work. And even if it did it would only allow for using the first splitter not the second. Can anyone shed some light?
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" x:Name="col1"/>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="{Binding ElementName=helperGrid, Path=ActualWidth}" />
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" Background="Red"/>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" Background="Red"/>
<Grid Grid.Column="0" x:Name="helperGrid" Width="{Binding ElementName=helperGrid2, Path=ActualWidth}" MinWidth="100"/>
<Grid Grid.Column="4" x:Name="helperGrid2"/>
</Grid>
This worked for me, I changed the first column's width to auto and used two helper grids in the first and last columns
After much playing around I could get close but not completely what I was looking for. So I ended up placing a Grid in each if the splitter columns instead of GridSplitters and handling the PreviewMouseDown event on the Grid and also the PreviewMouseUp and PreviewMouseMove events of the parent control to implement my own resizing. This was used to detect dragging in columns 1 and 3 and resize colunmns 0 and 3 together. Sadly the code has become rather interwoven with the rest of my control so isn't easy to post. Maybe one day when my xaml improves I'll be able to break the functionality out into a properly reusable control.
I defined the following DialogWindow:
<ui:DialogWindow x:Class="CodeElementRatingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.12.0"
Title="CodeElementRatingWindow" Height="600" Width="800">
<Grid Name="root">
<Grid.RowDefinitions>
<RowDefinition Height="60px"></RowDefinition>
<RowDefinition Height="510px"></RowDefinition>
<RowDefinition Height="30px"></RowDefinition>
</Grid.RowDefinitions>
<Label Grid.ColumnSpan="2" Grid.Row="0" Grid.Column="0" Name="TitleLabel" Content="Please rate the difficulty you perceived while working with each of the following code elements (1 = ''very easy'' / 6 = ''very difficult'')"></Label>
<ScrollViewer MinHeight="510px">
<Grid Grid.ColumnSpan="2" Grid.Row="1" Grid.Column="1" Name="ElementContainer">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
</ScrollViewer>
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="OK" Grid.Column="0" Click="OK_Button_Click"></Button>
<Button Content="Cancel" Grid.Column="1" Click="Cancel_Button_Click"></Button>
</Grid>
</Grid>
</ui:DialogWindow>
The layout basically consists of three rows. The first row has a title label, the bottom row two buttons and in the middle, I want to have a list of UI elements that I add dynamically in the code to the Grid there. Since I don't know in advance how many items that are, I want to display them in a ScrollViewer.
I can see that ScrollViewer is drawn, but the problem is, the ScrollViewer overlaps with the title label and is also somewhat clumsy. When I remove the ScrollViewer, this is not the case. So what am I doing wrong?
Just change the Grid.Row=1 for the ScrollViewer. It will work. Refer below code.
<Grid Name="root">
<Grid.RowDefinitions>
<RowDefinition Height="60px"></RowDefinition>
<RowDefinition Height="510px"></RowDefinition>
<RowDefinition Height="30px"></RowDefinition>
</Grid.RowDefinitions>
<Label Grid.ColumnSpan="2" Grid.Row="0" Grid.Column="0" Name="TitleLabel" Content="Please rate the difficulty you perceived while working with each of the following code elements (1 = ''very easy'' / 6 = ''very difficult'')"></Label>
<ScrollViewer MinHeight="510px" Grid.ColumnSpan="2" Grid.Row="1" Grid.Column="1">
<Grid Name="ElementContainer">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
</ScrollViewer>
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="OK" Grid.Column="0" Click="OK_Button_Click"></Button>
<Button Content="Cancel" Grid.Column="1" Click="Cancel_Button_Click"></Button>
</Grid>
</Grid>
I have a requirement to show 3 panel with GridSplitter as separators in grid in WPF and C#. Also Closing options for each panel.
Plese see image to better understand design:
When user close the left panel , now the middle panel stretch from left , same-thing like right panel also. In run time i'll dock again these panels.
I'm tried to hidden/collapsed Closed panel and closed panel related splitterm but no luck.
Any suggestions or ideas would be most welcome?
Edited
I required 5 column definitions including splitters (3 panels and 2 splitters). Design code is
<Grid Margin="0,120,0,20" Name="panelGrid">
<!--
1)Browser
2)Player
3)Chat
-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel Name="webBrowserPanel" Grid.Column="0"
Visibility="Visible" Background="Green" Height="auto">
<Button HorizontalAlignment="Center" Width="20"
Height="20" Click="leftBut"></Button>
</DockPanel>
<GridSplitter Name="sp1" Grid.Column="1" HorizontalAlignment="Center"
VerticalAlignment="Stretch" Background="Red"
ShowsPreview="True" Width="5"/>
<Grid x:Name="grid1" Grid.Column="2" AllowDrop="True"
Background="#FF807272"/>
<GridSplitter Name="sp2" Grid.Column="3" HorizontalAlignment="Center"
VerticalAlignment="Stretch" Background="Red"
ShowsPreview="True" Width="5"/>
<Grid x:Name="chatGrid" Grid.Column="4" Visibility="Visible"
Background="DarkOrange" >
<Button HorizontalAlignment="Center" Width="45" Height="20"
Click="righCli">
</Button>
</Grid>
</Grid>
Is this what you mean?
<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" x:Name="leftColumn"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*" x:Name="rightColumn"/>
</Grid.ColumnDefinitions>
<!-- u can also use DockPanel within a grid -->
<DockPanel>
<!-- this border is under the splitter and can't be seen-->
<Border Background="Red" DockPanel.Dock="Right" Width="5"/>
<Border Background="#AA0">
<Button VerticalAlignment="Top" Click="Button_Click_1" Content="x"/>
</Border>
</DockPanel>
<Border Background="#0AA" Grid.Column="1">
<Button VerticalAlignment="Top" Click="Button_Click_2" Content="reset"/>
</Border>
<!-- u can also use grid within a grid -->
<Grid Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- this is also an extra column for splitter -->
<Border Background="Red" Grid.Column="0"/>
<Border Background="#A0A" Grid.Column="1">
<Button VerticalAlignment="Top" Click="Button_Click_3" Content="x"/>
</Border>
</Grid>
<GridSplitter Grid.Column="0" Width="5" x:Name="leftSplitter"/>
<!-- by setting the correct margin you hide the underlying red border -->
<GridSplitter Grid.Column="1" Width="5" x:Name="rightSplitter" Margin="0,0,-5,0"/>
</Grid>
code behind:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
leftColumn.Width = new GridLength(0);
leftSplitter.Visibility = System.Windows.Visibility.Collapsed;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
leftColumn.Width = new GridLength(40);
rightColumn.Width = new GridLength(40);
leftSplitter.Visibility = System.Windows.Visibility.Visible;
rightSplitter.Visibility = System.Windows.Visibility.Visible;
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
rightColumn.Width = new GridLength(0);
rightSplitter.Visibility = System.Windows.Visibility.Collapsed;
}
it can improved using converters to bind splitters visibilities and columndefinitions widths to a property in view model.
I'm trying to have a stackpanel of radio buttons on the left, a button on the right, both of fixed width, and a text box between them that stretches to fill the space as the window is resized.
This is what seems like should work:
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel HorizontalAlignment="Left">
<RadioButton GroupName="FibOptions" IsChecked="True">Term Closest To N:</RadioButton>
<RadioButton GroupName="FibOptions">Nth Term:</RadioButton>
</StackPanel>
<TextBox x:Name="FibInput" Grid.Column="1" />
<Button Grid.Column="2" x:Name="FibGen" HorizontalAlignment="Right">Generate</Button>
</Grid>
But the above results in a tiny text box that's basically a vertical line right in the middle of the area. Any help with this?
Set the column width to *, which tells it to fill the remaining space, and set the other two to auto:
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />