当前位置: 首页 > 知识库问答 >
问题:

根据系统状态以不同的方式处理控制事件

李和昶
2023-03-14

我试图建立一个Ingenico POS终端(iWL220)的模拟器。主屏幕上有一个组合框。一旦用户输入id和密码,组合框加载6个菜单。如果用户点击btn1,则组合框清除菜单并添加另一组菜单。如果用户点击新加载菜单的< code>btn1,则再次清除组合框并加载另一组菜单,依此类推。

我的问题是,每次点击按钮(btn1、btn2、btn3、btn4、btn5),我都要编写大量的if-else语句。实例

第一个菜单(组合框上)有6个扇区。

    < li>1。部门A <李> 2。部门B <李> 3。部门C <李> 4。SectorD <李> 5。部门 <李> 6。SectorF

如果用户选择1.SectorA然后用户单击btn1。然后btn1清除组合框并加载另一组菜单。这个时间菜单(在组合框上)有3家公司。

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

这次用户选择1.1,然后再次单击btn1。然后btn1清除组合框并加载另一组菜单。此时间菜单(组合框上)有2个付款选项。

    < li>1。全额付款 <李> 2。平价付款

现在,如果用户单击btn1或btn2,可见的组合框将变为false,并且在主屏幕中有一个标签和输入框。输入框允许用户输入用户号码并按回车键(绿色按钮)。

我已经将Ingenico终端图片加载为jpeg,最上面我设置了按钮。我只给出了我的模拟的小版本。在我的应用程序中,用户可以选择114个概率。

在我的应用程序中,btn1被点击的概率为92,btn2被点击的概率为53,以此类推。用户输入订户号码并单击绿色按钮后,我的应用程序使用wfc服务格式化数据并发送到sql server。但在用户点击按钮的每个组合之前,我在我的应用程序中的一些地方存储btn号码为422。这422意味着,用户选择了部门d公司b平价支付选项。所以我的世界粮食理事会将知道这是什么意思。

我的问题是,对于这种114概率的情况,构建按钮事件的最短方法是什么?

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

当我的应用程序启动时,第一个数组值<code>1。(ArrayMain)

第二次,如果用户选择1.Salty,则用户再次单击btn1,这次btn1事件清除comboBox并将1.1.1ArraySalty()值加载到comboBox中。

如果用户选择“2.BB”,则第三次用户单击Btn2并发送信息“BB”进行计算。

首先,您有5个(或多或少)菜单项,每次您按下任何(数字)按钮(如pos终端中的1到9)时,新菜单就会出现在屏幕上。

共有1个答案

衡翰藻
2023-03-14

每个按钮在任何特定时间都应根据系统状态执行某些特定操作。显然,如果您试图根据大量不同的变量来决定具体的操作,您将创建大量分支代码。这样的代码很难正确编写,甚至更难调试和维护。

那么,如果我们将每个可能状态(状态序列)的当前操作封装在某个特定类(接口)中会怎么样呢

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

为了让我们具体的终端演示者与表单互操作,我们将强制表单实现以下接口:

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

现在,我们将创建两个 TerminalPresenter - 一个只允许通过 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);
    }

P、 S.1:这些代码段假设您有一个名为MainForm的表单,它有两个按钮-按钮1、按钮2、一个组合框、两个文本框-textBox_Input、textBox_ Output。

P.S.2:使用的模式足够接近模型-视图-表示器,只是没有数据绑定。

P.S.3 如果您修改 APlusBPresenter 代码,则可以创建或多或少的通用状态机表示器。或者尝试塑造ChainXxxx...类和接口。

P、 S.4:很抱歉这些代码墙。这对于[SO]格式来说可能太多了,所以我在GitHub上放了一个特别的概念证明-https://github.com/Podskal/StackOverflow_29870164.git.它在很多方面都很难看,但事实上,它至少可以提供一些关于如何实现自己的系统的想法。

P、 S.5:这段代码中有很多问题,因此您应该非常仔细地考虑如何从中构建自己的系统。

 类似资料:
  • 事务的概念 事务的概念来自于两个独立的需求:并发数据库访问,系统错误恢复。 一个事务是可以被看作一个单元的一系列SQL语句的集合。 事务的特性(ACID) A, atomacity 原子性 事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处

  • 我正在使用kafka在java中进行poc项目- 在Kafka上,将产生数量不可预测的事件,从0到数千个事件/秒,例如关于特定主题的事件。 Flink将消耗此事件,并应每秒陷入弹性搜索每个状态中的事件数ex: 我有10个状态:<代码>[创建,…,删除] 平均生命周期为15分钟。状态每秒可以更改两次。理论上可以增加新的州。 为了每时每刻都让溪流下沉,我想用Flink的时间窗https://flink

  • YodaOS Event Event battery.info 表示电池状态,参数描述如下: 参数名称 类型 描述 data string 电池信息 data.batSupported bool 表示是否支持电池 data.batChargingOnline bool 表示是否在充电 data.batLevel int 当前电量 Event app.setup.network-available

  • 我在我的JAVA应用程序中配置了Spring批处理作业,该应用程序在集群中运行。因此,相同的作业被执行两次,这是我不想要的。 所以我想在作业中配置一个步骤,它将检查CREATE_DATE是否在BATCH_JOB_EXECUTION表中存在,并将继续或故障转移。 如何在spring批处理步骤中进行配置?

  • 如何查看系统变量 执行env可以查看系统的环境变量,如主机的名称、当前用户的SHELL类型、当前用户的家目录、当前系统所使用的语言等。 执行set可以看到系统当前所有的变量,其中包括了: 系统的所有预设变量,这其中既包括了env所显示的环境变量,也包含了其它许多预设变量。 用户自定义的变量。 监控系统的状态 使用w命令查看当前系统整体上的负载 使用w命令可以查看当前系统整体上的负载: # w 2

  • 控制台-频道-状态统计 接口URL {youke-url}/console/Index.php?c=live&a=countStatus&timestamp=1607677497&access_key=abc&sign=c7da8103312da8793af4f526a42cb6ebaa06cfd4 请求方式 POST Content-Type form-data 请求Query参数 参数 示例值