制作背景

之前做Win8 Metro动态加载内容框架的时候,由于采用了XAML+JavaScript的方法,程序复杂的执行逻辑是由JavaScript控制的,而页面一多,流程一复杂,制作起来就非常麻烦,还要考虑不同XAML页面返回事件的名称。所以就写了个状态机模型的程序制作工具。

技术支持

说到制作状态机,无疑微软的VS是最强大的,微软本身就有Workflow。使用微软的工作流就可以很方便的制作出一个状态机,然后在用System.Workflow下的类库提取,整理结构,然后生成JavaScript就完事了。

使用VS来制作工作流XAML是因为VS非常直观方便,所以只使用微软工作流里的StateMachine、State、Transition、WriteLine(占位识别),支持嵌套状态机。

技术详解

  • 解析微软工作流XAML

    首先需要引用微软工作流相关的类库System.Activities、System.Workflow.ComponentModel、System.Workflow.Activities、System.Workflow.Runtime、System.WorkflowServices。

    读取活动树,path为VS生成的工作流XAML文件路径:

    1. Activity act = ActivityXamlServices.Load(path);

    然后对活动树进行解析,活动树的类型主要处理类型:StateMachine、State(需要处理状态的Enter、Exit和Transition)、Literal`1(状态转移条件填写为True时)、CSharpValue`1(状态转移条件需要后续编程时)、WriteLine(普通预埋点)

    状态转移条件

    这一步的目的是把微软工作流的复杂对象进行整理,方便序列化给JavaScript使用,并对预埋的需要扩展JavaScript编程的地方创建JavaScript函数名(创建方法需要根据活动树生成,要保证修改工作流后原有的未更改部分生成名一致),并记录到函数表上。

    整理后的活动树

  • JavaScript代码填写程序补完

    这一部分没什么太多说的,把之前解析出来的JavaScript函数列出来,填写上即可。当时我还是使用DataSet比较多,所以函数表使用DataSet做的,请各位想象成喜欢的形式:

    1. void initCodeTable()
    2. {
    3. codeTable = new DataTable("Code");
    4. codeTable.Columns.Add("Guid");
    5. codeTable.Columns.Add("Event");
    6. codeTable.Columns.Add("Interface");
    7. codeTable.Columns.Add("Codes");
    8. CM.Tables.Add(codeTable);
    9. }

    这里事件的概念主要是配合Win8Metro那头的框架设计的。事件都是XAML+JS Api中的。

    事件列表

  • JavaScript组装

    上一步已经把JavaScript函数全都做完了,接下来把这些函数生成到最终的html文件中就好了。这里预先写一个模版文件,执行主体JavaScript状态机就在这个文件里面。

    JavaScript的功底比较菜,没做封装,各位凑合看看吧:

  1. <!DOCTYPE html>
  2.  
  3. <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
  4. <head>
  5. <meta charset="utf-8" />
  6. <title></title>
  7. <script type="text/javascript" src="jquery-1.8.2.min.js"></script>
  8. <script type="text/javascript" src="core-min.js"></script>
  9. <script type="text/javascript" src="enc-base64-min.js"></script>
  10. <script type="text/javascript" src="json.js"></script>
  11. <script type="text/javascript" src="UppApp.js"></script><!--UppBox通讯类库-->
  12. <script type="text/javascript" src="Network.js"></script>
  13. </head>
  14. <body>
  15. <script type="text/javascript">
  16. //省略UppBox应用层初始化
  17.  
  18. var DEBUG = false;
  19. var NETDEBUG = false;
  20. var SMEngine;
  21. var currSM;
  22. var SUSPEND = false;
  23.  
  24. //状态机数据注入点
  25. //<!--JSONDATA-->
  26.  
  27. //状态用临时变量
  28. var tempVar = (function () {
  29. function tempVar() { }
  30. return tempVar;
  31. })();
  32.  
  33. function MessageBus(para);//接收Win8Metro发来的信息,具体内容略function SendMsg(cmd, msg);//向Win8Metro发送信息,具体内容略
  34. function DebugInfo(para);//调试信息传递,可通过控制台/UppBox/body的DOM节点
  35.  
  36. function InitApp() {
  37. //网络状态,配置项等的初始化注入点
  38. //<!--INITDATA-->
  39. AppDemo.initFW();//UppBox初始化
  40. SMEngine = eval(json);//json为上方注入的内容,是个Json结构对象
  41. currSM = SMEngine;
  42. if (DEBUG) DebugInfo("Init()" + currSM.DisplayName);
  43. EntryState(currSM.States[0]);
  44. try {
  45. AppLoaded();
  46. } catch (e) {
  47. }
  48. }
  49.  
  50. function runFunction(func, para) {
  51. if (func == null) return false;
  52. switch (func.Type) {
  53. case "Action":
  54. var funName = func.Code;
  55. try {
  56. if (DEBUG) DebugInfo("runFunction():" + funName + " para:" + para);
  57. var result = eval(funName + "(para);");
  58. return result;
  59. } catch (e) {
  60. return false;
  61. }
  62. break;
  63.  
  64. default:
  65. break;
  66. }
  67. }
  68.  
  69. function TAction(action, entryState, para) {
  70. if (DEBUG) DebugInfo("TAction:" + action.DisplayName + " " + entryState.DisplayName + " " + para);
  71. try {
  72. if (para != "[SUSPEND]") {
  73. var result = runFunction(action, para);
  74. if (result == false) {
  75. SUSPEND = true;
  76. setTimeout(function (action, entryState) {
  77. TAction(action, entryState, "[SUSPEND]");
  78. }, 500, action, entryState);
  79. } else {
  80. EntryState(entryState);
  81. }
  82. }
  83. else {
  84. if (SUSPEND == false) {
  85. EntryState(entryState);
  86. } else {
  87. setTimeout(function (action, entryState) {
  88. TAction(action, entryState, "[SUSPEND]");
  89. }, 500, action, entryState);
  90. }
  91. }
  92. } catch (e) {
  93. }
  94. }
  95.  
  96. function Trigger(para) {
  97. if (SUSPEND) {
  98. if (DEBUG) DebugInfo("SUSPEND():" + para);
  99. otherFun(para);
  100. return;
  101. }
  102. for (var i = 0; i < currSM.currState.Transitions.length; i++) {
  103. var result = runFunction(currSM.currState.Transitions[i].Trigger, para);
  104. if (result == true) {
  105. var result = runFunction(currSM.currState.Transitions[i].Condition, para);
  106. if (result == true) {
  107. var stateName = currSM.currState.Transitions[i].To;
  108. for (var j = 0; j < currSM.States.length; j++) {
  109. var sns = currSM.States[j].DisplayName.split("_");
  110. var CurrName = sns[sns.length - 1];
  111. if (CurrName == stateName) {
  112. ExitState();
  113. TAction(currSM.currState.Transitions[i].Action, currSM.States[j], para);
  114. return;
  115. }
  116. }
  117. return;
  118. }
  119. }
  120. }
  121. var result = runFunction(currSM.currState.Main, para);
  122. if (result != true) {
  123. if (DEBUG) DebugInfo("otherFun(): para:" + para);
  124. otherFun(para);
  125. }
  126. }
  127.  
  128. function otherFun(para) {
  129. try {
  130. var str = "";
  131. var msg = "";
  132. try {
  133. str = para.split(" ");
  134. if (str.length > 1) msg = str[1];
  135. for (var i = 2; i < str.length; i++) {
  136. msg += " " + str[i];
  137. }
  138. eval(str[0] + "(msg)");
  139. } catch (e) {
  140. str = para;
  141. eval(str + "()");
  142. }
  143. } catch (e) {
  144. }
  145. }
  146.  
  147. function EntryState(state) {
  148. if (DEBUG) {
  149. var debug = "EntryState():" + state.DisplayName;
  150. if (currSM.currState != null) debug += " CurrState:" + currSM.currState.DisplayName;
  151. DebugInfo(debug);
  152. }
  153. switch (state.Entry.Type) {
  154. case "Action":
  155. if (!state.IsFinal) {
  156. currSM.currState = state;
  157. } else {
  158. while (true) {
  159. if (currSM.preSM == null) break;
  160. currSM = currSM.preSM;
  161. if (!currSM.currState.IsFinal) break;
  162. }
  163. }
  164. runFunction(state.Entry, null);
  165. Trigger("");
  166. break;
  167.  
  168. case "StateMachine":
  169. currSM.currState = state;
  170. state.Entry.preSM = currSM;
  171. currSM = state.Entry;
  172. EntryState(currSM.States[0]);
  173. break;
  174.  
  175. default:
  176. break;
  177. }
  178. }
  179.  
  180. function ExitState() {
  181. if (DEBUG) DebugInfo("ExitState():" + currSM.currState.DisplayName);
  182. if (currSM.currState != null) {
  183. runFunction(currSM.currState.Exit, null);
  184. }
  185. }
  186.  
  187. //函数注入点,编辑器中写的各种函数在此注入
  188. //<!--FUNCDATA-->
  189.  
  190. //举个例子
  191. //Entry:SM_23717574ae2bff0c6e0984140518db_欢迎界面初始化_Entry_初始化_Entry:
  192. function A_87846c21b09faea4a622f8331aa9a4(para){
  193. var str;
  194. try {
  195. str = para.split(" ");
  196. switch (str[0]) {
  197. default:
  198. break;
  199. }
  200. }catch(e){}
  201.  
  202. SendMsg("Storyboard", "[NULL] Start 霓虹灯");
  203. SendMsg("Storyboard", "[NULL] Start 进入");
  204. SendMsg("Storyboard", "[NULL] Start 眨眼睛");
  205. }
  206. </script>
  207. </body>
  208. </html>

其他

程序逻辑编辑器界面

程序逻辑编辑器界面



HTML5支持WebSocket可以连接UppBox,自写的JS状态机引擎在调试模式下可以把与C#代码交互过程全部传输出来,还可以传输指令,方便调试。

JavaScript状态机程序逻辑编辑器的更多相关文章

  1. 了解 JavaScript 应用程序中的内存泄漏

    简介 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分配和释放的具体细节. 许多功能无需考虑内存管理 ...

  2. 大型JavaScript应用程序架构模式

    11月中旬在伦敦举行的jQuery Summit顶级大会上有个session讲的是大型JavaScript应用程序架构,看完PPT以后觉得甚是不错,于是整理一下发给大家共勉. PDF版的PPT下载地址 ...

  3. Backbone.js 为复杂Javascript应用程序提供模型(models)、集合(collections)、视图(views)的结构

    Backbone.js 为复杂Javascript应用程序提供模型(models).集合(collections).视图(views)的结构.其中模型用于绑定键值数据和 自定义事件:集合附有可枚举函数 ...

  4. (6)javascript的程序控制结构及语句-----(1)条件判断

    程序控制结构及语句 编程就是将现实应用,转换为程序能够读得懂的语法语句.Javascript编程中对程序流程控制主要是通过条件判断语句.循环控制语句及continue.break来完成的,其中条件判断 ...

  5. CTF---Web入门第十二题 程序逻辑问题

    程序逻辑问题分值:20 来源: 实验吧 难度:中 参与人数:6909人 Get Flag:1993人 答题人数:2070人 解题通过率:96% 绕过 解题链接: http://ctf5.shiyanb ...

  6. Java Web安全之程序逻辑缺陷

    Java Web程序逻辑缺陷本质是由于程序设计和开发者设计的程序执行逻辑存在某种缺陷而导致的安全隐患.企业的代码审查和渗透测试通常主要针对的大多是诸如xss攻击和sql注入和跨站点脚本这些头条式漏洞, ...

  7. javascript状态机及在工作流中的应用

    #javascript状态机及在工作流中的应用 ##状态机 什么叫状态机(Finite State Machine),书面上的解释可以自己借助搜索引擎寻找到.通俗地来讲是一个状态定义.查找.切换和事件 ...

  8. 《JavaScript》 程序基本知识 数据类型。 {0912上} {0912下}

    JS脚本语言: 这是JaxaScript的全称名 JS是网页里面使用的脚本语言 JS是一个非常强大的语言 JS的基础语法 注释语法:  单行注释 //     多行注释 /**/ 输出语法:   双标 ...

  9. JavaScript的程序构成

    JavaScript的程序构成主要从以下几方面做个总结:控制语句.函数 .事件驱动及事件处理,希望对读者有些帮助. 控制语句: if条件语句 基本格式 if(表述式) 语句段1: ...... els ...

随机推荐

  1. fragment嵌套问题

    fragment嵌套里面不能用再用getActivity().getFragmentManager()要用getChildFragmentManager()

  2. getSlotFromBufferLocked: unknown buffer: 0xf3d94ca0

    安卓6.0模拟器导致,换一个模拟器解决

  3. Git 简介

    版本控制 什么是版本控制? 我需要版本控制吗? - 如果你还没使用过版本控制系统,或许你会有以上疑问,甚至更多疑问.希望后面的回答能让你喜欢上版本控制系统,喜欢上Git. 什么是版本控制:顾名思义,版 ...

  4. Visual Studio 禁用Resharpe插件

    和普通的插件不一样,对于Resharper7+版本需要使用启动参数:/Resharper.Suspend

  5. Delphi 关键字详解[整理于 "橙子" 的帖子]

    absolute //它使得你能够创建一个新变量, 并且该变量的起始地址与另一个变量相同. var   Str: ];   StrLen: Byte absolute Str; //这个声明指定了变量 ...

  6. 【HDU2896】病毒侵袭 AC自动机

    [HDU2896]病毒侵袭 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年 ...

  7. map<虽然一直不喜欢map>但突然觉得挺好用的

    #include<iostream> #include<cmath> #include<cstdio> #include<algorithm> #inc ...

  8. 【BZOJ1911】[Apio2010]特别行动队 斜率优化DP

    想了好久啊....——黑字为第一次更新.——这里是第二次更新,维护上下凸包据题而论,第一种方法是化式子的方法,需要好的化式子的方法,第二种是偏向几何,十分好想,纯正的维护凸包的方法,推荐. 用了我感觉 ...

  9. tornado学习笔记18 _RequestDispatcher 请求分发器

    根据Application的配置,主要负责将客户端的请求分发到具体的RequestHandler.这个类实现了HTTPMessageDelegate接口. 18.1 构造函数 定义: def __in ...

  10. bootstrap学习笔记【转】

    bootstrap是由Twitter公司研发的一个基于HTML,CSS,JavaScript的开源框架,最重要的部分是它的响应式布局.(国内文档翻译官网:http://www.bootcss.com/ ...