WPF, XAML

(동영상)WPF, Command, 데이터 바인딩을 이용한 계산기 실습(MVVM)

 

(동영상)WPF, Command, 데이터 바인딩을 이용한 계산기 실습(MVVM)

n  지금까지 배운 Command 패턴, 데이터 바인딩 및 MVVM을 이용하여 간단한 계산기를 구현해 보자.

167511065da83b1ccd0e73dff6f5dbe8_1597993
 

 

1.MainWindow.xaml

<Window x:Class="WpfApp14.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:WpfApp14"

        mc:Ignorable="d"

        Title="MainWindow" Height="400" Width="400">

    <Grid HorizontalAlignment="Center"

            VerticalAlignment="Center">

        <Grid.RowDefinitions>

            <RowDefinition Height="60" />

            <RowDefinition Height="60" />

            <RowDefinition Height="60" />

            <RowDefinition Height="60" />

            <RowDefinition Height="60" />

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="60" />

            <ColumnDefinition Width="60" />

            <ColumnDefinition Width="60" />

            <ColumnDefinition Width="60" />

        </Grid.ColumnDefinitions>

        <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="120" />

                <ColumnDefinition Width="50*" />

                <ColumnDefinition Width="50*" />

            </Grid.ColumnDefinitions>

            <Border BorderThickness="1" BorderBrush="Black">

                <TextBlock FontSize="15" VerticalAlignment="Center"

                               HorizontalAlignment="Center"

                               Text="{Binding DisplayText}" />

            </Border>

            <Button Content="BACK" Grid.Column="1"

                                             Command="{Binding Backspace}" />

            <Button Content="Clear" Grid.Column="2"

                                             Command="{Binding Clear}" />

        </Grid>

        <Button Content="1" CommandParameter="1" Grid.Row="1" Grid.Column="0"

                    Command="{Binding Append}" />

        <Button Content="2" CommandParameter="2" Grid.Row="1" Grid.Column="1"

                     Command="{Binding Append}" />

        <Button Content="3" CommandParameter="3" Grid.Row="1" Grid.Column="2"

                    Command="{Binding Append}" />

        <Button Content="+" CommandParameter="+" Grid.Row="1" Grid.Column="3"

                    Command="{Binding Operator}" />

        <Button Content="4" CommandParameter="4" Grid.Row="2" Grid.Column="0"

                    Command="{Binding Append}" />

        <Button Content="5" CommandParameter="5" Grid.Row="2" Grid.Column="1"

                    Command="{Binding Append}" />

        <Button Content="6" CommandParameter="6" Grid.Row="2" Grid.Column="2"

                    Command="{Binding Append}" />

        <Button Content="-" CommandParameter="-" Grid.Row="2" Grid.Column="3"

                    Command="{Binding Operator}" />

        <Button Content="7" CommandParameter="7" Grid.Row="3" Grid.Column="0"

                    Command="{Binding Append}" />

        <Button Content="8" CommandParameter="8" Grid.Row="3" Grid.Column="1"

                    Command="{Binding Append}" />

        <Button Content="9" CommandParameter="9" Grid.Row="3" Grid.Column="2"

                    Command="{Binding Append}" />

        <Button Content="x" CommandParameter="*" Grid.Row="3" Grid.Column="3"

                    Command="{Binding Operator}" />

        <Button Content="0" CommandParameter="0" Grid.Row="4" Grid.Column="0"

                    Command="{Binding Append}" />

        <Button Content="." CommandParameter="." Grid.Row="4" Grid.Column="1"

                    Command="{Binding Append}" />

        <Button Content="=" CommandParameter="=" Grid.Row="4" Grid.Column="2"

                    Command="{Binding Calculate}" />

        <Button Content="/" CommandParameter="/" Grid.Row="4" Grid.Column="3"

                    Command="{Binding Operator}" />

    </Grid>

</Window>

 

2. MainWindow.xaml.cs

using System.Windows;

 

namespace WpfApp14

{

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

            this.DataContext = new CalcViewModel();

        }

    }

}

 

 

 

3. CalcViewModel.cs

using System.ComponentModel;

using System.Windows.Input;

 

namespace WpfApp14

{

    public class CalcViewModel : INotifyPropertyChanged

    {

        //아래 두 필드는 속성으로 구현되어 있다.

        //출력될 문자들을 담아둘 변수

        string inputString = "";

 

        //계산기화면의 출력 텍스트박스에 대응되는 필드

        string displayText = "";

 

        //View와 바인딩된 속성값이 바뀔때 이를 WPF에게 알리기 위한 이벤트

        public event PropertyChangedEventHandler PropertyChanged;

 

        // 생성자, 명령객체들을 초기화

        // 명령객체들은 UI쪽 버튼의 Command에 바인딩 되어 있다.

        public CalcViewModel()

