在Xamarin Forms中添加多个标签

16

我有以下标签:

<Label Text="{x:Static local:FontAwesome.FACheck}" FontFamily="FontAwesome" TextColor="Green"/>

并且一个按钮上的事件:

correctButton.Clicked += (sender, e) =>
{
   App.DB.IncrementScore();
};

每次点击按钮,这段代码会将我的分数加1。我想做的是根据分数的数量增加Label的数量。请参见下面的附图:

enter image description here

有人有任何想法如何实现这个?


2
我强烈建议为这个应用程序考虑使用MVVM架构。您可以将标签绑定到ViewMidel中的ObservableCollection <string> - Rob Lyndon
1
@RobLyndon 谢谢。我知道MVVM,但不知道如何在这里应用它。你能给我一些与我的问题相关的代码示例吗? - user6742877
4个回答

8
这个问题有不同的解决方案。在选择一个之前,请确保阅读所有解决方案——我最喜欢的(也是最简单的)解决方案在最底部列出……
第一种方法:
正如几位人士建议的那样,您可以创建一些集合控件(稍后我会讲到这个),在 ViewModel 中定义一个 ObservableCollection,将页面的 Binding Context 设置为该 ViewModel 的实例,并在单击按钮时向集合中添加项目:
public class MyViewModel()
{
    public ObservableCollection<int> Items { get; set; } = new ObservableCollection<int>();
}

private MyViewModel _viewModel = new MyViewModel();
public MainPage()
{
    InitializeComponent();

    BindingContext = _viewModel;
}

correctButton.Clicked += (sender, e) =>
{
    App.DB.IncrementScore();
    _viewModel.Items.Add(0);
};

“ObservableCollection”的类型实际上并不重要,因为我们对所有项都使用相同的静态“ItemTemplate”。
<ContentPage.Resources>
    <DataTemplate x:Key="ScoreItemTemplate">
        <ViewCell>
            <ViewCell.View>
                <Label Text="{x:Static local:FontAwesome.FACheck}" FontFamily="FontAwesome" TextColor="Green"/>
            </ViewCell.View>
        </ViewCell>
    </DataTemplate>
</ContentPage.Resources>

这种方法的主要问题是,Xamarin.Forms的ListView无法水平显示其项目。这意味着,您需要下载其中一个可用的HorizontalListView Nuget包,或者使用内置(仅在Xamarin.Forms 2.3及以上版本中可用!)CarouselView
<CarouselView ItemTemplate="{StaticResource ScoreItemTemplate}" ItemsSource="{Binding Items}"/>

然后,您可能希望花些时间删除轮播图的滑动视觉效果以及选择项目的视觉效果(如果您选择使用水平ListView)...
相反,有两种替代解决方案可以减少工作量:
方法2:
显然,简单的方法是在代码中创建“模板”标签:
private Label CreateScoreLabel()
{
    return new Label {Text = FontAwesome.FACheck, TextColor = Color.Green, FontFamily = "FontAwesome"};
}

在页面中添加一个水平的 StackLayout
<StackLayout Orientation="Horizontal" x:Name="LabelStack"/>

"...并且用较困难的方式添加新标签:"
correctButton.Clicked += (sender, e) =>
{
    App.DB.IncrementScore();
    LabelStack.Children.Add(CreateScoreLabel());
};

然而,仅为创建一个绿色勾号列表而言,所有这些方法似乎都有点笨拙。这就引出了第三种方法...
技术上讲,这并不完全是您要求的(增加标签数量),但根据您的屏幕截图,它可能以更简单的方式满足您的需求。
删除现有标签的文本(因为在启动时它将不显示任何内容),并给它一个唯一的名称:
<Label x:Name="ScoreLabel" FontFamily="FontAwesome" TextColor="Green"/>

现在,为“string”类型定义一个简单的扩展方法,用于重复给定字符串一定次数:
public static class StringExtensions
{
    public static string Repeat(this string input, int num)
    {
        return String.Concat(Enumerable.Repeat(input, num));
    }
}

有多种方法可以使这个“repeat”函数达到最佳性能,我选择了最简单的一句话代码,可以在StackOverflow上搜索详细讨论...
现在你可以使用在XAML中定义的单个“Label”控件,并在按钮点击时将多个复选标记分配给它:
correctButton.Clicked += (sender, e) =>
{
    App.DB.IncrementScore();
    ScoreLabel.Text = FontAwesome.FACheck.Repeat(App.DB.Score); // replace parameter by whatever method allows you to access the current score number
};

当然,这种方法也可以根据MMVM的方式进行调整,只需使用公共可绑定的“字符串”属性而不是直接设置标签的“Text”属性即可。不过,我建议你查看一些入门级的MVVM教程。

谢谢。我正在尝试第三种方法,但是出现了错误“字符串无法识别为有效的布尔值”。有任何想法吗? - user6742877
这个错误是在哪一行抛出的?另外,您能否展示一下精确的按钮点击处理程序,在适应您的需求后? - andreask
1
抱歉,这是我的错误。我之前在调试代码时添加了一个“IsVisible”属性到我的标签中,但是没有给它赋值。我会使用您的解决方案进一步完善代码,然后告诉您它是否有效。 - user6742877
1
一定要使用第三种方法,通过减少标签数量可以大大提高性能。创建5个标签来创建5个检查可能有些过度设计。这也消除了水平的StackLayoutCarouselView的需要,您可以使用Label间距选项来放置检查。第三种方法应该被标记为答案,并相应地修改问题。 - BrewMate

2

只需在按钮单击事件中插入新的标签代码,即可将新的子项添加到您的分数堆栈中。

CS页面代码:

button.Clicked += (sender, e) =>
    {
        App.DB.IncrementScore();
        lblStack.Children.Add(new Label {Text = FontAwesome.FACheck, TextColor = Color.Green, FontFamily = "FontAwesome"});
    };

XAML 代码
<StackLayout Orientation="Horizontal" x:Name="lblStack"/>

enter image description here


1
如果分数有最大值,只需添加最大数量的标签并绑定它们的可见性。
或者,您可以创建一个标签的列表视图,并将其源绑定到在需要时递增的集合。

我可以做到这一点,但这不是一个非常干净的解决方案,因为我最多只有20个点。 - user6742877

0
注意:我不确定这个答案是否正确,但是它太长了,不能作为评论。只需测试一下,如果不起作用,我会删除这个答案。

您可以通过编程方式添加控件。请记住,您需要在主线程上添加一个Label,因为这是对UI的更改。将以下内容添加到您的Clicked事件中:

correctButton.Clicked += (sender, e) =>
{
    App.DB.IncrementScore();
    Device.BeginInvokeOnMainThread(() => // On MainThread because it's a change in your UI
    {
        Label label = new Label();
        label.Text = "{x:Static local:FontAwesome.FACheck}"; // Not sure if this is right syntax...
        label.FontFamily = "FontAwesome";
        label.TextColor = Color.Green;
        stackPanel.Children.Add(label);
    });
};

如果您有一个Grid,您可以使用ControlSetValue方法设置Grid.RowGrid.Column
label.SetValue(Grid.RowProperty, 1);
label.SetValue(Grid.RowProperty, 2);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接