Skip to main content
added 133 characters in body
Source Link

MVVM pattern

YouThis pattern can start by separatinghelp you separate business logic and UI in a clear and testable manner.

You can start by separating business logic and UI

MVVM pattern

This pattern can help you separate business logic and UI in a clear and testable manner.

added 8 characters in body
Source Link
Heslacher
  • 50.4k
  • 5
  • 81
  • 175

CalculatorStateCalculatorState and CalculatorLogicCalculatorLogic is your model/BL and it can be made shareable. Any calculation can take your model and modify it with a result or with an error message (divide by zero etc). It represents the entire I/O of your business logic (calculation on a calculator), you could expand it to support new features, such as history, with minimum refactoring of other code.

CalculatorWindow/xamlCalculatorWindow/xaml is your UI, this is the visible part of your code

CalculatorVMCalculatorVM is the glue between UI and model.

CalculatorState and CalculatorLogic is your model/BL and it can be made shareable. Any calculation can take your model and modify it with a result or with an error message (divide by zero etc). It represents the entire I/O of your business logic (calculation on a calculator), you could expand it to support new features, such as history, with minimum refactoring of other code.

CalculatorWindow/xaml is your UI, this is the visible part of your code

CalculatorVM is the glue between UI and model.

CalculatorState and CalculatorLogic is your model/BL and it can be made shareable. Any calculation can take your model and modify it with a result or with an error message (divide by zero etc). It represents the entire I/O of your business logic (calculation on a calculator), you could expand it to support new features, such as history, with minimum refactoring of other code.

CalculatorWindow/xaml is your UI, this is the visible part of your code

CalculatorVM is the glue between UI and model.

added 519 characters in body
Source Link

// CalculatorState and CalculatorLogic is your model/BL and it can be made shareable. Any calculation can take your model and modify it with a result or with an error message (divide by zero etc) // this is. It represents the entire I/O signature of any calculationyour business logic (calculation on a calculator), you cancould expand it to support new features, such as history etc, with minimum refactoring of other code.

CalculatorWindow/xaml is your UI, this is the visible part of your code

CalculatorVM is the glue between UI and model.

// 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; }
  }
}

// business logic
public static class CalculatorLogic{
  public static readonly Action<CalculatorState, double?> Add = (state,prm)=>state.Value = state.Mem + state.Value;
  public static readonly Action<CalculatorState, double?> Sub = (state,prm)=>state.Value = state.Mem - state.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 - cCalculatorLogic.Value,Sub State);
    AddCommand = new CalculatorCommand(c,p=>c.Value = c.Mem + cCalculatorLogic.ValueAdd, 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(); 
  }
}

// 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(); 
  }
}

CalculatorState and CalculatorLogic is your model/BL and it can be made shareable. Any calculation can take your model and modify it with a result or with an error message (divide by zero etc). It represents the entire I/O of your business logic (calculation on a calculator), you could expand it to support new features, such as history, with minimum refactoring of other code.

CalculatorWindow/xaml is your UI, this is the visible part of your code

CalculatorVM is the glue between UI and model.

// 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; }
  }
}

// business logic
public static class CalculatorLogic{
  public static readonly Action<CalculatorState, double?> Add = (state,prm)=>state.Value = state.Mem + state.Value;
  public static readonly Action<CalculatorState, double?> Sub = (state,prm)=>state.Value = state.Mem - state.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(CalculatorLogic.Sub State);
    AddCommand = new CalculatorCommand(CalculatorLogic.Add, 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(); 
  }
}
Source Link
Loading