I have developed this simple desktop calculator with WPF. Just wondering, what do you guys think of my coding style of this side project and any code refactoring needed to reduce repeat code?
public partial class MainWindow : Window
{
double lastNumber;
string lastNumberString, selectedValue;
LastInputType lastInputType;
bool firstZero;
Button selectedBtn;
private void Init(bool isEqualPressed = false, bool isOperatorPressed = false)
{
if (!isEqualPressed)
resultLabel.Content = "0";
if (!isOperatorPressed)
resultLabelExp.Content = "";
// This reset is similar with after key in operator reset but without the above line
firstZero = false;
lastNumberString = "";
lastNumber = 0;
lastInputType = LastInputType.Operator;
}
public MainWindow()
{
InitializeComponent();
acButton.Click += AcButton_Click;
negativeButton.Click += NegativeButton_Click;
percentageButton.Click += PercentageButton_Click;
equalButton.Click += EqualButton_Click;
Init();
}
private void EqualButton_Click(object sender, RoutedEventArgs e)
{
if (resultLabelExp.Content.ToString().Trim() != "" && lastInputType != LastInputType.Operator)
{
resultLabel.Content = MathBodmas.EvalExpression(resultLabelExp.Content.ToString().ToCharArray()).ToString();
Init(true);
}
}
private void PercentageButton_Click(object sender, RoutedEventArgs e)
{
if (double.TryParse(resultLabel.Content.ToString(), out lastNumber))
{
lastNumber = lastNumber / 100;
resultLabel.Content = lastNumber.ToString();
}
}
private void NegativeButton_Click(object sender, RoutedEventArgs e)
{
if (double.TryParse(resultLabel.Content.ToString(), out lastNumber))
{
lastNumber = lastNumber * -1;
resultLabel.Content = lastNumber.ToString();
}
}
private void AcButton_Click(object sender, RoutedEventArgs e)
{
Init();
}
private void OperationButton_Click(object sender, RoutedEventArgs e)
{
selectedBtn = sender as Button;
selectedValue = selectedBtn.Content.ToString();
if (lastInputType == LastInputType.Operator)
{
if (resultLabelExp.Content.ToString() == "")
{
// Do nothing
}
else
{
ReplaceLastChar(selectedValue);
}
}
else
{
AppendExp(selectedValue);
}
Init(false, true);
}
private void DecimalButton_Click(object sender, RoutedEventArgs e)
{
selectedBtn = sender as Button;
selectedValue = selectedBtn.Content.ToString();
if (lastNumberString.Contains("."))
{
// Do nothing
}
else
{
if (lastNumberString == "")
{
lastNumberString += "0.".ToString();
resultLabelExp.Content += "0.".ToString();
}
else
{
// Append
AppendExp(selectedValue);
}
}
firstZero = false;
}
private void NumberButton_Click(object sender, RoutedEventArgs e)
{
selectedBtn = sender as Button;
selectedValue = selectedBtn.Content.ToString();
switch (lastInputType)
{
case LastInputType.Operator:
case LastInputType.Zero:
// firstZero value is assigned at Zero button click handler
if (firstZero)
{
ReplaceLastChar(selectedValue);
firstZero = false;
}
else
{
// Append
AppendExp(selectedValue);
}
break;
case LastInputType.Number:
// Append
AppendExp(selectedValue);
break;
default:
break;
}
lastInputType = LastInputType.Number;
}
private void ZeroButton_Click(object sender, RoutedEventArgs e)
{
selectedBtn = sender as Button;
selectedValue = selectedBtn.Content.ToString();
if (lastNumberString == "")
{
// First zero assigned
AppendExp(selectedValue);
firstZero = true;
// Do nothing
}
else if (lastNumberString.Length == 1 && lastNumberString == "0")
{
firstZero = true;
// Do nothing
// To block 00
}
else
{
// Append. i.e. 100
AppendExp(selectedValue);
}
lastInputType = LastInputType.Zero;
}
private void AppendExp(string _selectedValue)
{
lastNumberString += _selectedValue.ToString();
resultLabelExp.Content += _selectedValue.ToString();
}
private void ReplaceLastChar(string _selectedValue)
{
// Replace
lastNumberString = _selectedValue;
// Extract whole string without last char using substring.
resultLabelExp.Content = resultLabelExp.Content.ToString().Substring(0, resultLabelExp.Content.ToString().Length - 1);
resultLabelExp.Content += lastNumberString;
}
}
public enum LastInputType
{
Zero, Number, Operator
}
Full source is available at my github - https://github.com/ngaisteve1/CalculatorWPF
XAML file as requested
<Window x:Class="Calculator.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:Calculator"
mc:Ignorable="d"
Title="MainWindow" Height="525" Width="350">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label x:Name="resultLabelExp"
Content="0"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Grid.ColumnSpan="4" FontSize="30"
Foreground="Gray" />
<Label x:Name="resultLabel"
Content="0"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Grid.ColumnSpan="4" FontSize="40"
Grid.Row="1"/>
<Button x:Name="acButton"
Style="{StaticResource additionalButtonsStyle}"
Content="AC"
Grid.Row="2"/>
<Button x:Name="negativeButton"
Style="{StaticResource additionalButtonsStyle}"
Content="+/-"
Grid.Row="2"
Grid.Column="1" IsEnabled="False"/>
<Button x:Name="percentageButton"
Style="{StaticResource additionalButtonsStyle}"
Content="%"
Grid.Row="2"
Grid.Column="2" IsEnabled="False"/>
<Button x:Name="divisionButton"
Click="OperationButton_Click"
Style="{StaticResource operatorButtonsStyle}"
Content="/"
Grid.Row="2"
Grid.Column="3"/>
<Button x:Name="sevenButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="7"
Grid.Row="3"/>
<Button x:Name="eightButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="8"
Grid.Row="3"
Grid.Column="1"/>
<Button x:Name="nineButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="9"
Grid.Row="3"
Grid.Column="2"/>
<Button x:Name="multiplicationButton"
Click="OperationButton_Click"
Style="{StaticResource operatorButtonsStyle}"
Content="*"
Grid.Row="3"
Grid.Column="3"/>
<Button x:Name="fourButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="4"
Grid.Row="4"/>
<Button x:Name="fiveButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="5"
Grid.Row="4"
Grid.Column="1"/>
<Button x:Name="sixButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="6"
Grid.Row="4"
Grid.Column="2"/>
<Button x:Name="minusButton"
Click="OperationButton_Click"
Style="{StaticResource operatorButtonsStyle}"
Content="-"
Grid.Row="4"
Grid.Column="3"/>
<Button x:Name="oneButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="1"
Grid.Row="5"/>
<Button x:Name="twoButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="2"
Grid.Row="5"
Grid.Column="1"/>
<Button x:Name="threeButton"
Click="NumberButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="3"
Grid.Row="5"
Grid.Column="2"/>
<Button x:Name="plusButton"
Click="OperationButton_Click"
Style="{StaticResource operatorButtonsStyle}"
Content="+"
Grid.Row="5"
Grid.Column="3"/>
<Button x:Name="zeroButton"
Click="ZeroButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="0"
Grid.Row="6"
Grid.ColumnSpan="2"/>
<Button x:Name="pointButton"
Click="DecimalButton_Click"
Style="{StaticResource numberButtonsStyle}"
Content="."
Grid.Row="6"
Grid.Column="2" IsEnabled="true"/>
<Button x:Name="equalButton"
Style="{StaticResource operatorButtonsStyle}"
Content="="
Grid.Row="6"
Grid.Column="3"/>
</Grid>
In progress to change to stack to improve performance.