2015-04-25 3 views
3

Я пытаюсь построить симулятор терминала Ingenico POS (iWL220). На главном экране у меня есть комбинированная коробка. Когда пользователь вводит идентификатор и пароль, в поле со списком загружаются 6 меню. Если пользователь нажмет на btn1, то в поле со списком очистите меню и добавьте еще один набор меню. Если пользователь нажмет btn1 для нового загруженного меню, затем снова будет снято поле со списком и загрузится другой набор меню и далее.Управление событиями управления по-разному в зависимости от состояния системы

Моя проблема заключается в каждом нажатии кнопки (btn1, btn2, btn3, btn4, btn5) Мне нужно закодировать много команд if else. Пример;

Первое меню (на комбинированном поле) имеет 6 секторов.

  • 1.SectorA
  • 2.SectorB
  • 3.SectorC
  • 4.SectorD
  • 5.SectorE
  • 6.SectorF

Если пользователь может выбрать 1. SectorA, затем нажмите кнопку btn1. Затем btn1 очистите поле со списком и загрузите другой набор меню. В этом меню времени (на комбинированном поле) есть 3 компании.

  • 1.CompanyA
  • 2.CompanyB
  • 3.CompanyC

На этот раз пользователь может выбрать 1.CompanyA затем пользователь нажмет снова btn1. Затем btn1 очистите поле со списком и загрузите другой набор меню. Это меню времени (в комбинированном поле) имеет 2 варианта оплаты.

  • 1.FullPayment
  • 2.ParitalPayment

Теперь это время, если пользователь нажмет btn1 или btn2 поле со списком видны становятся ложными и в главном экране появляется окно этикетки и текст. Текстовое поле позволяет пользователю ввести номер абонента и нажать Enter (зеленая кнопка).

Я уже загрузил изображение терминала Ingenico как jpeg и его верх. Я установил свои кнопки. Я дал только небольшую версию моего моделирования. В моем приложении есть вероятность, которую пользователь может выбрать.

В моем приложении btn1 есть вероятность 92 щелчка, btn2 имеет 53 вероятности щелчка и так далее. После того, как пользователь вводит номер абонента и щелкает зеленую кнопку, мое приложение использует службы wfc для форматирования данных и отправки на сервер sql. Но прежде чем пользователь нажимает каждую комбинацию кнопок, где в моем приложении я храню номер btn как 422. Это 422 означает, что пользователь выбрал вариант SectorD + CompanyB + ParitalPayment. Итак, мой wfc будет знать, что это значит. 422.

Мой вопрос - это самый короткий способ построить события с кнопками для этого вероятностного случая?


У меня есть 4 кнопки. Btn1, Btn2, Btn3 и Btn4. Также у меня есть несколько массивов, как показано ниже, и 1 комбинированная коробка.

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”} 

При запуске мое приложение, первый массив значений 1.(ArrayMain) заполняет ComboBox. Этот comboBox будет иметь 4 значения как «1.Water», «2.Air», «3.Soil», «4.Fire». Если пользователь выбирает «1.Water», то пользователь нажимает Btn1. Чем события btn1 очищают comboBox и загружают значения 1.1ArrayWater() в comboBox.

Второй раз, когда пользователь выбирает «1.Salty», чем пользователь нажимает повторно btn1, и на этот раз события btn1 очищают comboBox и загружают значения 1.1.1ArraySalty() в comboBox.

В третий раз, если пользователь выбирает «2.BB», чем пользователь нажимает Btn2 и отправляет информацию «BB» для расчета.

Change ComboBox Values with button selection

Во-первых у вас есть 5 (более или менее) пункта меню и каждый раз при нажатии любой кнопки (числа) (от 1 до 9 lilke в POS-терминале) прессованную, чем новое меню появляется на экране.

+0

Отметьте этот ответ: http://stackoverflow.com/a/10061705/1308385 – jimutt

+0

спасибо, я посмотрю позже. Моя проблема заключается в том, что я уже добавил кнопки вручную и установил транс-цвет и загруженное изображение, чтобы пользователь мог упасть, как ввод фактических терминальных кнопок терминала. – NTMS

+0

@ user3362234 Я изменил свой ответ, включив в него почти полный пример. Кроме того, я вернул свой последний вопрос, чтобы вернуть ваш вопрос к более упорядоченному виду. –

ответ

3

Каждая кнопка в любое конкретное время должна выполнять определенное действие в зависимости от состояния системы. Очевидно, что если вы попытаетесь определить конкретное действие в зависимости от множества различных переменных, вы создадите много разветвляющихся кодов. Такой код очень сложно правильно писать и даже сложнее отлаживать и поддерживать.

Итак, что если мы инкапсулировать текущее действие для каждого возможного состояния (последовательность состояния) в какой-то конкретный класс (интерфейс):

/// <summary> 
/// Represents internal terminal presenter that is used inside IGlobalTerminalPresenter. 
/// </summary> 
public interface ITerminalPresenter 
{ 
    void UpdateUI(); 
    ITerminalPresenter this[Int32 index] 
    { 
     get; 
    } 
    ITerminalPresenter Do1(); 
    ITerminalPresenter Do2(); 
    ITerminalPresenter Parent 
    { 
     get; 
     set; 
    } 
    void Reset(); 
} 

