英文:
Binding AbsoluteLayout.LayoutBounds in Xamarin.Forms
问题
我正在尝试使用ViewModel设置LayoutBounds在AbsoluteLayout中布局一些矩形:
<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
位于一个Grid中,该Grid在Grid.Row="0" Grid.Column="1"有一个X轴,而在Grid.Row="1" Grid.Column="0"有一个Y轴。
Frame theBorder
被正确布局,但是CollectionView中的Frames没有:
它们具有适当的宽度,但高度对所有Frame对象来说都太小且相同。
为了测试,我定义了一个TapGestureRecognizer来检查调试器中Frame的属性:
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
具有我通过DataModel返回的Rect
的值,但h
和w
太小。
编辑:
我应用了ToolmakerSteve建议的更改。
HeightRequest似乎有效。然而,AnchorX,AnchorY和WidthRequest没有效果。Frame始终绘制到父视图的末尾:
<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" >
编辑:
我移除了第一个<Frame />
因为它令人困惑且不必要来理解我的意图。
我想要的是布局一个由ItemsSource
给出坐标的矩形图案。有人能给我一些建议该如何进行吗?
也许最好的方法是实现一个CollectionView
自定义渲染器。
英文:
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.)
答案1
得分: 1
AbsoluteLayout.LayoutBounds
对AbsoluteLayout
的直接子元素之外的元素没有影响。
这里的两个子元素是Frame
和RefreshView
。
无法应用于嵌套元素。
-
在
DataTemplate
内部,绑定内部Frame
的HeightRequest
和WidthRequest
。 -
还要设置
CollectionView
的ItemSizingStrategy="MeasureAllItems"
。
定位CollectionView
中的项目
你不能。CollectionView
控制它们的位置。
默认情况下,它们以垂直列表的形式排列。
类似地,宽度是CollectionView
本身的宽度。
如果子元素出现在区域的末尾而不是开头,请参阅这里。
具体来说,设置VerticalOptions="Start"
在CollectionView
本身上。
使用BindableLayout与AbsoluteLayout
有一个类似的问题现在存在。
查看Jason的评论,其中包含对BindableLayout
的链接。
您将使用AbsoluteLayout
作为布局。在那里阅读更多详细信息。
C#方法
如果需要独立控制项目的位置,它们不能是CollectionView
(或任何类似的组,如ListView
)的一部分。
可以在C#代码中创建元素,并将它们添加到AbsoluteLayout
中:
// 循环遍历您的数据。
foreach (.. item in ...)
{
var element = new BoxView(...);
AbsoluteLayout.SetLayoutBounds(element, ...);
outerLayout.Children.Add(element);
}
查阅BoxView
和AbsoluteLayout SetLayoutBounds
的文档,以查看参数。
注意:我使用了BoxView
而不是Frame
。首先使用它进行测试。Frame
在没有一些元素的情况下效果不佳。您可以尝试使用包含BoxView
的Frame
进行测试。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论