Добавить несколько ярлыков в Xamarin Forms

У меня есть следующая метка:

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

И событие на кнопке:

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

Что это значит, каждый раз, когда я нажимаю кнопку, мой счет увеличивается на 1. То, что я хотел сделать, также увеличивает число Label в зависимости от количества баллов. См. Прикрепленное изображение ниже:

введите описание изображения здесь

Кто-нибудь знает, как я могу это достичь?

Ответы

Ответ 1

Существуют различные решения этого вопроса. Обязательно прочитайте их все, прежде чем выбрать один - мой любимый (самый простой) будет указан до конца...

Подход №1:

Как было предложено несколькими людьми, вы можете создать некоторый элемент управления коллекцией (я приду к этому через мгновение), определите ObservableCollection в ViewModel, задайте страницу 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());
};

Однако все это кажется довольно взломанным для создания списка зеленых галочек. Это приводит нас к...

... подход № 3:

Технически это не совсем то, о чем вы просили (увеличивайте количество ярлыков), но в соответствии с вашим снимком экрана он может удовлетворить ваши потребности гораздо проще.

Удалите существующий текст ярлыка (поскольку он не будет отображаться при запуске) и вместо этого дайте ему уникальное имя:

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

(Существует несколько способов сделать эту функцию повторения максимально возможной, я просто выбрал простейший однострочный доступ, поиск StackOverflow для подробных обсуждений...)

Теперь вы можете работать с единственным элементом управления Label, определенным в XAML, и просто назначить ему несколько меток на кнопке:

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, просто используя общедоступное свойство bindable string вместо того, чтобы напрямую устанавливать атрибут метки Text, но для этого я бы посоветовал вам взять посмотрите учебник MVVM для начинающих.

Ответ 2

Если оценка имеет максимум, просто добавьте максимальное количество меток и привяжите их видимость.

Или вы можете создать список меток и привязать источник к коллекции, которую вы увеличиваете, когда это необходимо.

Ответ 3

Просто вставьте новый код ярлыка в событие нажатия кнопки, которое добавит новых детей в стек очков.

cs page Код: -

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

введите описание изображения здесь

Ответ 4

Примечание. Я не уверен, правильный ли ответ, но он слишком длинный для комментария. Просто проверьте его, и если это не сработает, я удалю этот ответ


Вы можете добавлять элементы управления программно. Имейте в виду, что вам нужно добавить Label в свой MainThread, потому что это изменение в пользовательском интерфейсе. Добавьте это в событие Clicked:

correctButton.Clicked += (sender, e) =>
{
    App.DB.IncrementScore();
    Device.BeginInvokeOnMainThread(() => // On MainThread because it 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, вы можете установить Grid.Row и Grid.Column с помощью метода SetValue для Control:

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