Building a custom .NET calculator control from scratch allows you to create a reusable visual component that processes mathematical expressions directly within your desktop or web applications. You can achieve this by separating your project into two distinct parts: a UI Layout (the buttons and display) and a Parsing Engine (the mathematical logic).
Below is a comprehensive guide to building a custom calculator control using WPF (Windows Presentation Foundation) and C#, which provides the best framework for custom control authoring via data binding. 1. Structure the Calculation Engine
Instead of using fragile string manipulation, utilize a stack-based algorithm or an expression evaluator to process inputs. A robust method is to use the Shunting-Yard algorithm to parse strings into Reverse Polish Notation (RPN), or leverage existing .NET capabilities like DataTable.Compute for simple evaluations.
Here is a clean implementation of an evaluation engine using standard .NET libraries:
using System; using System.Data; namespace CustomCalculatorControl { public class CalculatorEngine { private readonly DataTable _table = new DataTable(); public double Evaluate(string expression) { try { // Sanitize input to handle standard math symbols string sanitized = expression.Replace(“×”, “”).Replace(“÷”, “/”); object result = _table.Compute(sanitized, “”); return Convert.ToDouble(result); } catch { throw new InvalidOperationException(“Syntax Error”); } } } } Use code with caution. 2. Design the Custom Control UI
In WPF, you create a custom control by defining a UserControl. This allows you to bundle the XAML layout and the C# code-behind into a single, reusable package. XAML Layout (CalculatorControl.xaml) Use a Grid layout to align your buttons cleanly.
Use code with caution. 3. Implement Interaction Logic
The code-behind hooks up the UI events to the calculator engine. It manages the current state of the display string and handles errors safely. Code-Behind (CalculatorControl.xaml.cs)
using System; using System.Windows; using System.Windows.Controls; namespace CustomCalculatorControl { public partial class CalculatorControl : UserControl { private readonly CalculatorEngine _engine = new CalculatorEngine(); private bool _isNewEquation = true; public CalculatorControl() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { Button button = (Button)sender; string value = button.Content.ToString(); if (_isNewEquation) { // Clear the default zero unless appending an operator if (char.IsDigit(value[0]) || value == “(”) { DisplayBox.Text = “”; } _isNewEquation = false; } DisplayBox.Text += value; } private void Button_Clear_Click(object sender, RoutedEventArgs e) { DisplayBox.Text = “0”; _isNewEquation = true; } private void Button_Equal_Click(object sender, RoutedEventArgs e) { try { double result = _engine.Evaluate(DisplayBox.Text); DisplayBox.Text = result.ToString(); } catch (Exception) { DisplayBox.Text = “Error”; } finally { _isNewEquation = true; } } } } Use code with caution. 4. Expose the Result via Dependency Properties
To make this control truly reusable, you must allow host applications to read the calculation result. You can achieve this by implementing a Dependency Property so other developers can bind to your calculator output.
Add this dependency property inside your CalculatorControl class:
public static readonly DependencyProperty CurrentResultProperty = DependencyProperty.Register(“CurrentResult”, typeof(string), typeof(CalculatorControl), new PropertyMetadata(“0”)); public string CurrentResult { get { return (string)GetValue(CurrentResultProperty); } set { SetValue(CurrentResultProperty, value); } } // Update this property inside your Button_Equal_Click method: // SetValue(CurrentResultProperty, DisplayBox.Text); Use code with caution. 5. Consume the Control in an Application
Once built, you can instantiate your custom calculator control inside any window layout of your application.
Use code with caution. ✅ Summary of Best Practices
Separate concerns: Keep your UI layout logic completely isolated from the mathematical calculation engine.
Leverage Grid/UniformGrid: Avoid absolute positioning so that your control scales gracefully when resized by a parent application.
Expose data bindings: Always use DependencyProperties instead of standard properties to allow data interaction with other .NET views.
If you would like to explore this further, let me know if you want to add keyboard support, implement MVVM architecture, or learn how to compile this into a standalone NuGet package Class Library.
Leave a Reply