@MisterADK

Xamarin.Forms Как в функцию передать значение кнопки?

Привет всем! У меня следующая задача:
Имеется 4 кнопки(3 кнопки отображают значения, а 4 кнопка добавляет значение) при клике на кнопку (содержащее значиние) мы должны изменить ее цвет (при повторном клике вернуть назад цвет), а затем кликая на 4-ую кнопку (add) мы должны добавить выделенной кнопке +1.

Вот код (скорее всего он реализован неправильно):
namespace Clicker
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(false)]
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        
        private void Selected(object sender, System.EventArgs e)
        {
            Button button = (Button)sender;
           
            if(button.BackgroundColor == Color.Red) {
                button.BackgroundColor = Color.LightGray;
            }
           else
            {
                button.BackgroundColor = Color.Red;
            }
            
        }

        int count = 0;
        private void ButtonClick(object sender, System.EventArgs e){

           
            count++;
            Button buttonOne = (Button)sender;
            buttonOne.Text = Convert.ToString(count); 
            
        }

      
    }
}

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="Clicker.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackLayout>
        <!--  Place new controls here  -->
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />

            </Grid.RowDefinitions>
        <Label Grid.Column="1" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" FontSize="Large" Text="I"/>
        <Label Grid.Column="2" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" FontSize="Large" Text="II"/>
        <Label Grid.Column="3" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" FontSize="Large" Text="III"/>
        <Label Grid.Row="1" HorizontalTextAlignment="Center" FontSize="Medium"  Text="14"/>
        <Button Grid.Row="1" Grid.Column="1" Clicked="Selected" Text="14.1" />
        <Button Grid.Row="1" Grid.Column="2" Clicked="Selected" Text="14.2" />
        <Button Grid.Row="1" Grid.Column="3" Clicked="Selected" Text="14.3" />
        <Button Grid.Row="2" Grid.Column="3" Clicked="ButtonClick" Text="Add" />
            
    </Grid>
        


    </StackLayout>

</ContentPage>


Главный вопрос: как в функцию ButtonClick передать значение красной кнопке, чтобы его затем увеличить? (Пока что ButtonClick прибавляет единицу кнопке add). Заранее спасибо :)

5f22851256db5352379265.jpeg
  • Вопрос задан
  • 627 просмотров
Решения вопроса 2
FoggyFinder
@FoggyFinder
Лучше всего будет начать с чтения туториалов по MVVM

Паттерн Model-View-ViewModel

Ключевое в таком подходе разделение представления (View) от внутренней логики (Model/VM). В некоторых очень простых случаях (например, демонстрационных примерах) роли Model и VM объединяют в одну.

Концептуально, то что вы описали в своем вопросе можно определить следующим образом:

Есть некоторый объект, который содержит информацию об изменяемом значении. Также объект характеризуется двумя состояниями: "нажат" (кнопка окрашена в красный цвет) и "отжат" (кнопка стандартного цвета). В терминах C# можно выразить в виде класса:

public class Item : ViewModelBase
{
    private int value;
    private bool isSelected;
    public int Value
    {
        get => value;
        private set => SetProperty(ref this.value, value);
    }
    public bool IsSelected
    {
        get => isSelected;
        set => SetProperty(ref isSelected, value);
    }

    public Item(int value, bool isSelected = false)
    {
        Value = value;
        IsSelected = isSelected;
    }

    public void IncrementSelected()
    {
        if (IsSelected)
        {
            Value++;
        }
    }
}


Обратите внимание что класс унаследован от ViewModelBase это вспомогательный класс для того чтобы сообщать представлению об изменении некоторых свойств объекта.

Теперь сама страница:

Здесь у вас есть 3 объекта (Item) которые можно изменять, а также методы для изменения этих самых объектов. Понадобятся всего два метода:

1. Изменить состояние соответствующего объекта по нажатию на кнопку
2. Изменить значение для всех объектов для которых IsSelected истинно

Опишем этом в коде:

public class MyContext
{
    public int BaseValue { get; } = 14;
    public Item Item1 { get; }
    public Item Item2 { get; }
    public Item Item3 { get; }

