c# - Handle control events differently depending on the state of the system -


i have trying build simulator of ingenico pos terminal (iwl220). main screen have combo-box. once user enter id , password combo-box load 6 menus. if user click btn1 combo-box clear menu , add set of menu. if user click btn1 new loaded menu again combo-box cleared , load set of menu on.

my problem each button click (btn1, btn2, btn3, btn4, btn5) have code lot of if else statement. example;

first menu (on combo-box) has 6 sector.

  • 1.sectora
  • 2.sectorb
  • 3.sectorc
  • 4.sectord
  • 5.sectore
  • 6.sectorf

if user choose 1.sectora user click btn1. btn1 clear combo-box , loads set of menu. time menu (on combo-box) has 3 companies.

  • 1.companya
  • 2.companyb
  • 3.companyc

this time user choose 1.companya user click again btn1. btn1 clear combo-box , loads set of menu. time menu (on combo-box) has 2 payment option.

  • 1.fullpayment
  • 2.paritalpayment

now time if user click btn1 or btn2 combo-box visible become false , in main screen there label , text box. text box allows user enter subscriber number , press enter (green button).

i load ingenico terminal picture jpeg , top of set buttons. gave small version of simulation. in app there 114 probability user can choose.

in app btn1 has 92 probability clicked, btn2 has 53 probability clicked , on. after user enters subscriber number , click green button app use wfc services format data , send sql server. before user click each combination of button in app store btn number 422. 422 means, user chose sectord + companyb + paritalpayment option. wfc know mean 422.

my question shortest way construct button events 114 probability case?


i have 4 buttons. btn1, btn2, btn3 , btn4. have arrays shown below , 1 combo-box.

1.arraymain() = {“1.water”,”2.air”,”3.soil”,”4.fire”}    1.1. arraywater() = {“1.salty”,”2.fresh”, “3.contaminated”}       1.1.1.arraysalty() = {1.”aa”, 2.”bb”, 3.”cc”}       1.1.2.arrayfresh() = {1.”dd”, 2.”ee”, 3.”ff”}       1.1.3.arraycontaminated() = {1.”xx”, 2.”yy”, 3.”zz”}                                1.2   arrayair() = {“1.fresh”, “2.contaminated”} 1.3   arraysoil() = {“1.normal”, “2.contaminated”} 1.4   arrayfire() = {“1.low”,”2.mid”,”3.high”} 

when app starts, first array values 1.(arraymain) fills combobox. combobox have 4 values as, “1.water”, ”2.air”, ”3.soil”, ”4.fire” in it. if user choose “1.water” user clicks btn1. btn1 events clears combobox , loads 1.1arraywater() values combobox.

second time if user chooses “1.salty” user clicks again btn1 , time btn1 events clears combobox , loads 1.1.1arraysalty() values combobox.

third time if user chooses “2.bb” user clicks btn2 , sends information “bb” calculation.

change combobox values button selection

first have 5 (more or less) menu item , each time press (number) buttons (1 9 lilke in pos terminal) pressed new menu appears on screen.

each button @ specific time shall execute specific action depending on state of system. obviously, if try decide specific action depending on multitude of different variables, create lot of branching code. such code difficult write correctly , more difficult debug , maintain.

so, if encapsulate current action each possible state(sequence of state) in specific class (interface):

/// <summary> /// represents internal terminal presenter used inside iglobalterminalpresenter. /// </summary> public interface iterminalpresenter {     void updateui();     iterminalpresenter this[int32 index]     {         get;     }     iterminalpresenter do1();     iterminalpresenter do2();     iterminalpresenter parent     {         get;         set;     }     void reset(); } 

inside form use field of similar interface encapsulate changes of presenter.

/// <summary> /// represents terminal presenter ui can operate upon. /// </summary> public interface iglobalterminalpresenter {     void updateui();      void do1();      void do2();      int32 selectedindex     {         get;         set;     }      void reset(); } 

our event handlers become:

    private void combobox_selectedindexchanged(object sender, eventargs e)     {         var sendercombobox = (combobox)sender;          this.globalterminalpresenter.selectedindex = sendercombobox.selectedindex;     }      private void button1_click(object sender, eventargs e)     {         this.globalterminalpresenter.do1();     }      private void button2_click(object sender, eventargs e)     {         this.globalterminalpresenter.do2();     } 

