一、运行效果图
二、代码结构
.net版本 5.0
VS 版本:VS2019 16.11.3
三、主要逻辑说明
3.1 MainWindow.xaml.cs
主要代码:
采用MVVM模式绑定数据:
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
不使用原有的标题栏和菜单栏,响应最小化、关闭、鼠标拖动
private void Move_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
this.DragMove();
}
}
private void MinBtn_Click(object sender, RoutedEventArgs e)
{
this.WindowState = System.Windows.WindowState.Minimized;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
3.2 MainViewModel.cs
主要被绑定的数据
此值用来做输出显示:
private string _value = "0";
public string Value
{
get { return _value; }
set
{
_value = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
}
}
响应按钮Command:
private ICommand _valueCommand = null;
public ICommand ValueCommand
{
get{
if (_valueCommand == null)
{
_valueCommand = new CommandBase()
{
DoAction = new Action<object>(ValueCommandAction),
DoCanExecute = new Func<object, bool>(CanExecateChanged)
};
}
return _valueCommand; }
set{_valueCommand = value; }
}
其中CommandBase实现ICommand的接口
CanExecateChanged用来修改button的状态
ValueCommandAction用来获取不同按键的消息,从而做出不同的响应
3.3 MainWindow.xaml
更改title为计算器,字号30,改成黑底白字,透明,鼠标移动事件
Title="Calculator" FontSize="30" Height="420" Width="700" Background="Black" Opacity="0.8" AllowsTransparency="True" WindowStyle="None" MouseMove="Move_MouseMove" >
grid布局,分为两行两列
0行0列为标题
<StackPanel>
<TextBlock Margin="20,10,0,0" Text="Calcultor" FontSize="20" Foreground="White" />
</StackPanel>
0行1列为最小化按钮和关闭按钮
<StackPanel Margin="10,0,10,10" Grid.Column="1" Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="MinBtn" Width ="20" Height="20" Content="-" FontSize="10" Background="Black" Foreground="White" Click="MinBtn_Click"/>
<Button x:Name="CloseBtn" Width ="20" Height="20" Content="X" FontSize="10" Background="Black" Foreground="White" Click="Button_Click"/>
</StackPanel>
1行0列为计算器主要功能区
首先用一个TextBox作为输出显示
其次用不同的button来作为“+-*/”
等按键
1行1列为历史记录
用了两个TextBox,一个提示,一个显示历史记录
四、完整代码
4.1 CommandBase.cs
using System;
using System.Windows.Input;
namespace Calcultor
{
internal class CommandBase : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
// throw new NotImplementedException();
return DoCanExecute?.Invoke(parameter) == true;
}
public void Execute(object parameter)
{
// throw new NotImplementedException();
DoAction?.Invoke(parameter);
}
public Action<object> DoAction { get; set; }
public Func<object, bool> DoCanExecute { get; set; }
public void Raise()
{
CanExecuteChanged?.Invoke(this, new EventArgs());
}
}
}
4.2 MainWindow .xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Calcultor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
private void Move_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
this.DragMove();
}
}
private void MinBtn_Click(object sender, RoutedEventArgs e)
{
this.WindowState = System.Windows.WindowState.Minimized;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
}
4.3 MainWindow.xaml
<Window x:Class="Calcultor.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:Calcultor"
mc:Ignorable="d"
Title="Calculator" FontSize="30" Height="420" Width="700" Background="Black" Opacity="0.8" AllowsTransparency="True" WindowStyle="None" MouseMove="Move_MouseMove" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="11*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="450"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel>
<TextBlock Margin="20,10,0,0" Text="Calcultor" FontSize="20" Foreground="White" />
</StackPanel>
<StackPanel Margin="10,0,10,10" Grid.Column="1" Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="MinBtn" Width ="20" Height="20" Content="-" FontSize="10" Background="Black" Foreground="White" Click="MinBtn_Click"/>
<Button x:Name="CloseBtn" Width ="20" Height="20" Content="X" FontSize="10" Background="Black" Foreground="White" Click="Button_Click"/>
</StackPanel>
<StackPanel Grid.Column="0" Grid.Row="1">
<TextBox Text="{Binding Value}" Background="Black" Foreground="White" Margin="30,10,30,10" BorderThickness="0" Height="50" HorizontalAlignment="Right" />
<StackPanel Margin="30,0,30,0" Orientation="Horizontal" Width="390" Height="50" HorizontalAlignment="Center" >
<Button Command="{Binding ValueCommand}" CommandParameter="C" Background="Black" Foreground="White" Content="C" Margin="0,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="X" Background="Black" Foreground="White" Content="X" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="%" Background="Black" Foreground="White" Content="%" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="/" Background="Black" Foreground="White" Content="/" Margin="23,0,0,0" Width="80"/>
</StackPanel>
<StackPanel Margin="30,10,30,0" Orientation="Horizontal" Width="390" Height="50" HorizontalAlignment="Center" >
<Button Command="{Binding ValueCommand}" CommandParameter="7" Background="Black" Foreground="White" Content="7" Margin="0,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="8" Background="Black" Foreground="White" Content="8" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="9" Background="Black" Foreground="White" Content="9" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="*" Background="Black" Foreground="White" Content="*" Margin="23,0,0,0" Width="80"/>
</StackPanel>
<StackPanel Margin="30,10,30,0" Orientation="Horizontal" Width="390" Height="50" HorizontalAlignment="Center" >
<Button Command="{Binding ValueCommand}" CommandParameter="4" Background="Black" Foreground="White" Content="4" Margin="0,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="5" Background="Black" Foreground="White" Content="5" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="6" Background="Black" Foreground="White" Content="6" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="-" Background="Black" Foreground="White" Content="-" Margin="23,0,0,0" Width="80"/>
</StackPanel>
<StackPanel Margin="30,10,30,0" Orientation="Horizontal" Width="390" Height="50" HorizontalAlignment="Center" >
<Button Command="{Binding ValueCommand}" CommandParameter="1" Background="Black" Foreground="White" Content="1" Margin="0,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="2" Background="Black" Foreground="White" Content="2" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="3" Background="Black" Foreground="White" Content="3" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="+" Background="Black" Foreground="White" Content="+" Margin="23,0,0,0" Width="80"/>
</StackPanel>
<StackPanel Margin="30,10,30,0" Orientation="Horizontal" Width="390" Height="50" HorizontalAlignment="Center" >
<Button Command="{Binding ValueCommand}" CommandParameter="0" Background="Black" Foreground="White" Content="0" Margin="0,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="." Background="Black" Foreground="White" Content="." Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="^" Background="Black" Foreground="White" Content="^" Margin="23,0,0,0" Width="80"/>
<Button Command="{Binding ValueCommand}" CommandParameter="=" Background="Black" Foreground="White" Content="=" Margin="23,0,0,0" Width="80"/>
</StackPanel>
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="1">
<TextBox Text="历史记录" Background="Black" Foreground="White" Margin="0,0,20,0" BorderThickness="0" />
<TextBox Text="{Binding HistoryValue}" FontSize="15" Background="Black" Foreground="White" Margin="0,0,20,0" Height="330"/>
</StackPanel>
</Grid>
</Window>
4.4 MainViewModel .cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace Calcultor
{
public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _value = "0";
public string Value
{
get { return _value; }
set
{
_value = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
}
}
private ICommand _valueCommand = null;
public ICommand ValueCommand
{
get{
if (_valueCommand == null)
{
_valueCommand = new CommandBase()
{
DoAction = new Action<object>(ValueCommandAction),
DoCanExecute = new Func<object, bool>(CanExecateChanged)
};
}
return _valueCommand; }
set{_valueCommand = value; }
}
private bool CanExecateChanged(object arg)
{
if ((string)arg == "=") {
return true;
}
switch (arg){
case "C":
case ".":
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
return true;
}
return flag;
}
private void ValueCommandAction(object obj)
{
switch (obj) {
case ".":
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
if (Value == "0") {
Value = (string)obj;
}
else {
Value += (string)obj;
}
break;
case "+": {
flag = false;
no1 = Value;
Value += "+";
cha = "+";
} break;
case "-":
{
flag = false;
no1 = Value;
Value += "-";
cha = "-";
}
break;
case "*":
{
flag = false;
no1 = Value;
Value += "*";
cha = "*";
}
break;
case "/":
{
flag = false;
no1 = Value;
Value += "/";
cha = "/";
}
break;
case "%":
{
flag = false;
no1 = Value;
Value += "%";
cha = "%";
}
break;
case "^":
{
flag = false;
no1 = Value;
Value += "^";
cha = "^";
}
break;
case "X":
{
flag = false;
Value = Value.Substring(0, Value.Length - 1);
}
break;
case "=": {
flag = true;
if (string.IsNullOrEmpty(no1)) {
break;
}
no2 = Value.Substring(no1.Length+1);
Value+="=";
double n1, n2;
try {
n1 = Double.Parse(no1);
n2 = Double.Parse(no2);
}
catch (Exception e) {
Value = "0";
break;
}
switch (cha) {
case "+":
result = n1 + n2;
break;
case "-":
result = n1 - n2;
break;
case "*":
result = n1 * n2;
break;
case "/":
if (n2 == 0) {
MessageBox.Show("除数不可为0");
break;
}
result = n1 / n2;
break;
case "%":
result = n1 % n2;
break;
case "^":
result = Math.Pow(n1,n2);
break;
}
Value += result;
HistoryValue += Value;
HistoryValue += "\r\n";
break;
}
case "C":
{
flag = true;
Value = "0";
break;
}
}
}
private string no1 = "0";
private string no2 = "0";
private string cha = "";
private double result = 0 ;
private string _historyValue = "";
private bool flag = true;
public string HistoryValue
{
get { return _historyValue; }
set { _historyValue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("HistoryValue"));
}
}
}
}