如何在 Xamarin Forms 中的数据绑定指定的位置放置文本

Posted

技术标签:

【中文标题】如何在 Xamarin Forms 中的数据绑定指定的位置放置文本【英文标题】:How to place text in view at locations specified by databinding in Xamarin Forms 【发布时间】:2021-11-27 05:21:38 【问题描述】:

我正在寻找的功能是可点击的标签,其中文本和位置都是数据绑定的,并且位置与正在显示的图像相关。

AbsoluteLayoutRelativeLayout 我都试过了,但是标签似乎无法摆脱CollectionView 的限制;即标签根据标签的大小不断向下或跨页面迭代。我不在乎标签是否相互重叠。事实上,如果标签的字体足够大并且数据绑定的位置足够接近,那么重叠的标签是肯定的,并且点击事件在逻辑上可能发生在该像素位置顶部的任何标签上。这对我来说很好。

例如,我想要显示一个大小为 640x480 像素的图像。我想要放置在它们上面的标签文本和位置需要进行数据绑定。这是示例MockData

        public MockDataStore()
        
            items = new List<Item>()
            
                new Item  Id = Guid.NewGuid().ToString(), Text = "A"  , Description="My A"  , X= 85, Y=130 ,
                new Item  Id = Guid.NewGuid().ToString(), Text = "B"  , Description="My B"  , X=140, Y=150 ,
                new Item  Id = Guid.NewGuid().ToString(), Text = "C"  , Description="My C"  , X=190, Y=165 ,
                new Item  Id = Guid.NewGuid().ToString(), Text = "D"  , Description="My D"  , X=240, Y=175 ,
                new Item  Id = Guid.NewGuid().ToString(), Text = "E"  , Description="My E"  , X=290, Y=180 ,
                new Item  Id = Guid.NewGuid().ToString(), Text = "F"  , Description="My F"  , X=335, Y=185 
            ;
        

这是我正在尝试的 XAML。

    <Grid x:Name="grid" 
          x:DataType="local:ItemsViewModel">
        <!--<Image Source="bg.png" Aspect="AspectFit" HorizontalOptions="Start" VerticalOptions="Start" x:Name="bg"/>-->
        <RefreshView x:DataType="local:ItemsViewModel" 
                        Command="Binding LoadItemsCommand" 
                        IsRefreshing="Binding IsBusy, Mode=TwoWay">
        <CollectionView x:Name="ItemsListView"
                        ItemsSource="Binding Items"
                        SelectionMode="None">
            <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <RelativeLayout Padding="10" x:DataType="model:Item">
                            <Label Text="Binding Text" 
                                    RelativeLayout.XConstraint="ConstraintExpression Type=RelativeToParent, Property=X, Constant=Binding X"
                                    RelativeLayout.YConstraint="ConstraintExpression Type=RelativeToParent, Property=Y, Constant=Binding Y"
                                    BackgroundColor="Transparent" 
                                    FontSize="16" />
                            <RelativeLayout.GestureRecognizers>
                                <TapGestureRecognizer 
                                    NumberOfTapsRequired="1"
                                    Command="Binding Source=RelativeSource AncestorType=x:Type local:ItemsViewModel, Path=ItemTapped"     
                                    CommandParameter="Binding .">
                                </TapGestureRecognizer>
                            </RelativeLayout.GestureRecognizers>
                        </RelativeLayout>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </RefreshView>
    </Grid>

发生的情况是标签的相对位置被放置在页面下方的递增位置。只要我还能得到ItemTapped,我就不会使用CollectionView

我也尝试过使用BindableLayout,但没有成功,虽然我不确定我是否理解如何正确使用该类,而且数据源都是文本和位置。

我想要完成的类似于 GPS 应用如何显示地图并覆盖从数据加载并相对于地图内坐标的可点击兴趣点。

使用 Xamarin 的 XAML 甚至可以实现我想要完成的任务吗?

编辑:我发现RelativeLayout.XConstraint="ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0, Constant=0" TranslationX="Binding X" 会将标签放置在正确的 X 位置。但是,这个想法不适用于 Y 位置。 CollectionView 不断增加页面下方的 Y 位置。我希望 CollectionView 可以设置为不进行任何控件定位,只允许我通过绑定设置标签的 x/y 位置。

【问题讨论】:

我认为你不能用上面的方法为 XConstraint 绑定 X,它会抛出异常 No property, BindableProperty, or event found for "Constant", or mismatching type between value and property 你能解释一下如何绑定这个属性吗? 【参考方案1】:

将标签放置在正确的 X 位置。但是,这个想法不适用于 Y 位置。

问题是您在每个 CollectionView 项目中显示标签,但它们有不同的RelativeLayout 父项。并且它有足够的宽度来设置 Y 值,但不能设置 X 值。

对于这种情况,我们建议您使用BindableLayout 撰写项目

例如

<ContentPage.BindingContext>
   <local:ItemsViewModel />
</ContentPage.BindingContext>

<RelativeLayout BindableLayout.ItemsSource="Binding items">
    <BindableLayout.ItemTemplate>
        <DataTemplate x:DataType="local:Item">
            <Label
                BackgroundColor="Transparent"
                FontSize="16"
                RelativeLayout.XConstraint="Binding X"
                RelativeLayout.YConstraint="Binding Y"
                Text="Binding Text" />
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</RelativeLayout>

代码背后

public partial class MainPage : ContentPage

    public MainPage()
    
        InitializeComponent();
    


public class ItemsViewModel

    public ItemsViewModel()
    
        MockDataStore();
    
    public List<Item> items  get; set; 
    public void MockDataStore()
    
        items = new List<Item>()
        
            new Item  Id = Guid.NewGuid().ToString(), Text = "A"  , Description="My A"  ,X = Constraint.Constant(85),Y= Constraint.Constant(130),
            new Item  Id = Guid.NewGuid().ToString(), Text = "B"  , Description="My B"  ,X = Constraint.Constant(140),Y= Constraint.Constant(150),
            new Item  Id = Guid.NewGuid().ToString(), Text = "C"  , Description="My C"  ,X = Constraint.Constant(190),Y= Constraint.Constant(165),
            new Item  Id = Guid.NewGuid().ToString(), Text = "D"  , Description="My D"  ,X = Constraint.Constant(240),Y= Constraint.Constant(175),
            new Item  Id = Guid.NewGuid().ToString(), Text = "E"  , Description="My E"  ,X = Constraint.Constant(290),Y= Constraint.Constant(180),
            new Item  Id = Guid.NewGuid().ToString(), Text = "F"  , Description="My F"  ,X = Constraint.Constant(335),Y= Constraint.Constant(185)
        ;
    

public class Item

    public string Id  get; internal set; 
    public string Text  get; internal set; 
    public string Description  get; internal set; 
    public Constraint X  get; set; 
    public Constraint Y  get; set; 

【讨论】:

我试过了,但它不起作用。因此,我开始使用 Xamarin 移动应用程序模板创建一个新项目。我根据您的建议修改了 Item.cs 和 MockDataStore.cs 和 ItemsPage.xaml。 .cs 文件需要“使用 Xamarin.Forms;”添加到它们以进行编译。不去。然后我在 "" 之前添加了 "" 所以我可以查看应放置标签的区域。依然没有。为 android Marshmallow 编译。 我将项目上传到 OneDrive link 我运行你的代码,问题是你为 ItemsSource 绑定了错误的项目。它应该是项目而不是项目。 &lt;RelativeLayout BackgroundColor="cyan" BindableLayout.ItemsSource="Binding Items"&gt;。顺便说一句,您需要致电LoadItemsCommand 来准备您的数据。 但是,这确实为我指明了正确的方向。我正在建立一个 github repo 供其他人查看我做了什么,与您所说的非常相似。我会尽快发布。 有效的解决方案(至少对于 Android)是here。谢谢尼科!

以上是关于如何在 Xamarin Forms 中的数据绑定指定的位置放置文本的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 c# 将单个 html 行绑定到 xamarin.forms 中的多个标签

ReactiveUI 中的 Xamarin.Forms 控件是不是需要自定义绑定?

Xamarin.Forms:如何避免在 MVVM 绑定中硬编码字符串

如何使用 xamarin.forms-shell 在 XAML 中动态绑定类型为 <ShellContent> 的 Tab.Items 列表

自定义控件的 Xamarin 数据绑定值计算为 Xamarin.Forms.Binding

在 Xamarin Forms 中绑定之前修改数据