(WPF 계산기)Command, 데이터 바인딩을 이용한 WPF 계산기 실습(MVVM, ViewModel), WPF학원교육
http://ojc.asia/bbs/board.php?bo_table=WPF&wr_id=176
ojc.asia
https://www.youtube.com/watch?v=K3v-A5d2fNI&list=PLxU-iZCqT52Cmj47aKB1T-SxI33YL7rYS&index=21&t=5s

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

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 그리고 + 를 누르면 DisplayText는3, 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;
}
}
}
#WPF계산기, #MVVM, #INotifyPropertyChanged , #WPFCommand, #WPFMVVM, #MVVM이란, #WPF강좌, #WPF교육, #WPF동영상, #WPF학원
WPF계산기, MVVM, INotifyPropertyChanged , WPFCommand, WPFMVVM, MVVM이란, WPF강좌, WPF교육, WPF동영상, WPF학원