Внутри формы мы будем использовать поле подобного интерфейса, который будет инкапсулировать все изменения ведущего.

/// <summary> 
/// Represents terminal presenter that UI can operate upon. 
/// </summary> 
public interface IGlobalTerminalPresenter 
{ 
    void UpdateUI(); 

    void Do1(); 

    void Do2(); 

    Int32 SelectedIndex 
    { 
     get; 
     set; 
    } 

    void Reset(); 
} 

Наших обработчиков событий станет:

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

Чтобы разрешить наше конкретное TerminalPresenters взаимодействовать с формой мы заставим нашу форму реализовать следующий интерфейс:

/// <summary> 
/// This represents your 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 
    { 
     get { return this.Text; } 
     set { this.Text = value; } 
    } 

    public String Button1_Text 
    { 
     get { return this.button1.Text; } 
     set { this.button1.Text = value; } 
    } 

    public String Button2_Text 
    { 
     get { return this.button2.Text; } 
     set { this.button2.Text = value; } 
    } 

    public string Input 
    { 
     get { return this.textBox_Input.Text; } 
     set { this.textBox_Input.Text = value; } 
    } 

    public string Output 
    { 
     get { return this.textBox_Output.Text; } 
     set { this.textBox_Output.Text = value; } 
    } 

    public IEnumerable<string> SelectionItems 
    { 
     get { 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 

В настоящее время мы создаст два TerminalPresenters - один, чтобы просто разрешить выбор следующей опции через combobox, который вычисляет сумму двух чисел. Оба они используют один и тот же базовый класс.

/// <summary> 
/// Base class for all 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 whose sole goal is to allow user to select some other option and 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] 
    { 
     get 
     { 
      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 A 
       { 
        if (!Int32.TryParse(this.view.Input, out this.a)) 
        { 
         this.error = "A is in incorrect format. Enter A 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 to A"; 
       }, 
       Do1 =() => // Confirm B 
       { 
        if (!Int32.TryParse(this.view.Input, out this.b)) 
        { 
         this.error = "B is in incorrect format. Enter B again"; 
         return this; 
        } 

        this.error = null;      
        this.state = APlusBState.Result; 

        return this; 
       }, 
       Do2 =() => // Back to a 
       { 
        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 =() => // Back to 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] 
    { 
     get { 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 to use inside GUI. It 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 
    { 
     get 
     { 
      return this.selectedIndex; 
     } 
     set 
     { 
      this.selectedIndex = value; 

      if (value == -1) 
       return; 

      this.current = this.current[value]; 
     } 
    } 

    public void Reset() 
    { 
     this.current.Reset(); 
    } 
} 

Затем мы инициализируем их в конструкторе форму:

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 with no selection choices", 
        Enumerable 
         .Empty<KeyValuePair<String, ITerminalPresenter>>() 
         .ToArray())) 
     }; 

     var topPresenter = new SelectOptionPresenter(this, "Select the option and press the confirm button", nextLevelPresenters); 

     this.globalTerminalPresenter = new GlobalTerminalPresenter(topPresenter); 
    } 

PS1: Эти фрагменты кода Предположим, что вы назвали формы MainForm, который имеет две кнопки - Button1, button2, один combobox, два текстовых поля - textBox_Input, textBox_Output.

P.S.2: Образец используется достаточно близко к Model-View-Presenter, без DataBindings.

P.S.3 Вы можете создать более или менее общий конечный автомат. Если вы измените код APlusBPresenter. Или попробуйте сформировать классы и интерфейсы ChainXxxx....

P.S.4: И извините за эти стены кода. Это, наверное, слишком много для формата [SO], поэтому я внедрил ad-hoc доказательство концепции в GitHub - https://github.com/Podskal/StackOverflow_29870164.git. Это уродливо во многих аспектах, но, как есть, он может по крайней мере дать несколько идей о том, как реализовать свою собственную систему.

P.S.5: В этом коде есть много проблемных мест, поэтому вы должны очень внимательно рассмотреть, как вы будете строить свою собственную систему.

+0

Спасибо, ваш добрый пост. Моя проблема в том, что каждая кнопка выполняет много работы. ex: каждый раз, щелкая btn1, он загружает другое значение в поле со списком. затем снова, если я нажму btn1 base на значение combo-box, он очистит данные со списком и загрузит другой, и так далее. Мне жаль, что я не могу загрузить мой пример excel, но я не могу сделать это здесь. – NTMS

+0

Hi Eugene, спасибо. Ваша первая идея очень хорошая. Я не хочу ставить несколько элементов управления. Я также научусь лучше программировать для использования интерфейсов. Я понимаю, что более понятно ваш терминал Контексты. Но я новичок в C# Interface. Так я должен создать ITerminalContext в отдельном классе? Этот класс находится в папке моего приложения? Если так, то, я думаю, мне удастся адаптироваться к моему приложению. Если я застрял, я напишу здесь. Я также напишу свой код здесь. С уважением. – NTMS

+0

Привет @Eugene, я застрял! Прежде всего, я создаю отчаянный файл класса в моей папке приложения формы как ITerminalContext.cs. Мой класс выглядит так, как вы писали выше. – NTMS

Смежные вопросы