-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make UniformGrid
account for layout rounding.
#17700
Conversation
When layout rounding is available, children may be laid out with a slightly different position/size than requested. Layout each each child with it's top-left aligned against the previous column/row bounds and request the bottom-right to be placed in the ideal position.
You can test this PR using the following package version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we can use the bounds from the children at all. The UniformGrid
should constrain its children, not the reverse.
An alternative fix might be to simply apply the layout rounding to the cell size. Conceptually, it's not really different from having a panel for each cell, which should work "naturally".
// requested. Layout each each child with it's top-left aligned against the | ||
// previous column/row bounds and request the bottom-right to be placed in | ||
// the ideal position. | ||
var topLeft = new Point(x, y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't rely on the previous child's bounds here: it might effectively be completely different (try any child with non-stretch alignment) from the cell's size, breaking the uniformity.
Example:
<UniformGrid Columns="2">
<Border Width="100" Height="100" Background="Blue" />
<Border Width="100" Height="100" Background="Gray" />
<Border Width="50" Height="100" Background="Blue" HorizontalAlignment="Left" />
<Border Width="50" Height="100" Background="Gray" HorizontalAlignment="Left" />
</UniformGrid>
It might even be out of bounds of the UniformGrid
(if the children are larger than their container), causing an invalid rectangle to be passed to Arrange
, and an InvalidOperationException
.
Example:
<UniformGrid Width="50" Height="50">
<Border Width="100" Height="100" />
<Border Width="100" Height="100" />
</UniformGrid>
My first attempt started out doing this, but I was finding that you wound up in situations where the children didn't fill the panel completely, or went outside the panel bounds. However thinking more about it, it might because i was using
Good catch! Yes I should have thought of this ;) We need more unit tests for this control obviously. |
One thing we need to decide: when snapping to pixels, there are situations where we have to choose between having the children not completely fill the panel, or having the child sizes not be completely uniform. Need to confirm what WPF does (from looking at the code, I think it will sacrifice uniformity but need to check this in practise). |
I think we should keep Imagine that instead of having a In that case, the cells would naturally "compose" without overlap, because they're already using With code, I expect the following two panels to have the exact same layout at any DPI size: <StackPanel Orientation="Horizontal" Width="99" Height="100" Background="Black">
<Border Width="33" Background="Red" />
<Border Width="33" Background="Green" />
<Border Width="33" Background="Blue" />
</StackPanel>
<UniformGrid Width="99" Height="100" Columns="3" Background="Black">
<Border Background="Red" />
<Border Background="Green" />
<Border Background="Blue" />
</UniformGrid> That won't work if we apply a different algorithm just for |
I tested your two examples on WPF with 125% scaling, modifying the code to make the panel width 100 (i.e. not divisible by 3) and to also make clear the child bounds in relation to the parent: <Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800"
UseLayoutRounding="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="Beige" Padding="0 4" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel x:Name="stack" Orientation="Horizontal" Width="100" Height="100">
<Border Width="33" BorderBrush="Red" BorderThickness="1"/>
<Border Width="33" BorderBrush="Green" BorderThickness="1"/>
<Border Width="33" BorderBrush="Blue" BorderThickness="1"/>
</StackPanel>
</Border>
<Border Background="Beige" Padding="0 4" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">
<UniformGrid Name="uniform" Width="100" Height="100" Columns="3">
<Border BorderBrush="Red" BorderThickness="1"/>
<Border BorderBrush="Green" BorderThickness="1"/>
<Border BorderBrush="Blue" BorderThickness="1"/>
</UniformGrid>
</Border>
</Grid>
</Window> We get the following results StackPanel 0,0,32.8,100 UniformGrid 0,0,33.6,100 And look what happens. The |
The docs for the WinUI UniformGrid say (highlighting added):
So the two constraints for its behavior is that
Obviously, these two requirements are in conflict when the pixel size of the panel is not divisible by the number of children. In this case there are two possible ways out of the conundrum:
When So I'm tempted to say that the control is working as intended and this PR should be closed. |
Closing as the current behavior matches WPF. |
What does the pull request do?
As described in #17699,
UniformGrid
was ported from WPF but Avalonia's layout rounding is slightly different. UpdateArrangeOverride
to account for this.Instead of arranging each child without considering whether it was snapped to the pixel grid, layout each each child with it's top-left aligned against the previous column/row, with the bottom-right placed in the ideal position. This ensures that there are no overlapping/spaces between controls, and also ensures that the overall uniform grid is preserved.
Fixed issues
Fixes #17699