Reputation:
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 Label
s depending on the number of score. See the attached image below:
Anyone has any idea how I could achieve this?
Upvotes: 16
Views: 5507
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
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"/>
Upvotes: 2
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
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