to allow our concrete terminalpresenters interoperate form force our form implement following interface:

/// <summary> /// represents ui in technology-independent manner /// </summary> public interface iterminalview {     string title { get; set; }     string input { get; set; }     string output { get; set; }     string button1_text { get; set; }     string button2_text { get; set; }     ienumerable<string> selectionitems { get; set; }     void clear(); }  public partial class mainform : form,     iterminalview {     ...     #region iterminalview implementation      public string title     {         { return this.text; }         set { this.text = value; }     }      public string button1_text     {         { return this.button1.text; }         set { this.button1.text = value; }     }      public string button2_text     {         { return this.button2.text; }         set { this.button2.text = value; }     }      public string input     {         { return this.textbox_input.text; }         set { this.textbox_input.text = value; }     }      public string output     {         { return this.textbox_output.text; }         set { this.textbox_output.text = value; }     }      public ienumerable<string> selectionitems     {         { return this.combobox.items.cast<string>(); }         set         {              this.combobox.items.clear();              if (value == null)                 return;              foreach (var item in value)             {                 this.combobox.items.add(item);             }         }     }      public void clear()     {         this.combobox.selectedindex = -1;         this.title = string.empty;         this.input = string.empty;         this.output = string.empty;         this.selectionitems = null;     }      #endregion 

for create 2 terminalpresenters - 1 allow selection of next option through combobox, 1 calculates sum of 2 numbers. both of them use same base class.

/// <summary> /// base class presenters /// </summary> public abstract class terminalpresenterbase : iterminalpresenter {     protected iterminalview view;      public terminalpresenterbase(iterminalview view)     {         if (view == null)              throw new argumentnullexception("view");          this.view = view;         this.parent = this;     }      public abstract void updateui();      public abstract iterminalpresenter this[int index]     {         get;     }      public abstract iterminalpresenter do1();     public abstract iterminalpresenter do2();      public virtual iterminalpresenter parent     {         get;         set;     }      public virtual void reset()     {         this.updateui();     } }  /// <summary> /// presenter sole goal allow user select other option , press next /// </summary> public class selectoptionpresenter : terminalpresenterbase {     private ilist<keyvaluepair<string, iterminalpresenter>> options;     private iterminalpresenter selected;     private string title;      public selectoptionpresenter(iterminalview view,         string title,          ilist<keyvaluepair<string, iterminalpresenter>> options)         : base(view)     {         if (options == null)             throw new argumentnullexception("options");          this.title = title;          this.options = options;          foreach (var item in options)         {             item.value.parent = this;         }     }      public override void updateui()     {         this.view.clear();          this.view.button1_text = "confirm selection";         this.view.button2_text = "go back";         this.view.title = title;         this.view.selectionitems = options             .select(opt => opt.key);     }      public override iterminalpresenter this[int index]     {                 {             this.selected = this.options[index].value;              return this;         }     }      public override iterminalpresenter do1()     {         return this.confirmselection();     }      public override iterminalpresenter do2()     {         return this.goback();     }      public iterminalpresenter confirmselection()     {         this.selected.updateui();         return this.selected;     }      public iterminalpresenter goback()     {         this.parent.updateui();         return this.parent;     } }  public enum aplusbstate {     entera,     enterb,     result }  public class stepactions {     public action updateui { get; set; }      public func<iterminalpresenter> do1 { get; set; }      public func<iterminalpresenter> do2 { get; set; } }  public class aplusbpresenter : terminalpresenterbase {     private int32 a, b;     private aplusbstate state;     private string error = null;      private dictionary<aplusbstate, stepactions> stateactions;      private void initializestateactions()     {         this.stateactions = new dictionary<aplusbstate, stepactions>();          this.stateactions.add(aplusbstate.entera,             new stepactions()             {                 updateui = () =>                 {                     this.view.title = this.error ?? "enter a";                     this.view.input = this.a.tostring();                     this.view.button1_text = "confirm a";                     this.view.button2_text = "exit";                 },                 do1 = () => // confirm                 {                     if (!int32.tryparse(this.view.input, out this.a))                     {                         this.error = "a in incorrect format. enter again";                         return this;                     }                      this.error = null;                                          this.state = aplusbstate.enterb;                      return this;                 },                 do2 = () => // exit                 {                     this.reset();                      return this.parent;                 }             });          this.stateactions.add(aplusbstate.enterb,             new stepactions()             {                 updateui = () =>                 {                     this.view.title = this.error ?? "enter b";                     this.view.input = this.b.tostring();                     this.view.button1_text = "confirm b";                     this.view.button2_text = "back a";                 },                 do1 = () => // confirm b                 {                     if (!int32.tryparse(this.view.input, out this.b))                     {                         this.error = "b in incorrect format. enter b again";                         return this;                     }                      this.error = null;                                          this.state = aplusbstate.result;                      return this;                 },                 do2 = () => //                 {                     this.state = aplusbstate.entera;                      return this;                 }             });          this.stateactions.add(aplusbstate.result,             new stepactions()             {                 updateui = () =>                 {                     this.view.title = string.format("the result of {0} + {1}", this.a, this.b);                     this.view.output = (this.a + this.b).tostring();                     this.view.button1_text = "exit";                     this.view.button2_text = "back";                 },                 do1 = () => // exit                 {                     this.reset();                      return this.parent;                 },                 do2 = () => // b                 {                     this.state = aplusbstate.enterb;                      return this;                 }             });     }      public aplusbpresenter(iterminalview view) : base(view)     {         this.initializestateactions();         this.reset();     }      public override void updateui()     {         this.view.clear();          this.stateactions[this.state].updateui();     }      public override iterminalpresenter this[int index]     {         { throw new notimplementedexception(); }     }      public override iterminalpresenter do1()     {         var nextpresenter = this.stateactions[this.state].do1();          nextpresenter.updateui();          return nextpresenter;     }      public override iterminalpresenter do2()     {         var nextpresenter = this.stateactions[this.state].do2();          nextpresenter.updateui();          return nextpresenter;     }      public override void reset()     {         this.state = aplusbstate.entera;         this.a = 0;         this.b = 0;         this.error = null;     } }  /// <summary> /// represents terminal presenter use inside gui. handles current ispecificterminalpresenter inside itself. /// </summary> public class globalterminalpresenter : iglobalterminalpresenter {     #region fields      private iterminalpresenter current;     private int32 selectedindex;      #endregion       #region constructors      public globalterminalpresenter(iterminalpresenter mainpresenter)     {         if (mainpresenter == null)             throw new argumentnullexception("mainpresenter");          this.current = mainpresenter;          this.updateui();     }      #endregion      public void updateui()     {         this.current.updateui();     }      public void do1()     {         this.current = this.current.do1();     }      public void do2()     {         this.current = this.current.do2();     }      public int32 selectedindex     {                 {             return this.selectedindex;         }         set         {             this.selectedindex = value;              if (value == -1)                 return;              this.current = this.current[value];         }     }      public void reset()     {         this.current.reset();     } } 

