I am trying to layout some rectangles in an AbsoluteLayout using a ViewModel to set LayoutBounds:
<AbsoluteLayout x:Name="outerLayout" Grid.Row="1" Grid.Column="1"
VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" Margin="0,0,10,10" >
<RefreshView x:DataType="vm:MyViewModel" Command="{Binding ProjectEditor.LoadItemsCommand}" IsRefreshing="{Binding ProjectEditor.IsBusy, Mode=TwoWay}">
<CollectionView x:Name="ItemsListView"
ItemsSource="{Binding Items}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame x:DataType="model:LayoutItem"
AbsoluteLayout.LayoutBounds="{Binding Rect, Mode=OneWay}" AbsoluteLayout.LayoutFlags="All"
BackgroundColor="LightSalmon" >
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="Test_Clicked" />
</Frame.GestureRecognizers>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
</AbsoluteLayout>
outerLayout
is located in a Grid that has an X-axis in Grid.Row="0" Grid.Column="1" and an Y-Axis in Grid.Row="1" Grid.Column="0".
Frame theBorder
is layed out correctly but not the frames in the CollectionView:
They have the appropriate width but heights are too small and identical for all Frame objects.
For test purposes I defined a TapGestureRecognizer to check the Frame's properties in the debugger:
Frame frm = sender as Frame;
var x = frm.AnchorX;
var y = frm.AnchorY;
var h = frm.Height;
var w = frm.Width;
var bounds = AbsoluteLayout.GetLayoutBounds(frm);
bounds
has the values I returned in Rect
through the DataModel but h
and w
are too small.
What is wrong?
Edit:
I applied the changes suggested by ToolmakerSteve.
HeightRequest seems to work. However, AnchorX, AnchorY and WidthRequest have no effect. The Frame is always drawn to the end of the Parent View:
<Frame x:DataType="model:LayoutItem"
AnchorX="{Binding Rect.X}" AnchorY="{Binding Rect.Y}"
HeightRequest="{Binding Rect.Height}" WidthRequest="{Binding Rect.Width}"
BackgroundColor="LightSalmon" BorderColor="Black" HorizontalOptions="StartAndExpand" >
Edit:
I removed the first <Frame />
because it is confusing and not necessary to understand my intention.
What I want is to layout a pattern of rectangles whose coordinates are given by ItemsSource
. Can anybody give me some hints how to proceed?
Perhaps the best approach is to implement a CollectionView
custom renderer.
(My activity here is my hobby, not my job. I am still learning about Xamarin MVVM Patterns, so it will last some time until I can show you my solution here.)
AbsoluteLayout.LayoutBounds
has no effect except on direct chidren of the AbsoluteLayout.
The two children here are the Frame and the RefreshView.
Cannot apply it to nested elements.
Inside DataTemplate, bind that inner Frame's HeightRequest and WidthRequest.
Also set CollectionView's ItemSizingStrategy="MeasureAllItems"
.
Positioning items of a CollectionView
You can't. The CollectionView controls their position.
By default, they are in a vertical list.
Similarly, the Width is the width of the CollectionView itself.
If child is appearing at end of area, instead of start, see https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/layout-options.
Specifically VerticalOptions="Start"
. Set that on the collectionview itself.
Use BindableLayout with AbsoluteLayout
A similar question now exists.
See Jason's comment with link to BindableLayout.
You would use AbsoluteLayout as the Layout. Read there for more details.
A c# approach
If you need to independently control the positions of items, they can't be part of a CollectionView (or any similar group, such as ListView).
Could create the elements in c# code, and add them to the AbsoluteLayout:
// Loop over your data.
foreach (.. item in ...)
{
var element = new BoxView(...);
AbsoluteLayout.SetLayoutBounds(element, ...);
outerLayout.Children.Add(element);
}
Look up docs for BoxView
and AbsoluteLayout SetLayoutBounds
, to see the parameters.
NOTE: I've used BoxView instead of Frame. Test with that first. Frame won't work well until it has some element inside of it. You could test with a Frame containing a BoxView.