У меня есть работающий тестовый конечный автомат в консольном приложении - 3 состояния и 5 событий.
Проблема: как работать в Windows Forms, т.е. у меня есть основной цикл, который выполняется все времяглядя на состояние ... и если да, то где ... если я использую события, например btnPress.
Цель состоит в том, чтобы приложение могло находиться в нескольких различных состояниях / экранах, и оно должно быть твердым, поэтому использованиеконечный автомат для принудительного исполнения, где мы находимся, и что нет крайних случаев необработанных.
Код рабочей консоли:
namespace StateMachineTest {
class Program {
static void Main(string[] args) {
var fsm = new FiniteStateMachine();
while (true) {
if (fsm.State == FiniteStateMachine.States.EnterVoucherCode) {
Console.WriteLine("State: " + fsm.State);
Console.WriteLine("Enter Voucher Code:");
string voucherCode = Console.ReadLine();
Console.WriteLine("voucher is " + voucherCode);
Console.WriteLine();
fsm.ProcessEvent(FiniteStateMachine.Events.PressNext);
}
if (fsm.State == FiniteStateMachine.States.EnterTotalSale) {
Console.WriteLine("State: " + fsm.State);
Console.WriteLine("Enter Total Sale or x to simulate back");
string voucherSaleAmount = Console.ReadLine();
if (voucherSaleAmount == "x")
fsm.ProcessEvent(FiniteStateMachine.Events.PressBackToVoucherCode);
else {
Console.WriteLine("total sale is " + voucherSaleAmount);
Console.WriteLine();
fsm.ProcessEvent(FiniteStateMachine.Events.PressRedeem);
}
}
if (fsm.State == FiniteStateMachine.States.ProcessVoucher) {
Console.WriteLine("State: " + fsm.State);
Console.WriteLine("Press 1 to fake a successful redeem:");
Console.WriteLine("Press 2 to fake a fail redeem:");
Console.WriteLine("Press 3 to do something stupid - press the Next Button which isn't allowed from this screen");
Console.WriteLine();
string result = Console.ReadLine();
//EnterVoucherCode state
if (result == "1")
fsm.ProcessEvent(FiniteStateMachine.Events.ProcessSuccess);
if (result == "2")
fsm.ProcessEvent(FiniteStateMachine.Events.ProcessFail);
if (result == "3")
fsm.ProcessEvent(FiniteStateMachine.Events.PressNext);
}
//how to handle async calls?
//how to handle many many states.. matrix could get unwieldy
}
}
}
class FiniteStateMachine {
//first state is the default for the system
public enum States { EnterVoucherCode, EnterTotalSale, ProcessVoucher };
public enum Events { PressNext, PressRedeem, ProcessSuccess, ProcessFail, PressBackToVoucherCode };
public delegate void ActionThing();
public States State { get; set; }
private ActionThing[,] fsm;
public FiniteStateMachine() {
//array of action delegates
fsm = new ActionThing[3, 5] {
//PressNext, PressRedeem, ProcessSuccess, ProcessFail, PressBackToVoucherCode
{PressNext, null, null, null, null}, //EnterVoucherCode.... can pressnext
{null, PressRedeem, null, null, PressBackToVoucherCode}, //EnterTotalSale... can pressRedeem or pressBackToVoucherCode
{null, null, ProcessSuccess, ProcessFail, null} }; //moving from ProcessVoucher... can be a processSuccess or ProcessFail.. can't go back to redeem
}
public void ProcessEvent(Events theEvent) {
try {
var row = (int)State;
var column = (int)theEvent;
//call appropriate method via matrix. So only way to change state is via matrix which defines what can and can't happen.
fsm[row, column].Invoke();
}
catch (Exception ex) {
Console.WriteLine(ex.Message); //possibly catch here to go to an error state? or if do nothing like here, then it will continue on in same state
}
}
private void PressNext() { State = States.EnterTotalSale; }
private void PressRedeem() { State = States.ProcessVoucher; }
private void ProcessSuccess() { State = States.EnterVoucherCode; }
private void ProcessFail() { State = States.EnterVoucherCode; }
private void PressBackToVoucherCode() { State = States.EnterVoucherCode; }
}
}
Не работает код WinForms:
//goal is to get a fsm demo working with 3 states and 5 events.
//need number buttons, redeem and back to work.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e) {
SystemSettings.ScreenOrientation = ScreenOrientation.Angle90;
var fsm = new FiniteStateMachine();
while (true)
{
if (fsm.State == FiniteStateMachine.States.EnterVoucherCode)
{
//Console.WriteLine("State: " + fsm.State);
//if next/redeem button is pressed
//fsm.ProcessEvent(FiniteStateMachine.Events.PressNext);
}
if (fsm.State == FiniteStateMachine.States.EnterTotalSale)
{
Console.WriteLine("State: " + fsm.State);
Console.WriteLine("Enter Total Sale or x to simulate back");
string voucherSaleAmount = Console.ReadLine();
if (voucherSaleAmount == "x")
fsm.ProcessEvent(FiniteStateMachine.Events.PressBackToVoucherCode);
else
{
Console.WriteLine("total sale is " + voucherSaleAmount);
Console.WriteLine();
fsm.ProcessEvent(FiniteStateMachine.Events.PressRedeem);
}
}
if (fsm.State == FiniteStateMachine.States.ProcessVoucher)
{
Console.WriteLine("State: " + fsm.State);
Console.WriteLine("Press 1 to fake a successful redeem:");
Console.WriteLine("Press 2 to fake a fail redeem:");
Console.WriteLine("Press 3 to do something stupid - press the Next Button which isn't allowed from this screen");
Console.WriteLine();
string result = Console.ReadLine();
//EnterVoucherCode state
if (result == "1")
fsm.ProcessEvent(FiniteStateMachine.Events.ProcessSuccess);
if (result == "2")
fsm.ProcessEvent(FiniteStateMachine.Events.ProcessFail);
if (result == "3")
fsm.ProcessEvent(FiniteStateMachine.Events.PressNext);
}
}
}
private void btn_0_MouseUp(object sender, MouseEventArgs e)
{
txtCode.Text += '0';
}
private void btn_1_MouseUp(object sender, MouseEventArgs e)
{
txtCode.Text += '1';
}
private void btn_2_MouseUp(object sender, MouseEventArgs e)
{
txtCode.Text += '2';
}
private void btn_del_MouseUp(object sender, MouseEventArgs e)
{
txtCode.Text = txtCode.Text.Substring(0, txtCode.Text.Length - 1);
}
private void btn_redeem_MouseUp(object sender, MouseEventArgs e)
{
txtCode.Visible = false;
txtStatus.Visible = true;
txtStatus.Text = "PROCESSING PLEASE WAIT";
}

Код из: Простой пример конечного автомата в C #?