    public MyContext()
    {
        Item1 = new Item(BaseValue, true);
        Item2 = new Item(BaseValue);
        Item3 = new Item(BaseValue);

        IncrementSelectedCommand =
            new DelegateCommand<object>(_ => IncrementSelected());
        ClickCommand = new DelegateCommand<Item>(
            o => SelectOrDeselect(o),
            o => o is Item);
    }

    public ICommand IncrementSelectedCommand { get; }
    public ICommand ClickCommand { get; }

    public void IncrementSelected()
    {
        Item1.IncrementSelected();
        Item2.IncrementSelected();
        Item3.IncrementSelected();
    }

    public void SelectOrDeselect(Item item)
    {
        item.IsSelected = !item.IsSelected;
    }
}


Теперь сама сложная часть - View. Сложная она только тем что я хочу максимально близко оставить вашу разметку.

Для начала определим простой стиль который будет менять цвет фона у кнопки:

<Style x:Key="selectableBtn" TargetType="Button">
    <Style.Triggers>
        <DataTrigger
            Binding="{Binding IsSelected}"
            TargetType="Button"
            Value="True">
            <Setter Property="BackgroundColor" Value="Red" />
        </DataTrigger>
    </Style.Triggers>
</Style>


Пока все просто - как только IsSelected становится равным True задаем установку свойства BackgroundColor в нужный цвет.

Последний рубеж - сетка:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Label
        Grid.Column="1"
        FontSize="Large"
        HorizontalTextAlignment="Center"
        Text="I"
        VerticalTextAlignment="Center" />
    <Label
        Grid.Column="2"
        FontSize="Large"
        HorizontalTextAlignment="Center"
        Text="II"
        VerticalTextAlignment="Center" />
    <Label
        Grid.Column="3"
        FontSize="Large"
        HorizontalTextAlignment="Center"
        Text="III"
        VerticalTextAlignment="Center" />
    <Label
        Grid.Row="1"
        FontSize="Medium"
        HorizontalTextAlignment="Center"
        Text="{Binding BaseValue}" />
    <Button
        Grid.Row="1"
        Grid.Column="1"
        BindingContext="{Binding Item1}"
        Command="{Binding BindingContext.ClickCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type d:ContentPage}}}"
        CommandParameter="{Binding .}"
        Style="{StaticResource selectableBtn}"
        Text="{Binding Value}" />
    <Button
        Grid.Row="1"
        Grid.Column="2"
        BindingContext="{Binding Item2}"
        Command="{Binding BindingContext.ClickCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type d:ContentPage}}}"
        CommandParameter="{Binding .}"
        Style="{StaticResource selectableBtn}"
        Text="{Binding Value}" />
    <Button
        Grid.Row="1"
        Grid.Column="3"
        BindingContext="{Binding Item3}"
        Command="{Binding BindingContext.ClickCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type d:ContentPage}}}"
        CommandParameter="{Binding .}"
        Style="{StaticResource selectableBtn}"
        Text="{Binding Value}" />
    <Button
        Grid.Row="2"
        Grid.Column="3"
        Command="{Binding IncrementSelectedCommand}"
        Text="Add" />
</Grid>


Единственную хитрость здесь представляет установка BindingContext для кнопки чтобы реагировать на связанный элемент.

И как вам уже подсказали чтобы из View передать информацию в VM можно использовать CommandParameter.

И, завершающий штрих, установка BindingContext для содержимого:

this.BindingContext = new MyContext();

код выше можно поместить в конструктор для MainPage

Напоследок, демонстрация работоспособности

5f22d822d81b2087880445.gif

Я намеренно не приводил код для классов ViewModelBase и RelayCommand - это стандартный классы реализации которых вы легко сможете найти.
Например, тут и тут.
Ответ написан
firedragon
@firedragon
Не джун-мидл-сеньор, а трус-балбес-бывалый.
У кнопки есть CommandParameter туда засовываете что вам нужно посмотрите в моем гите там есть код который работает с параметрами
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы