採用MvvmLight工具構建的計算器
Models:CalculationModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MvvmCalculator.Models
{
public class CalculationModel
{
#region 私有成員
private string _result;
#endregion
#region 構造函數
public CalculationModel()
{
FirstOperand = string.Empty;
SecondOperand = string.Empty;
Operation = string.Empty;
_result = string.Empty;
}
#endregion
#region 公共屬性和方法
public string FirstOperand { get; set; } //第一個數
public string SecondOperand { get; set; } //第二個數
public string Operation { get; set; } //運算符
public string Result { get { return _result; } } //結果
public void CalculateResult() //計算結果
{
ValidateData(); //校驗數據
try
{
switch (Operation) //利用運算符,決定使用哪種算法
{
case ("+"):
_result = (Convert.ToDouble(FirstOperand) + Convert.ToDouble(SecondOperand)).ToString();
break;
case ("-"):
_result = (Convert.ToDouble(FirstOperand) - Convert.ToDouble(SecondOperand)).ToString();
break;
case ("*"):
_result = (Convert.ToDouble(FirstOperand) * Convert.ToDouble(SecondOperand)).ToString();
break;
case ("/"):
_result = (Convert.ToDouble(FirstOperand) / Convert.ToDouble(SecondOperand)).ToString();
break;
case ("sin"):
_result = Math.Sin(DegreeToRadian(Convert.ToDouble(FirstOperand))).ToString();
break;
case ("cos"):
_result = Math.Cos(DegreeToRadian(Convert.ToDouble(FirstOperand))).ToString();
break;
case ("tan"):
_result = Math.Tan(DegreeToRadian(Convert.ToDouble(FirstOperand))).ToString();
break;
}
}
catch (Exception)
{
_result = "Error whilst calculating";
throw;
}
}
private double DegreeToRadian(double angle) //角度運算
{
return Math.PI * angle / 180.0;
}
private void ValidateOperand(string operand) //校驗數據
{
try
{
Convert.ToDouble(operand);
}
catch (Exception)
{
_result = "Invalid number: " + operand;
throw;
}
}
private void ValidateOperation(string operation) //校驗運算符
{
switch (operation)
{
case "/":
case "*":
case "-":
case "+":
case "tan":
case "cos":
case "sin":
break;
default:
_result = "Unknown operation: " + operation;
throw new ArgumentException("Unknown Operation: " + operation, "operation");
}
}
private void ValidateData() //校驗所有數據
{
switch (Operation)
{
case "/":
case "*":
case "-":
case "+":
ValidateOperand(FirstOperand);
ValidateOperand(SecondOperand);
break;
case "tan":
case "cos":
case "sin":
ValidateOperand(FirstOperand);
break;
default:
_result = "Unknown operation: " + Operation;
throw new ArgumentException("Unknown Operation: " + Operation, "operation");
}
}
#endregion
}
}
ViewModels:CalculatorViewModel.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using MvvmCalculator.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace MvvmCalculator.ViewModels
{
public class CalculatorViewModel:ViewModelBase
{
#region 私有成員
private CalculationModel calculation;
private string lastOperation;
private bool newDisplayRequired = false;
private string fullExpression;
private string display;
#endregion
#region 構造函數
public CalculatorViewModel()
{
this.calculation = new CalculationModel();
this.display = "0";
this.FirstOperand = string.Empty;
this.SecondOperand = string.Empty;
this.Operation = string.Empty;
this.lastOperation = string.Empty;
this.fullExpression = string.Empty;
}
#endregion
#region 公共屬性
public string FirstOperand //第一個數
{
get { return calculation.FirstOperand; }
set { calculation.FirstOperand = value; }
}
public string SecondOperand //第二個數
{
get { return calculation.SecondOperand; }
set { calculation.SecondOperand = value; }
}
public string Operation //運算符
{
get { return calculation.Operation; }
set { calculation.Operation = value; }
}
public string LastOperation //最後運算符
{
get { return lastOperation; }
set { lastOperation = value; }
}
public string Result //結果
{
get { return calculation.Result; }
}
public string Display //顯示數據
{
get { return display; }
set
{
display = value;
RaisePropertyChanged("Display");
}
}
public string FullExpression //表達式
{
get { return fullExpression; }
set
{
fullExpression = value;
RaisePropertyChanged("FullExpression");
}
}
#endregion
#region 命令
public ICommand OperationButtonPressCommand //操作符按鈕命令(=)
{
get
{
return new RelayCommand<string>((operation) =>
{
try
{
if (FirstOperand == string.Empty || LastOperation == "=") //第一個操作數爲空,則賦值爲0,或者計算完,拿結果作爲第一個操作數
{
FirstOperand = display;
LastOperation = operation;
}
else
{
SecondOperand = display;
Operation = lastOperation;
calculation.CalculateResult();
FullExpression = Math.Round(Convert.ToDouble(FirstOperand), 10) + " " + Operation + " "
+ Math.Round(Convert.ToDouble(SecondOperand), 10) + " = "
+ Math.Round(Convert.ToDouble(Result), 10);
LastOperation = operation;
Display = Result;
FirstOperand = display; //將計算結果賦值給第一個操作數
}
newDisplayRequired = true;
}
catch (Exception)
{
Display = Result == string.Empty ? "Error " : Result;
}
});
}
}
public ICommand SingularOperationButtonPressCommand //單操作數按鈕命令
{
get
{
return new RelayCommand<string>((operation) =>
{
try
{
FirstOperand = Display;
Operation = operation;
calculation.CalculateResult();
FullExpression = Operation + "(" + Math.Round(Convert.ToDouble(FirstOperand), 10) + ") = "
+ Math.Round(Convert.ToDouble(Result), 10);
LastOperation = "=";
Display = Result;
FirstOperand = display;
newDisplayRequired = true;
}
catch (Exception)
{
Display = Result == string.Empty ? "Error " : Result;
}
});
}
}
public ICommand DigitButtonPressCommand //數字按鈕命令
{
get
{
return new RelayCommand<string>((button) =>
{
switch (button)
{
case "C": //清除按鈕
Display = "0";
FirstOperand = string.Empty;
SecondOperand = string.Empty;
Operation = string.Empty;
LastOperation = string.Empty;
FullExpression = string.Empty;
break;
case "Del": //刪除按鈕
if (display.Length > 1)
Display = display.Substring(0, display.Length - 1);
else Display = "0";
break;
case "+/-": //正數,負數
if (display.Contains("-") || display == "0")
{
Display = display.Remove(display.IndexOf("-"), 1);
}
else Display = "-" + display;
break;
case ".":
if (newDisplayRequired) //如果需要重新顯示
{
Display = "0.";
}
else
{
if (!display.Contains("."))
{
Display = display + ".";
}
}
break;
default:
if (display == "0" || newDisplayRequired)
Display = button;
else
Display = display + button;
break;
}
newDisplayRequired = false;
});
}
}
#endregion
}
}
Views:Calculator.xaml
<Window x:Class="MvvmCalculator.Views.Calculator"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MvvmCalculator.ViewModels"
Title="WPF Calculator"
Height="340"
Width="500"
ResizeMode="CanMinimize" >
<DockPanel Name="MyPanel">
<Grid Name="MyGrid" Background="Black" ShowGridLines="False" Height="287" Width="475">
<Grid.Resources>
<Storyboard x:Key="playStoryboard">
<DoubleAnimation From="30" To="20" Duration="0:0:0.25" RepeatBehavior="1x" AutoReverse="True" Storyboard.TargetName="TB" Storyboard.TargetProperty="(Rectangle.Height)"/>
<DoubleAnimation From="60" To="40" Duration="0:0:0.25" RepeatBehavior="1x" AutoReverse="True" Storyboard.TargetName="TB" Storyboard.TargetProperty="(Rectangle.Width)"/>
</Storyboard>
<Style x:Key="DigitBtn" TargetType="{x:Type Button}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="FontSize" Value="14pt"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Width="60" Height="32">
<Rectangle RadiusX="10" RadiusY="10" Width="57" Height="30" x:Name="TB" StrokeThickness="1"
Stroke="{TemplateBinding Foreground}" Fill="{TemplateBinding Background}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="TB" Property="Rectangle.Fill" Value="Gray" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="TB" Property="Rectangle.Fill" Value="DarkSlateGray" />
</Trigger>
<EventTrigger RoutedEvent="ButtonBase.Click">
<EventTrigger.Actions>
<BeginStoryboard Name="playStoryboard" Storyboard="{StaticResource playStoryboard}"/>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Name="DisplayBox" Text="{Binding Path=Display, Mode=TwoWay}" Background="White" Margin="20,10,20,2" Grid.ColumnSpan="5" FontSize="24" TextAlignment="Right"></TextBlock>
<TextBlock Name="ExpressionBox" Text="{Binding Path=FullExpression, Mode=TwoWay}" Background="DarkGray" TextAlignment="Center" Grid.Column="0" Grid.Row="1" Margin="20,10,20,10" Grid.ColumnSpan="3" FontSize="18"></TextBlock>
<Button Name="Button7" Command="{Binding DigitButtonPressCommand}" CommandParameter="7" Style="{StaticResource DigitBtn}" Grid.Column="0" Grid.Row="2">7</Button>
<Button Name="Button8" Command="{Binding DigitButtonPressCommand}" CommandParameter="8" Style="{StaticResource DigitBtn}" Grid.Column="1" Grid.Row="2">8</Button>
<Button Name="Button9" Command="{Binding DigitButtonPressCommand}" CommandParameter="9" Style="{StaticResource DigitBtn}" Grid.Column="2" Grid.Row="2">9</Button>
<Button Name="Button4" Command="{Binding DigitButtonPressCommand}" CommandParameter="4" Style="{StaticResource DigitBtn}" Grid.Column="0" Grid.Row="3" >4</Button>
<Button Name="Button5" Command="{Binding DigitButtonPressCommand}" CommandParameter="5" Style="{StaticResource DigitBtn}" Grid.Column="1" Grid.Row="3" >5</Button>
<Button Name="Button6" Command="{Binding DigitButtonPressCommand}" CommandParameter="6" Style="{StaticResource DigitBtn}" Grid.Column="2" Grid.Row="3" >6</Button>
<Button Name="Button1" Command="{Binding DigitButtonPressCommand}" CommandParameter="1" Style="{StaticResource DigitBtn}" Grid.Column="0" Grid.Row="4" >1</Button>
<Button Name="Button2" Command="{Binding DigitButtonPressCommand}" CommandParameter="2" Style="{StaticResource DigitBtn}" Grid.Column="1" Grid.Row="4" >2</Button>
<Button Name="Button3" Command="{Binding DigitButtonPressCommand}" CommandParameter="3" Style="{StaticResource DigitBtn}" Grid.Column="2" Grid.Row="4" >3</Button>
<Button Name="Button0" Command="{Binding DigitButtonPressCommand}" CommandParameter="0" Style="{StaticResource DigitBtn}" Grid.Column="0" Grid.Row="7" >0</Button>
<Button Name="ButtonPoint" Command="{Binding DigitButtonPressCommand}" CommandParameter="." Style="{StaticResource DigitBtn}" Grid.Column="1" Grid.Row="7" >.</Button>
<Button Name="ButtonPlusMinus" Command="{Binding DigitButtonPressCommand}" CommandParameter="+/-" Background="DarkGray" Style="{StaticResource DigitBtn}" Grid.Column="2" Grid.Row="5" >+/-</Button>
<Button Name="ButtonDivide" Command="{Binding OperationButtonPressCommand}" CommandParameter="/" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="3" Grid.Row="2" >/</Button>
<Button Name="ButtonMultiply" Command="{Binding OperationButtonPressCommand}" CommandParameter="*" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="3" Grid.Row="3" >*</Button>
<Button Name="ButtonMinus" Command="{Binding OperationButtonPressCommand}" CommandParameter="-" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="3" Grid.Row="4" >-</Button>
<Button Name="ButtonPlus" Command="{Binding OperationButtonPressCommand}" CommandParameter="+" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="3" Grid.Row="5" >+</Button>
<Button Name="ButtonC" Command="{Binding DigitButtonPressCommand}" CommandParameter="C" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="4" Grid.Row="1" ToolTip="Clear All">C</Button>
<Button Name="ButtonDel" Command="{Binding DigitButtonPressCommand}" CommandParameter="Del" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="3" Grid.Row="1" ToolTip="Delete">Del</Button>
<Button Name="ButtonSin" Command="{Binding SingularOperationButtonPressCommand}" CommandParameter="sin" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="4" Grid.Row="2">Sin(x)</Button>
<Button Name="ButtonCos" Command="{Binding SingularOperationButtonPressCommand}" CommandParameter="cos" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="4" Grid.Row="3">Cos(x)</Button>
<Button Name="ButtonTan" Command="{Binding SingularOperationButtonPressCommand}" CommandParameter="tan" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="4" Grid.Row="4">Tan(x)</Button>
<Button Name="ButtonEqual" Command="{Binding OperationButtonPressCommand}" CommandParameter="=" Background="Darkgray" Style="{StaticResource DigitBtn}" Grid.Column="4" Grid.Row="5" Margin="0,0,0,0">=</Button>
</Grid>
</DockPanel>
</Window>
App.xaml.cs:
namespace MvvmCalculator
{
/// <summary>
/// App.xaml 的交互邏輯
/// </summary>
public partial class App : Application
{
private void OnStartup(object sender, StartupEventArgs e)
{
// 建立ViewModel和使用ViewModel作爲DataContext
Views.Calculator view = new Views.Calculator();
view.DataContext = new ViewModels.CalculatorViewModel();
view.Show();
}
}
}