\$\begingroup\$
\$\endgroup\$
3
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.
Steve NgaiSteve Ngai
asked May 29, 2019 at 10:21
-
1\$\begingroup\$ What is MathBodmas? And could you also paste the designer code? \$\endgroup\$dfhwze– dfhwze2019年05月29日 10:36:52 +00:00Commented May 29, 2019 at 10:36
-
4\$\begingroup\$ You should apply MVVM: c-sharpcorner.com/UploadFile/nipuntomar/mvvm-in-wpf , intellitect.com/… , intellitect.com/… , stackoverflow.com/questions/1405739/… , etc. \$\endgroup\$BCdotWEB– BCdotWEB2019年05月29日 10:44:45 +00:00Commented May 29, 2019 at 10:44
-
\$\begingroup\$ MathBodmas is the class which has some method to evaluate math string according to Bodmas sequence. Anyway, that class is from a third party source \$\endgroup\$Steve Ngai– Steve Ngai2019年05月29日 13:26:01 +00:00Commented May 29, 2019 at 13:26
1 Answer 1
\$\begingroup\$
\$\endgroup\$
5
Tips
- Use the M-V-VM pattern when designing WPF applications.
- Post all the code you want to get reviewed, even if a link is provided.
Cleanup Your Code
- Don't make empty clauses just for comments.
- Don't add comments when the code is self-explaining.
- Don't check
string
against""
. - Don't call an irrelevant
.ToString()
onstring
.
snippet 1
if (lastInputType == LastInputType.Operator) { if (resultLabelExp.Content.ToString() == "") { // Do nothing } else { ReplaceLastChar(selectedValue); } } else { AppendExp(selectedValue); }
if (lastInputType == LastInputType.Operator)
{
if (resultLabelExp.Content.ToString().Any())
{
ReplaceLastChar(selectedValue);
}
}
else
{
AppendExp(selectedValue);
}
snippet 2
if (lastNumberString.Contains(".")) { // Do nothing } else { if (lastNumberString == "") { lastNumberString += "0.".ToString(); resultLabelExp.Content += "0.".ToString(); } else { // Append AppendExp(selectedValue); } }
if (!lastNumberString.Contains("."))
{
if (!lastNumberString.Any())
{
lastNumberString += "0.";
resultLabelExp.Content += "0.";
}
else
{
AppendExp(selectedValue);
}
}
answered May 29, 2019 at 11:13
-
\$\begingroup\$ Thanks a lot for the code review. Appreciate it. \$\endgroup\$Steve Ngai– Steve Ngai2019年05月29日 13:22:33 +00:00Commented May 29, 2019 at 13:22
-
4\$\begingroup\$ Personally I think replacing
str == ""
with!str.Any()
makes the intent of the code less clear. If you must replace it, then I'd go forstring.IsNullOrEmpty(str)
instead. \$\endgroup\$Pieter Witvoet– Pieter Witvoet2019年05月29日 13:52:25 +00:00Commented May 29, 2019 at 13:52 -
1\$\begingroup\$ @PieterWitvoet I thought about the IsNullOrEmpty, but right before there is another check on the object. So checking Is'Null'OrEmpty seemed a bit stupid purely from a semantic point of view. \$\endgroup\$dfhwze– dfhwze2019年05月29日 15:15:10 +00:00Commented May 29, 2019 at 15:15
-
\$\begingroup\$ Just wondering why MVVM is needed for Calculator? I mean the Model layer. \$\endgroup\$Steve Ngai– Steve Ngai2019年05月30日 01:00:33 +00:00Commented May 30, 2019 at 1:00
-
1\$\begingroup\$ @Steve MathBodmas is your model layer. \$\endgroup\$dfhwze– dfhwze2019年05月30日 08:11:31 +00:00Commented May 30, 2019 at 8:11
lang-cs