then initialize them in constructor of our form:

public partial class mainform : form,     iterminalview {     private iglobalterminalpresenter globalterminalpresenter;      public mainform()     {         initializecomponent();          var nextlevelpresenters = new keyvaluepair<string, iterminalpresenter>[]         {             new keyvaluepair<string, iterminalpresenter>(                 "a plus b",                  new aplusbpresenter(this)),             new keyvaluepair<string, iterminalpresenter>(                 "just empty selector",                  new selectoptionpresenter(this,                      "selector no selection choices",                      enumerable                         .empty<keyvaluepair<string, iterminalpresenter>>()                         .toarray()))         };          var toppresenter = new selectoptionpresenter(this, "select option , press confirm button",  nextlevelpresenters);          this.globalterminalpresenter = new globalterminalpresenter(toppresenter);     } 

p.s.1: these code snippets assume have form named mainform has 2 buttons - button1, button2, 1 combobox, 2 textboxes - textbox_input, textbox_output.

p.s.2: pattern used close enough model-view-presenter, without databindings.

p.s.3 can create more or less generic state machine presenters if modify aplusbpresenter code. or try shape chainxxxx... classes , interfaces.

p.s.4: , sorry these walls of code. that's [so] format, i've put ad-hoc proof of concept @ github - https://github.com/podskal/stackoverflow_29870164.git. ugly in many aspects, is, can @ least give few ideas how implement own system.

p.s.5: there lot of problematic places in code, should consider how build own system it.


Comments

Popular posts from this blog

asp.net mvc - SSO between MVCForum and Umbraco7 -

Python Tkinter keyboard using bind -

ubuntu - Selenium Node Not Connecting to Hub, Not Opening Port -