简体   繁体   中英

Convert methods from code behind to ICommand Databinding Xamarin.Forms

I have a calculator application in Xamarin.Forms and I would like to implement MVVM. Now before I had the MVVM folders, I created the methods in MainPage.xaml.cs. When I created the ViewModel folder, I put every code from MainPage.xaml.cs to Methods.cs without changing the methods themselves. Of course, the "resultText" does not exist in the current context, so I deeply searched the internet to find out that I need the ICommand Interface. I searched for hours on how to implement the Interface to my code, but it is so complex to me, that I cannot understand a word about it, hours wasted watching hundreds of tutorials, but my mind cannot take the information on how to implement it in my code. The only thing I did is putting: ICommand after the class name, so it generated 2 methods and 1 event in my code and that's all, I have no idea how to continue. Any idea?

Methods.cs:

namespace Calculator.ViewModel
{
    class Methods : ICommand
    {
        private decimal firstNumber;
        private string operatorName;
        private bool isOperatorClicked;

        public event EventHandler CanExecuteChanged;

        //public event PropertyChangedEventHandler PropertyChanged;

        public void OnNumberButton_Clicked(object sender, EventArgs e)
        {
            var button = sender as Button;
            if (resultText.Text == "0" || isOperatorClicked)
            {
                isOperatorClicked = false;
                resultText.Text = button.Text;
            }

            else
            {
                resultText.Text += button.Text;
            }

        }

        public void OnClearButton_Clicked(object sender, EventArgs e)
        {
            resultText.Text = "0";
        }


        public void OnOperationButton_Clicked(object sender, EventArgs e)
        {
            var button = sender as Button;
            isOperatorClicked = true;
            operatorName = button.Text;
            firstNumber = Convert.ToDecimal(resultText.Text);
        }

        public void OnEqualButton_Clicked(object sender, EventArgs e)
        {
            try
            {
                decimal secondNumber = Convert.ToDecimal(resultText.Text);
                string finalResult = Calculate(firstNumber, secondNumber).ToString("0.##");
                resultText.Text = finalResult;
            }
            catch (Exception)
            {

                throw;
            }
        }

        public decimal Calculate(decimal firstNumber, decimal secondNumber)
        {
            decimal result = 0;
            if (operatorName == "+")
            {
                result = firstNumber + secondNumber;
            }

            else if (operatorName == "-")
            {
                result = firstNumber - secondNumber;
            }

            else if (operatorName == "*")
            {
                result = firstNumber * secondNumber;
            }
            else if (operatorName == "/")
            {
                result = firstNumber / secondNumber;
            }
            return result;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            OnClearButton_Clicked;
        }
        
    }
}

MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Calculator.MainPage">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="Android" Value="20, 20" > </On>
        </OnPlatform>
    </ContentPage.Padding>

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="infostyle" TargetType="Button">
                <Setter Property="WidthRequest" Value="60"/>
                <Setter Property="HeightRequest" Value="60"/>
                <Setter Property="TextColor" Value="White"/>
                <Setter Property="FontSize" Value="25"/>
                <Setter Property="BorderColor" Value="Black"/>
                <Setter Property="BorderWidth" Value="1"/>
                <Setter Property="BackgroundColor" Value="Green"/>
            </Style>
        </ResourceDictionary>
        <ResourceDictionary>
            <Style x:Key="topstyle" TargetType="Button">
                <Setter Property="WidthRequest" Value="60"/>
                <Setter Property="HeightRequest" Value="60"/>
                <Setter Property="TextColor" Value="White"/>
                <Setter Property="FontSize" Value="25"/>
                <Setter Property="BorderColor" Value="Black"/>
                <Setter Property="BorderWidth" Value="1"/>
                <Setter Property="BackgroundColor" Value="Green"/>
            </Style>
        </ResourceDictionary>
        <ResourceDictionary>
                <Style x:Key="rightstyle" TargetType="Button">
                    <Setter Property="WidthRequest" Value="60"/>
                    <Setter Property="HeightRequest" Value="60"/>
                    <Setter Property="TextColor" Value="White"/>
                    <Setter Property="FontSize" Value="25"/>
                    <Setter Property="BorderColor" Value="Black"/>
                    <Setter Property="BorderWidth" Value="1"/>
                    <Setter Property="BackgroundColor" Value="Red"/>
                </Style>
            </ResourceDictionary>
        <ResourceDictionary>
            <Style x:Key="resultstyle" TargetType="Button">
                <Setter Property="FontAttributes" Value="Bold"/>
                <Setter Property="TextColor" Value="Black"/>
                <Setter Property="FontSize" Value="38"/>
                <Setter Property="HorizontalOptions" Value="End"/>
                <Setter Property="VerticalOptions" Value="Center"/>
            </Style>
        </ResourceDictionary>


    </ContentPage.Resources>

    <Grid Padding="0, 0" RowSpacing="10" ColumnSpacing="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <ContentView Padding="0, 0, 20, 0" Margin="0, 0, 0, 10" Grid.ColumnSpan="4" BackgroundColor="Brown">
            <Label x:Name="resultText" Text="0" Style="{StaticResource resultstyle}">
                <Label.FontFamily>
                    <OnPlatform x:TypeArguments="x:String">
                        <On Platform="Android">
                        </On>
                    </OnPlatform>
                </Label.FontFamily>
            </Label>
        </ContentView>

        <Button Text="C" x:Name="btnClear" Grid.Column="0" Grid.Row="1" Style="{StaticResource topstyle}" Clicked="{Binding OnClearButton_Clicked}"/>
        <Button x:Name="btnSave" Grid.Column="1" Grid.Row="1" Text="⎚" Style="{StaticResource topstyle}"/>
        <Button Text="/" Grid.Column="2" Grid.Row="1" Style="{StaticResource topstyle}" Clicked= "{Binding OnOperationButton_Clicked}"/>
        <Button Text="÷" Grid.Column="3" Grid.Row="1" Style="{StaticResource rightstyle}"/>

        <Button Text="7" Grid.Column="0" Grid.Row="2" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button Text="8" Grid.Column="1" Grid.Row="2" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button Text="9" Grid.Column="2" Grid.Row="2" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button Text="*" Grid.Column="3" Grid.Row="2" Style="{StaticResource rightstyle}" Clicked="{Binding OnOperationButton_Clicked}"/>

        <Button Text="4" Grid.Column="0" Grid.Row="3" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button Text="5" Grid.Column="1" Grid.Row="3" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button Text="6" Grid.Column="2" Grid.Row="3" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button Text="-" Grid.Column="3" Grid.Row="3" Style="{StaticResource rightstyle}" Clicked="{Binding OnOperationButton_Clicked}"/>

        <Button Text="1" Grid.Column="0" Grid.Row="4" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button Text="2" Grid.Column="1" Grid.Row="4" Style="{StaticResource infostyle}" Clicked="{Binding OnNumberButton_Clicked}"/>
        <Button Text="3" Grid.Column="2" Grid.Row="4" Style="{StaticResource infostyle}" Clicked="{Binding OnNumberButton_Clicked}"/>
        <Button Text="+" Grid.Column="3" Grid.Row="4" Grid.RowSpan="2" Style="{StaticResource rightstyle}" Clicked="{Binding OnOperationButton_Clicked}"/>

        <Button Text="." Grid.Column="0" Grid.Row="5" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button Text="0" Grid.Column="1" Grid.Row="5" Style="{StaticResource infostyle}" Clicked= "{Binding OnNumberButton_Clicked}"/>
        <Button x:Name="btnEqual" Text="=" Grid.Column="2" Grid.Row="5" Style="{StaticResource infostyle}" Clicked= "{Binding OnEqualButton_Clicked}"/> 



    </Grid>

MainPage.xaml.cs:

namespace Calculator
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            BindingContext = new Methods();
        }

I would love to somehow convert the methods (like OnEqualButton_Clicked or OnClearButton_Clicked to become bindable commands

You need to create a viewmodel to bind with bindingcontext, initialize the command in the constructor like(code is from xamarin documents):

class CommandDemoViewModel : INotifyPropertyChanged
{
    double number = 1;

    public event PropertyChangedEventHandler PropertyChanged;

    public CommandDemoViewModel()
    {
        MultiplyBy2Command = new Command(() => Number *= 2);

        DivideBy2Command = new Command(() => Number /= 2);
    }

    public double Number
    {
        set
        {
            if (number != value)
            {
                number = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
            }
        }
        get
        {
            return number;
        }
    }

    public ICommand MultiplyBy2Command { private set; get; }

    public ICommand DivideBy2Command { private set; get; }
}

Here are the document and example of it:

https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/button

https://docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/userinterface-buttondemos/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM