You can start by separating business logic and UI

// CalculatorState is your model. Any calculation can take your model and modify it with a result or with an error message (divide by zero etc)
// this is the entire I/O signature of any calculation, you can expand to support history etc with minimum refactoring of other code.

 // model class
 public class CalculatorState : INotifyPropertyChanged /*IMPLEMENT, ON ALL PROPERTIES */ { 
 public bool IsError{get;set;}
 public string ErrorMessage{get;set;} 
 
 // Value is what's on the calculator screen under normal conditions
 public double Value {get;set;}
 
 // the calculator's memory
 private double? mem;
 public double Mem {
 get { return mem.GetValueOrDefault(Value); } 
 set { mem = value; }
 }
 }
 
 // VM component
 public class CalculatorCommand: ICommand<double?>{
 public CalculatorState State {get;set;}
 
 public readonly Action<CalculatorState, double?> Calculate;
 public readonly bool IsTwoOpCommand;
 
 public CalculatorCommand(Action<CalculatorState, double?> calculate, CalculatorState state = null, bool isTwoOpCommand = true){
 Calculate = calculate;
 State = state;
 IsTwoOpCommand = isTwoOpCommand;
 }
 
 public void Execute(double? prm){
 if (State!=null){
 if (Calculate!=null){
 // for two-op commands without a Mem put the Value in Mem 
 if (!IsTwoOpCommand || State.Mem.HasValue)
 Calculate(State);
 else
 State.Mem = State.Value;
 } else {
 State.IsError = true;
 State.ErrorMessage = "Null function";
 }
 } else // throw if you wish 
 Debug.WriteLine("Unexpected empty state");
 }
 }

 // View-Model, links your UI to the model
 public CalculatorVM : INotifyPropertyChanged {
 public readonly CalculatorState State;
 
 public readonly ICommand AddCommand;
 public readonly ICommand SubCommand;
 ....
 public readonly ICommand NumberCommand;
 
 public CalculatorVM(CalculatorState state){
 State = state;
 NumberCommand = new CalculatorCommand(c,p=>c.Value = c.Value*10 + p, State, false);
 SubCommand = new CalculatorCommand(c,p=>c.Value = c.Mem - c.Value, State);
 AddCommand = new CalculatorCommand(c,p=>c.Value = c.Mem + c.Value, State);
 }
 }

 // View (UI). If you did the rest of the work your UI class should be mostly empty,
 // most of the setup would be done in the declarative part (XAML) via bindings
 // this allows you to reuse your entire business logic, unit test included
 // when you decide to switch platforms (desktop, mobile, server)
 public CalculatorWindow: Window{
 
 public CalculatorWindow(){ 
 BindingContext = new CalculatorVM(new CalculatorState()); 
 InitializeComponent(); 
 }
 }

CalculatorWindow.xaml:

 <CalculatorWindow....>
 ...
 <TextBlock Text="{Binding State.Value}"/>
 ...
 <TextBlock Text="{Binding State.ErrorMessage}" Visibility="{Binding State.IsError, Converter={...bool-to-visible-converter}}"/>
 ...
 <Button Command="{Binding NumberCommand}" CommandParameter="0">0</Button> 
 ... 
 <Button Command="{Binding AddCommand}">+</Button> 
 </CalculatorWindow>