Why is the circle getting cut off? - xaml

Steps:
Make a brand new "Blank App (Universal Windows)"
Set Target and Minimum Version: "Windows 10 Creators Update (10.0; Build 15063)"
Add the code below to MainPage.xaml and run the app.
MainPage.xaml
<Grid Width="128" Height="120">
<Grid.RowDefinitions>
<RowDefinition Height="120" />
<RowDefinition Height="1" x:Name="ChangeHeightRow" />
</Grid.RowDefinitions>
<Grid>
<Canvas Background="Red">
<Ellipse Width="140" Height="140" Fill="Green" />
</Canvas>
</Grid>
</Grid>
Should see this:
Why is the green circle getting cut off? Further to that, if you set ChangeHeightRow.Height to 0, it looks like this:
What is going on? I would expect the circle to never be cut off...maybe I'm wrong?

TL;DR: You are clipping of the Ellipse by having an empty row of 1 pixel in your Grid.
The problem is on multiple levels. Your outer Grid has a Width and Height set. Next your RowDefinition has a Height set and your Ellipse is of a bigger size than both heights.
<Grid Width="128" Height="120">
<Grid.RowDefinitions>
<RowDefinition Height="120" />
<RowDefinition Height="1" x:Name="ChangeHeightRow" />
</Grid.RowDefinitions>
<Grid>
<Canvas Background="Red">
<Ellipse Width="140" Height="140" Fill="Green" />
</Canvas>
</Grid>
</Grid>
By setting these sizes, you are allowing other controls to come closer to the inner controls than they would if you would use Auto as sizing for the rows and nothing (=auto) as Grid size.
In your initial code, you have a Grid row with the Ellipse and an empty row of 1 pixel high. By default XAML controls have a Z-axis with items declared at the bottom of your XAML file being the topmost control in the visual layers. So for your Grid, your second row is on top of your first row in case of overlap. Since the Ellipse leaks outside of the row, the second row is drawn over it and clips your Ellipse.
By setting the height to 0, the second row is no longer drawn and can't clip your control.
To make this more clear, I have tweaked your XAML a bit, adding another StackPanel outside your grid and adding a Button. As you can see, the Button is drawn on top of the Ellipse, as it's defined below in XAML and thus getting a higher visual layer on the Z-axis.
<StackPanel Width="130">
<Grid Width="128" Height="120">
<Grid.RowDefinitions>
<RowDefinition Height="120" />
<RowDefinition Height="0" x:Name="ChangeHeightRow" />
</Grid.RowDefinitions>
<Grid>
<Canvas Background="Red">
<Ellipse Width="140" Height="140" Fill="Green" />
</Canvas>
</Grid>
</Grid>
<Button Background="Black" Foreground="White">Test</Button>
</StackPanel>
If we change the StackPanel to a Grid, we have the same behavior. However moving the Button to the top in the XAML declaration (and keeping Grid.Row on 1 so it's below the Ellipse), you'll notice that it's now behind the Ellipse because of the Z-layers ordered differently.
<Grid Width="130">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Background="Black" Foreground="White" Grid.Row="1">Test</Button>
<Grid Width="128" Height="120" Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="120" />
<RowDefinition Height="0" x:Name="ChangeHeightRow" />
</Grid.RowDefinitions>
<Grid>
<Canvas Background="Red">
<Ellipse Width="140" Height="140" Fill="Green" />
</Canvas>
</Grid>
</Grid>
</Grid>

Related

Xamarin.Forms: Tiny icons are getting cut ever so slightly when size is set with grid value

this is a simple grid with a tiny button in it:
<!--ReverseButton-->
<Grid Grid.Row="1" RowSpacing="0" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<ImageButton
Source="btn_reversed_unpressed"
x:Name="btn_reverse_list_mainmenu"
BackgroundColor="#00000000"
Grid.Column="1"
Clicked="ReverseListForSwipeView"
/>
</Grid>
The size of this Row (row 1) is set here:
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="0.17*" />
<RowDefinition Height="4.5*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
I set the value to 0.17* to have the button always be very tiny. If i would set the row to "auto" the icon would become much bigger (since the source image is bigger in size)
If I make the size to, lets say 0.25* instead of 0.17* the row and therefore the button both get bigger and everything is fine. (Except now it is too big)
But with size 0.17* it is just about right... Well except for this:
It is quite hard to see, but the icon at the bottom is cut of slightly. The border is not as big as it is on the top.
This I have noticed quite some time now.
I tried setting the rowspacing to 0 or even negative values, but nothing worked.
Why is the icon cut off.
The top part isnt cut and both parts (top and bottom) touch the row end and beginning pixel perfect.
An answer based on my comment above. I suggest setting the HeightRequest of the ImageButton to the size you want the icon to be and then just set the row height to Auto and let the layout manager do the rest. See my example where I create a Grid with 3 rows set to Auto size and then just use the HeightRequest property to have it draw at the correct size. I left the grey background of the button in so you can see how the row sizes dynamically.
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ImageButton Source="ic_email_dark"
Aspect="AspectFit"
HeightRequest="50"
HorizontalOptions="Fill"
VerticalOptions="Center"
Grid.Row="0" />
<ImageButton Source="ic_email_dark"
Aspect="AspectFit"
HeightRequest="75"
HorizontalOptions="Fill"
VerticalOptions="Center"
Grid.Row="1" />
<ImageButton Source="ic_email_dark"
Aspect="AspectFit"
HeightRequest="100"
HorizontalOptions="Fill"
VerticalOptions="Center"
Grid.Row="2" />
</Grid>
</ContentPage.Content>
Gives the following:

ListView gets not scrollable

I have a proble which seems pretty common and has been asked alot, but I can't find a fixing solution for my problem.
So I try to use 3 listviews in in one page all shall have a title and an explaining image, but instead of designing all 3 ListViews in one page I outsourced one listview with image and title into a control, which I use in my page.
The 3 Controls are placed in a grid. When the listview items get filled thy scrollbar should become visible if the remaining space is no longer enough but it won't show.
I provided a sandbox project where I placed the control and etc. like in the application I'm working on. SampleProject
Their you just need to press start and the listviews get filled. But they don't show the scrollbar.
Thanks in advance!
Edit 1:
As requested I share my code below. If you open up the sample project then you do not need to read further until a second edit is done.
Control containing listview:
<Grid>
<Grid x:Name="Section"
HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="grdTitleArea"
HorizontalAlignment="Stretch"
Height="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<BitmapIcon
VerticalAlignment="Center"
HorizontalAlignment="Center"
Tapped="grdTitleArea_Tapped"
UriSource="ms-appx:///Assets/area.png"
Height="40" />
<TextBlock
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Tapped="grdTitleArea_Tapped"
Text="Area"
Grid.Column="1" />
</Grid>
<!--<ScrollViewer
VerticalAlignment="Stretch"
VerticalScrollBarVisibility="Auto"
VerticalScrollMode="Enabled"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
HorizontalScrollBarVisibility="Hidden"
HorizontalScrollMode="Disabled"
>-->
<ListView x:Name="ListView"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Auto"
Grid.Row="1">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
BorderThickness="1"
Margin="1"
Height="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding ActionDescription}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!--</ScrollViewer>-->
</Grid>
</Grid>
Control which contains the control above 3 times:
<Grid x:Name="ProgressControl">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:SynchronizeSettingsControl
Visibility="Visible"
x:Name="Settings" />
<local:SynchronizeSectionControl
x:Name="ActualAction"
Visibility="Visible"
Grid.Row="1" />
<local:SynchronizeSectionControl
x:Name="Error"
Visibility="Visible"
Grid.Row="2" />
<local:SynchronizeSectionControl
x:Name="Log"
Visibility="Visible"
Grid.Row="3" />
</Grid>
Page which contains the control which contains the listview:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1"
Text="Demo"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Width="70"
VerticalAlignment="Stretch"
Content="Useless Button" />
</Grid>
<Controls:SynchronizeControl
x:Name="ctlSync"
Grid.Row="2"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" />
<Button VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
x:Name="btnStart"
Content="Start"
Tapped="btnStart_Tapped"
Grid.Row="3" />
</Grid>
The problem is you used Auto height in the page. This means basically that the page tells the local:SynchronizeSectionControl control: "You can use whichever height you want".
The control then has * as the height of the second row which means "use the rest space available". But because the page offered essentially "infinite height", the ListView height will stretch as much as possible to accommodate for all its items and hence it doesn't scroll, as its height is big enough to display everything, although it is cut off and not visible, because the window height is of course limited.
The thing is you used the Auto property for the height of your rows in your control.
This works fine is the control you use uses a definite space. Like a button or similar stuff. But when the control can extend indefinitely the allocation for the space gets screwed up.
Basically the control displays at its maximum size but extends way over its boundaries.
You can prevent that when you use the * as a Height value.
This will lead to the control taking up all the space available. You can further limit this with using the MaxHeight property.
If you do it that way it will display a scrollviewer when necessary and it will even resize when you change the window size.

Dynamically expanding Grid also expands fixed height Rows and Columns

I have a dynamically expanding Grid inside another Grid which is separated onto 4 rows and 4 columns.
My main content grid spans 4 rows and 2 columns and dynamically loads different Views, and sometimes expands in height. My problem is, the other rows are also expanded although they have a fixed height, which makes the layout appear weird.
I want to keep all the rows' heights to 36, but just expand the lowest row so all content of my grid is shown.
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="45" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="110" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="36" />
<RowDefinition Height="36" />
<RowDefinition Height="36" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
FontSize="14"
Content="X">
</Button>
<Grid x:Name="MainPaymentContentRoot"
Grid.Row="0"
Grid.RowSpan="4"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="20,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollMode="Auto">
</Grid>
<TextBlock Text="MyField" Grid.Row="0" Grid.Column="3" Margin="10,0,0,0" VerticalAlignment="Center" />
<Button Grid.Row="1" Grid.Column="3" Margin="10,0,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Right"
Content="AnotherButton">
</Button>
</Grid>
This is for a Win 8 Development.
Currently, your RowDefinition is set to Auto. This means that the row will calculate the content size, and adjust it's height accordingly.
You need to change it to Height="*".
<RowDefinition Height="*" />
This will force the RowDefinition to expand to the height of the parent. In other words, it will take up all available space.

Issue with XAML layout

I've got the following XAML:-
<Grid Width="400" Height="400">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Heading" />
<ListBox Grid.Row="1" ItemsSource="{Binding Foo}"
Margin="0,12,0,12" />
<Button Grid.Row="2" Content="Button"
VerticalAlignment="Top" HorizontalAlignment="Left" />
</Grid>
This simply displays a heading, a listbox, and a button immediately below the listbox. As the number of items in the listbox grows, the button gets pushed down, however the listbox will keep growing and eventually disappear off the bottom of the window, taking the button with it.
Instead, I would like the listbox to grow until the button hits the bottom of the window. At this point the listbox shouldn't grow any further, and instead display scrollbars to scroll the list. What am I missing?
Edit:
I've just come up with the following, which seems to do the trick. Not sure if there is a more elegant solution though?
<Grid Width="400" Height="400">
<Grid.RowDefinitions >
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Heading" />
<DockPanel Grid.Row="1" LastChildFill="True" VerticalAlignment="Top">
<Button DockPanel.Dock="Bottom" Content="Button"
VerticalAlignment="Top" HorizontalAlignment="Left" />
<ScrollViewer VerticalScrollBarVisibility="Auto" Margin="0,12,0,12">
<ListBox ItemsSource="{Binding Foo}" />
</ScrollViewer>
</DockPanel>
</Grid>
You need to limit the height of the grid row containing your ListBox to some fixed height to stop it taking up whatever vertical height it likes. I'm away from an IDE to test but you may also need to set the VerticalScrollBarVisibility on the ListBox to Auto.
<Grid Width="400" Height="400">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="200"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Heading" />
<ListBox Grid.Row="1" ItemsSource="{Binding Foo}"
Margin="0,12,0,12" />
<Button Grid.Row="2" Content="Button"
VerticalAlignment="Top" HorizontalAlignment="Left" />
</Grid>

ScrollViewer not to scroll when content does not exceed parent's height

In this XAML I can scroll Contents grid up and down a bit even though it does not exceed the ScrollViewer height.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid x:Name="Controller" Grid.Row="0">
<controls:SearchField x:Name="Searcher" />
</Grid>
<ScrollViewer x:Name="Scroller" Grid.Row="1">
<ScrollViewer.Content>
<Grid x:Name="Contents">
<TextBlock Text="HI" />
</Grid>
</ScrollViewer.Content>
</ScrollViewer>
</Grid>
I guess it is a standard behavior of some kind but I don't like it too much. It it possible to make ScrollViewer not to scroll it's contents if they don't exceed ScrollViewer's height?