绑定 AbsoluteLayout.LayoutBounds 在 Xamarin.Forms 中

huangapple go评论62阅读模式
英文:

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的值,但hw太小。

编辑:

我应用了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:

    &lt;AbsoluteLayout x:Name=&quot;outerLayout&quot; Grid.Row=&quot;1&quot; Grid.Column=&quot;1&quot;
                    VerticalOptions=&quot;FillAndExpand&quot; HorizontalOptions=&quot;FillAndExpand&quot; Margin=&quot;0,0,10,10&quot; &gt;
        &lt;RefreshView x:DataType=&quot;vm:MyViewModel&quot; Command=&quot;{Binding ProjectEditor.LoadItemsCommand}&quot; IsRefreshing=&quot;{Binding ProjectEditor.IsBusy, Mode=TwoWay}&quot;&gt;
            &lt;CollectionView x:Name=&quot;ItemsListView&quot;
                            ItemsSource=&quot;{Binding Items}&quot;
                            SelectionMode=&quot;None&quot;&gt;
                &lt;CollectionView.ItemTemplate&gt;
                    &lt;DataTemplate&gt;
                        &lt;Frame x:DataType=&quot;model:LayoutItem&quot; 
                               AbsoluteLayout.LayoutBounds=&quot;{Binding Rect, Mode=OneWay}&quot; AbsoluteLayout.LayoutFlags=&quot;All&quot;                                              
                               BackgroundColor=&quot;LightSalmon&quot; &gt;
                            &lt;Frame.GestureRecognizers&gt;
                                &lt;TapGestureRecognizer Tapped=&quot;Test_Clicked&quot; /&gt;
                            &lt;/Frame.GestureRecognizers&gt;
                        &lt;/Frame&gt;
                    &lt;/DataTemplate&gt;
                &lt;/CollectionView.ItemTemplate&gt;
            &lt;/CollectionView&gt;
        &lt;/RefreshView&gt;
    &lt;/AbsoluteLayout&gt;

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:

&lt;Frame x:DataType=&quot;model:LayoutItem&quot; 
         AnchorX=&quot;{Binding Rect.X}&quot; AnchorY=&quot;{Binding Rect.Y}&quot; 
         HeightRequest=&quot;{Binding Rect.Height}&quot; WidthRequest=&quot;{Binding Rect.Width}&quot;                                       
         BackgroundColor=&quot;LightSalmon&quot; BorderColor=&quot;Black&quot; HorizontalOptions=&quot;StartAndExpand&quot; &gt;

Edit:

I removed the first &lt;Frame /&gt; 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.LayoutBoundsAbsoluteLayout直接子元素之外的元素没有影响。
这里的两个子元素是FrameRefreshView
无法应用于嵌套元素。

  • DataTemplate内部,绑定内部FrameHeightRequestWidthRequest

  • 还要设置CollectionViewItemSizingStrategy="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);    
}

查阅BoxViewAbsoluteLayout SetLayoutBounds的文档,以查看参数。

注意:我使用了BoxView而不是Frame。首先使用它进行测试。Frame在没有一些元素的情况下效果不佳。您可以尝试使用包含BoxViewFrame进行测试。

英文:

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=&quot;MeasureAllItems&quot;.


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=&quot;Start&quot;. 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.

huangapple
  • 本文由 发表于 2023年3月7日 01:49:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75654162.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定