I have a pretty simple requirement that I can't seem to find a solution for. Take a look at my sample XAML code:
<Grid ShowGridLines="True" VerticalAlignment="Top" Margin="5">
<Grid.RowDefinitions>
<RowDefinition MinHeight="100"/>
<RowDefinition MinHeight="100"/>
<RowDefinition MinHeight="100"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="GridSplitter">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Height" Value="1"/>
<Setter Property="Background" Value="Black"/>
</Style>
</Grid.Resources>
<GridSplitter/>
<GridSplitter Grid.Row="1"/>
<GridSplitter Grid.Row="2"/>
</Grid>
I have three rows that start out with a height of 100. I want the user to be able to drag the edge of any row to make it taller, so I put a GridSplitter in every row.
The problem is:
The GridSplitter control redistributes space between rows or columns
in a Grid, without changing the dimensions of the Grid. For example,
when a GridSplitter resizes two columns, the ActualWidth property of
one column is increased while at the same time the ActualWidth
property of the other column is decreased by the same amount.
The above XAML doesn't work, none of the rows change size when dragged, because the GridSplitter is trying to take height from another row and add it to the one being resized. Since none of the rows can get any smaller (MinHeight="100"), nothing happens.
But I don't want to take height from the other rows. I want to increase the size of one row independently, which will in turn change the overall height of the Grid. If I drag the middle row to be 50px taller, I want to have that row be 150px while the other two remain 100px, making the overall grid 350px.
Is there any setting on the GridSplitter I'm missing that will allow this? Or is there some other control I can use?
Is this what you're expecting?
<StackPanel>
<TextBlock Text="{Binding ActualHeight,
ElementName=grid,
StringFormat='Grid Actual Height: {0}'}" FontSize="30"/>
<Grid x:Name="grid" Background="Aqua">
<Grid.Resources>
<Style TargetType="GridSplitter">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Height" Value="5"/>
<Setter Property="ShowsPreview" Value="False"/>
<Setter Property="Background" Value="Black"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Text"
Value="{Binding ActualHeight,
RelativeSource={RelativeSource AncestorType=StackPanel},
StringFormat='Row Actual Height: {0}'}"/>
<Setter Property="FontSize" Value="30"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition MinHeight="100" Height="100" />
<RowDefinition Height="Auto" />
<RowDefinition MinHeight="100" Height="100" />
<RowDefinition Height="Auto" />
<RowDefinition MinHeight="100" Height="100" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Background="Tan">
<TextBlock />
</StackPanel>
<GridSplitter Grid.Row="1"/>
<StackPanel Grid.Row="2" Background="Brown">
<TextBlock />
</StackPanel>
<GridSplitter Grid.Row="3"/>
<StackPanel Grid.Row="4" Background="Bisque">
<TextBlock />
</StackPanel>
<GridSplitter Grid.Row="5" ResizeBehavior="PreviousAndCurrent"/>
</Grid>
</StackPanel>
The problem is with the way you're adding GridSplitter to your Grid control. You can get more detail on how this works at GridSplitter documentation. This also includes how to use ResizeBehavior; which i'd used to get it working for last row
Related
I need to show ListBox with dynamic content (so I do not know its height) and Button below it. So user should be able to scroll ListBox to end and see button.
In Android I would use RelativeLayout and below property for button or some other solution, but in WP I do not know how to do it.
What I had tryed:
1) Put all in StackPanel
<StackPanel>
<ListBox />
<Button />
</StackPanel>
This is not working, because StackPanel is blocking ListBox scrolling.
2) Ok, lets put ListBox in Grid
<StackPanel>
<Grid>
<ListBox />
</Grid>
<Button />
</StackPanel>
Nothing happens.
3) Put all in Grid and use Grid.Row not worked.
4) Lets put all in Grid and set margin for Button dynamically
<Grid>
<ListBox />
<Button />
</Grid>
Ok, this is working, but it is not good solution , because I need to handle ListBoxpopulating each time and reset margin for button. Bad bad bad.
P.S. Also, I can put button as ListBox item (not bad, but not good :)
Help me please...
If I understood you correctly, you need a simple Grid defined like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox />
<Button Grid.Row="1" Height="80"/>
</Grid>
By making height of the row zero to "star" and the first row to Auto, the ListBox will fill the remaining space, and the Button only 80 (you can change this to whatever you like). ListBox is automatically put to row zero because that's the default if it is not explicitly set.
If you don't want the button fixed on the page but to scroll with the ListBox, you could edit the ListBox template like this:
<Style x:Key="ListBoxWithButtonStyle" TargetType="ListBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer x:Name="ScrollViewer" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" Padding="{TemplateBinding Padding}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ItemsPresenter/>
<Button Content="Touch me" Height="80" Grid.Row="1"/>
</Grid>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then apply to ListBox:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Style="{StaticResource ListBoxWithButtonStyle}">
</ListBox>
</Grid>
I'm trying to build a simple 3x3 grid in Silverlight with a button in each grid cell. The grid definition is below. When I add button to the grid they never fill the 130x130 grid cell. I set the margin and padding to 0 on the buttons as well as setting their horizontal and vertical alignment to Stretch.
<Grid x:Name="Test" ShowGridLines="True" HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130"></ColumnDefinition>
<ColumnDefinition Width="130"></ColumnDefinition>
<ColumnDefinition Width="130"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Style x:Key="OperandButton" TargetType="Button">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="{StaticResource PhoneAccentColor}" />
<Setter Property="FontSize" Value="50" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style>
<Button Content="10" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="0" />
<Button Content="3" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="1" />
<Button Content="7" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="2" />
Your code should just work fine. Just try this code as it is.
<Grid x:Name="Test" ShowGridLines="True" HorizontalAlignment="Center" >
<Grid.Resources>
<Style x:Key="OperandButton" TargetType="Button">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="Blue" />
<Setter Property="FontSize" Value="50" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="130"></ColumnDefinition>
<ColumnDefinition Width="130"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="10" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="0" />
<Button Content="3" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="1" />
<Button Content="7" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="2" />
</Grid>
Let me know if you still not getting it.
Try the following,
When you open your project in Blend. Right click the button, go to edit template, edit current. You'l find that every button has a grid and a container. Make the size of both equal then, you'l see the default border's size same as the buttons size.
The same template can be used for other buttons too.
Now try enveloping the buttons in the grid.
Looking at the template in blend solved the problem. The following property was set on the Border:
Margin="{StaticResource PhoneTouchTargetOverhang}"
Once this was set to 0, the grid was perfect. Thanks for the guidance.
Try this, it's must not specified VerticalAlignment Or HorizontalAlignment.
Margin="-10"
I would like to put two controls in WPF in a Grid - GridView and ScheduleView one above the other with GridSplitter like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<telerik:RadScheduleView Grid.Row="0" />
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" Height="4"/>
<telerik:RadGridView Grid.Row="2"/>
</Grid>
The problem is that there are three modes:
- only GridView is shown
- only ScheduleView is shown
- GridView and ScheduleView are shown
In each case I want the visible control(s) to fill all available space. In case the two are shown I want them to share the space between them and GridSplitter should be able to resize that space.
How can I accomplish this without explicitly setting heights while changing display modes?
I would suggest doing something like a MathConverter to explicitly set your Grid's heights based on some triggers
For example, if both Grids are visible, set their height to to be ((GridHeight - 4) / 2), while if only one grid is visible then set it to the Grid's full height since neither the GridSplitter nor the other Grid are visible.
Here's an example. I left out the visibility triggers since I'm assuming you already know how to implement them.
<Grid x:Name="ParentGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<telerik:RadScheduleView x:Name="MyGridView" Grid.Row="0">
<telerik:RadScheduleView.Style>
<Style TargetType="telerik:RadScheduleView">
<Setter Property="Height"
Value="{Binding ElementName=ParentGrid,
Path=ActualHeight,
Converter={StaticResource MathConverter},
ConverterParameter=((#VALUE-4)/2)}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyScheduleView, Path=IsVisible}" Value="False">
<Setter Property="Height" Value="{Binding ElementName=ParentGrid, Path=ActualHeight}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadScheduleView.Style>
</telerik:RadScheduleView>
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" Height="4"/>
<telerik:RadGridView x:Name="MyScheduleView" Grid.Row="2"
<telerik:RadScheduleView.Style>
<Style TargetType="telerik:RadScheduleView">
<Setter Property="Height"
Value="{Binding ElementName=ParentGrid,
Path=ActualHeight,
Converter={StaticResource MathConverter},
ConverterParameter=((#VALUE-4)/2)}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyGridView, Path=IsVisible}" Value="False">
<Setter Property="Height" Value="{Binding ElementName=ParentGrid, Path=ActualHeight}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadScheduleView.Style>
</telerik:RadScheduleView>
</Grid>
Simply give the height of two rows as * which means it will fill all the available space.
And bind the GridSplitter with the visibility of two columns using Triggers or Converter whichever you feel comfortable with. With trigger this would work-
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="4" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<telerik:RadScheduleView Grid.Row="0" />
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch">
<GridSplitter.Style>
<Style TargetType="GridSplitter">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=btn1, Path=IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=btn2, Path=IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</GridSplitter.Style>
</GridSplitter>
<telerik:RadGridView Grid.Row="2"/>
</Grid>
I am assuming that Visibility for your GridView's are already in place (the logic of how to play with the visibility). Make sure you set the Visibility to Collapsed instead of Hidden for your GridViews.
I have something like this:
<MyView>
<Style TargetType="Border" x:Key="Module">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="Padding" Value="10" />
<Setter Property="Margin" Value="10" />
</Style>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Name="Border1" Style="{StaticResource Module}">
<!--some controls with non-fixed width-->
</Border>
<Border Grid.Row="1" Name="Border2" Style="{StaticResource Module}">
<!--some controls with non-fixed width-->
</Border>
<Border Grid.Column="1" Grid.RowSpan="2" Style="{StaticResource Module}" Name="Border3">
<!--some controls with non-fixed width-->
</Border>
</Grid>
</MyView>
The controls inside Border1 and Border2 might have different width, so their borders will also have different width, which doesn't look good. How do I force Border1 and Border2 border to have same width so it would look better?
The solution of setting same width manually doesn't count because the width of child controls of Border1 and Border2 may vary.
And the content of Border3 just eats up all available space, and this is fine.
Add <Setter Property="HorizontalAlignment" Value="Stretch" /> to your Border Style
I have two expanders in one grid row but in distinct columns. How can I expand each of it to the full row but not on column only.
<Grid x:Name="mainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition MinHeight="40" />
<RowDefinition MinHeight="40" />
</Grid.RowDefinitions>
<Controls:Expander Grid.Row="0" Grid.Column="0" x:Name="expander2" Header="Header1"
MinHeight="33" Padding="3">
<TextBlock Text="SomeText1" />
</Controls:Expander>
<Controls:Expander Grid.Row="0" Grid.Column="1" x:Name="expander1" Header="Header2"
MinHeight="33" Padding="3">
<TextBlock Text="SomeText2" />
</Controls:Expander>
</Grid>
expander1 and expander2 should expand to the whole row 0.
Introduce the triggers for Expanders that check their IsExpanded property and set their Grid.RowSpan as 2.
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter Property="Grid.RowSpan" Value="2" />
</Trigger>
</Style.Triggers>
</Style>
For silverlight
<Style TargetType="{x:Type Expander}">
<Setter Property="Grid.RowSpan"
Value="{Binding IsExpanded,
RelativeSource={RelativeSource
Self},
Converter={StaticResource
local:ExpansionToRowSpanConverter}}"
</Style>
Code behind ... (this is just for illustration)
ExpansionToRowSpanConverter.Convert(....)
{
return (bool)value ? 2 : 1;
}
Does this work for you?