user6742877
user6742877

Reputation:

Add multiple labels in Xamarin Forms

I have the following label:

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

And an event on button:

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

What this does is everytime I click on a button my score is incremented by 1. What I wanted to do is also increment the number of Labels depending on the number of score. See the attached image below:

enter image description here

Anyone has any idea how I could achieve this?

Upvotes: 16

Views: 5507

Answers (4)

Dennis Schr&#246;er
Dennis Schr&#246;er

Reputation: 2422

Note: I'm not sure if this answer is correct, but it's too long for a comment. Just test it and if it doesn't work I will delete this answer


You can add controls programmatically. Keep in mind that you need to add a Label on your MainThread, because it's a change to the UI. Add this to your Clicked event:

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);
    });
};

In case you have a Grid, you can set Grid.Row and Grid.Column with the SetValue method of a Control:

label.SetValue(Grid.RowProperty, 1);
label.SetValue(Grid.RowProperty, 2);

Upvotes: 0

sumeet
sumeet

Reputation: 305

Simply insert new label code in button click event which will add new children in your score stack.

cs page Code:-

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

xamal code

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

enter image description here

Upvotes: 2

andreask
andreask

Reputation: 4298

There are different solutions to this question. Be sure to read through all of them before choosing one - my favorite (the simplest one) is listed all the way down...

Approach #1:

As several people have suggested, you can create some collection control (I'll come to that in a moment), define an ObservableCollection within a ViewModel, set the Page's Binding Context to an instance of that ViewModel, and add items to the collection on button click:

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);
};

The type of ObservableCollection actually does not matter, since we are using the same static ItemTemplate for all items:

<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>

The main problem with this approach is that Xamarin.Forms ListView can not display its items horizontally. This means, you'd need to download one of the available HorizontalListView Nuget packages out there, or use the built-in (only in Xamarin.Forms 2.3 and above!) CarouselView:

<CarouselView ItemTemplate="{StaticResource ScoreItemTemplate}" ItemsSource="{Binding Items}"/>

Then, you'll might wish to spend some time removing all the visual effects for swiping through the carousel, and for selecting items if you choose to use a horizontal ListView...

Instead, there are two alternative solutions that involve less effort:

Approach #2:

Obviously, the simple approach would be to create the "template" label in code:

private Label CreateScoreLabel()
{
    return new Label {Text = FontAwesome.FACheck, TextColor = Color.Green, FontFamily = "FontAwesome"};
}

...add a horizontal StackLayout to the page:

<StackLayout Orientation="Horizontal" x:Name="LabelStack"/>

...and add new labels the hard way:

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

However, all this seems rather hacky for just creating a list of green check marks. This leads us to...

...approach #3:

Technically, this isn't exactly what you asked for (increment the number of Labels), but according to your screen shot it might fulfill your needs in a much simpler way.

Remove the existing label's text (as it shall display nothing at startup), and instead give it a unique name:

<Label x:Name="ScoreLabel" FontFamily="FontAwesome" TextColor="Green"/>

Now, define a simple extension method for the string type that repeats a given string for a certain number of times:

public static class StringExtensions
{
    public static string Repeat(this string input, int num)
    {
        return String.Concat(Enumerable.Repeat(input, num));
    }
}

(There are multiple ways to make this repeat function as performant as possible, I simply chose the simplest one-liner available, search StackOverflow for detailed discussions...)

You can now work with the single Label control defined in XAML, and just assign several check marks to it on button click:

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
};

Of course, this approach can also be adapted to follow the MMVM way, by simply using a public bindable string property instead of setting the label's Text attribute directly, but for this I'd advise you to take a look at a beginner's MVVM tutorial.

Upvotes: 8

Fran&#231;ois
Fran&#231;ois

Reputation: 3274

If the score has a maximum just add the max number of labels and bind their visibility.

Or you can make a listview of labels and bind the source to a collection that you increment when required.

Upvotes: 1

Related Questions