        {

            //이벤트 핸들러 정의

            //숫자 버튼을 클릭할 때 실행

            this.Append = new Append(this);

 

            //백스페이스 버튼을 클릭할 때 실행, 한글자 삭제

            this.Backspace = new Backspace(this);

 

            //출력화면 클리어

            this.Clear = new Clear(this);

 

            //+, -, *, / 등 연산자 클릭할 때 실행

            this.Operator = new Operator(this);

 

            // =’ 버튼을 클릭할 때 실행

            this.Calculate = new Calculate(this);

        }

 

        public string InputString

        {

            internal set

            {

                if (inputString != value)

                {

                    inputString = value;

                    OnPropertyChanged("InputString");

                    if (value != "")

                    {

                        // 숫자를 여러개 입력하면 계속 화면에 출력하기 위해

                        DisplayText = value;

                    }

                }

            }

            get { return inputString; }

        }

 

        //계산기의 출력창과 바인딩된 속성

        public string DisplayText

        {

            internal set

            {

                if (displayText != value)

                {

                    displayText = value;

                    OnPropertyChanged("DisplayText");

                }

            }

            get { return displayText; }

        }

 

        public string Op { get; set; }       // Opertaor

        public double? Op1 { get; set; }  // Operand 1

 

        public ICommand Append { protected set; get; }

        public ICommand Backspace { protected set; get; }

        public ICommand Clear { protected set; get; }

        public ICommand Operator { protected set; get; }

        public ICommand Calculate { protected set; get; }

 

        protected void OnPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

 

 

    }

}

 

 

4. CalcCommand.cs

using System;

using System.Windows.Input;

 

namespace WpfApp14

{

    class Append : ICommand

    {

        private CalcViewModel c;

        public event EventHandler CanExecuteChanged;

        public Append(CalcViewModel c)

        {

            this.c = c;

        }

        public bool CanExecute(object parameter)

        {

            return true;

        }

        public void Execute(object parameter)

        {

            c.InputString += parameter;

        }

    }

 

    class Backspace : ICommand

    {

        private CalcViewModel c;

 

        public Backspace(CalcViewModel c)

        {

            this.c = c;

        }

        public event EventHandler CanExecuteChanged

        {

            add { CommandManager.RequerySuggested += value; }

            remove { CommandManager.RequerySuggested -= value; }

        }

        public bool CanExecute(object parameter)

        {

            return c.DisplayText.Length > 0;

        }

        public void Execute(object parameter)

        {

            int length = c.InputString.Length - 1;

            if (0 < length)

            {

                c.InputString = c.InputString.Substring(0, length);

            }

            else

            {

                c.InputString = c.DisplayText = "";

            }

        }

    }

 

    class Clear : ICommand

    {

        private CalcViewModel c;

 

        public Clear(CalcViewModel c)

        {

            this.c = c;

        }

        public event EventHandler CanExecuteChanged

        {

            add { CommandManager.RequerySuggested += value; }

            remove { CommandManager.RequerySuggested -= value; }

        }

        public bool CanExecute(object parameter)

        {

            return c.DisplayText.Length > 0;

        }

        public void Execute(object parameter)

        {

            c.InputString = c.DisplayText = "";

            c.Op1 = null;

        }

    }

 

    class Operator : ICommand

    {

        private CalcViewModel c;

        public Operator(CalcViewModel c)        {            this.c = c;        }

        public event EventHandler CanExecuteChanged

        {

            add { CommandManager.RequerySuggested += value; }

            remove { CommandManager.RequerySuggested -= value; }

        }

        public bool CanExecute(object parameter)

        {

            return 0 < c.InputString.Length;

        }

        public void Execute(object parameter)

        {

            string op = parameter.ToString();

            double op1;

            if (double.TryParse(c.InputString, out op1))

            {

                c.Op1 = op1;

                c.Op = op;

                c.InputString = "";   //3 그리고 + 를 누르면 DisplayText3, InputString Clear

            }

            else if (c.InputString == "" && op == "-")

            {

                c.InputString = "-";

            }

        }

    }

 

    class Calculate : ICommand

    {

        private CalcViewModel c;

        public Calculate(CalcViewModel c)

        {

            this.c = c;

        }

        public event EventHandler CanExecuteChanged

        {

            add { CommandManager.RequerySuggested += value; }

            remove { CommandManager.RequerySuggested -= value; }

        }

 

        public bool CanExecute(object parameter)

        {

            double op2;

            return c.Op1 != null && double.TryParse(c.InputString, out op2);

        }

 

        public void Execute(object parameter)

        {

            double op2 = double.Parse(c.InputString);

            c.InputString = calculate(c.Op, (double)c.Op1, op2).ToString();

            c.Op1 = null;

        }

        private static double calculate(string op, double op1, double op2)

        {

            switch (op)

            {

                case "+": return op1 + op2;

                case "-": return op1 - op2;

                case "*": return op1 * op2;

                case "/": return op1 / op2;

            }

            return 0;

        }

    }

 

}

 

 

 

Comments