WF与其他工作流框架不同,由于WF做为NET3.0的一部份发部,
这样使我们在设计WF应用时有更多的方案:
常用的有
1.使用服务器单一引擎处理所有客户端流程
2.每个客户端启动自己的业引擎,服务器从事数据保存与消息中转的工作
这些具体的应用,其他文章已经描述过,这里就不多说了;
本例的应用场景是第二种,
当然也可以很容易的改成第一种方式,数据交换用WebService,技巧就用[由一个WF项目说起]中我贴出的那段代码为基础。
要实现该例,要在数据库中建一些表,每张表代表一个具体的业务表单,表的个数、名称、结构任意,例子就是要动态挂单。

挂单类代码
using System;
using System.Collections.Generic;
using System.Text;

namespace WFDataForm


{
class DynamicDataForm : System.Windows.Forms.Form

{
public string conString = "";
public string tabName;
public DynamicDataForm(string db, string tabName)

{
this.conString = string.Format("data source=.;initial catalog={0};integrated security=true", db);
this.tabName = tabName;
InitializeComponent();
OperateData();
GetTabStruct();
ShowTabStruct(tabRow); ;
}

private System.Windows.Forms.Panel dataPanel;
private System.Windows.Forms.Button okButton;

private System.Data.SqlClient.SqlConnection con;
private System.Data.SqlClient.SqlCommand cmd_Select;
private System.Data.SqlClient.SqlCommand cmd_Insert;


System.Collections.Generic.List<TabField> tabRow = new List<TabField>();


private void InitializeComponent()

{
okButton = new System.Windows.Forms.Button();
okButton.Text = "完成";
okButton.Click += new EventHandler(okButton_Click);

dataPanel = new System.Windows.Forms.Panel();
dataPanel.AutoScroll = true;
dataPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
dataPanel.Width = 400;
dataPanel.Height = 200;
dataPanel.Top = 30;

this.Width = 410;
this.Controls.Add(okButton);
this.Controls.Add(dataPanel);
}

void okButton_Click(object sender, EventArgs e)

{
con.Open();
string s = GetInsetrString(tabRow);

System.Console.WriteLine(s);

cmd_Insert.CommandText = s;
cmd_Insert.ExecuteNonQuery();

con.Close();
this.Close();

}

private void OperateData()

{
con = new System.Data.SqlClient.SqlConnection(this.conString);
cmd_Select = con.CreateCommand();
cmd_Select.CommandText = string.Format("select * from {0} where 1> 2", this.tabName);
cmd_Insert = con.CreateCommand();

}

private void GetTabStruct()

{
con.Open();
System.Data.SqlClient.SqlDataReader rd = cmd_Select.ExecuteReader();
for (int i = 0; i < rd.FieldCount; i++)

{
TabField f = new TabField();
f.fieldType = rd.GetFieldType(i);
f.fieldName = rd.GetName(i);
tabRow.Add(f);

}
rd.Close();
con.Close();



}

private void ShowTabStruct(List<TabField> o)

{
int x = 120;
int y = 30;
int i = 0;
foreach (TabField temp in o)

{

System.Windows.Forms.Label l = new System.Windows.Forms.Label();
l.Text = temp.fieldName;
l.Top = y * i;

System.Windows.Forms.TextBox t = new System.Windows.Forms.TextBox();

t.Left = x;
t.Top = y * i;
t.Tag = temp.fieldType;

i = i + 1;

this.dataPanel.Controls.Add(l);
this.dataPanel.Controls.Add(t);


}
}


private void GetData(List<TabField> o)

{
int i = 0;
foreach (System.Windows.Forms.Control temp in this.dataPanel.Controls)

{
if (temp is System.Windows.Forms.TextBox)

{

tabRow[i].fieldValue = temp.Text;
i = i + 1;

}

}

}


private string GetInsetrString(List<TabField> o)

{
GetData(o);

string f = "";
string v = "";
foreach (TabField temp in o)

{
f = f + temp.fieldName + ",";

if (temp.fieldType.ToString() == "System.Int32")

{
v = v + temp.fieldValue + ",";
}
else

{
v = v + "'" + temp.fieldValue + "'" + ",";

}

}

f = DeleteRearwardSymbol(f);
v = DeleteRearwardSymbol(v);
string s = string.Format("insert into {0} ({1}) values ({2})", tabName, f, v);
return s;
}

private string DeleteRearwardSymbol(string s)

{
string temp = s.Remove(s.Length - 1);
return temp;
}


class TabField

{
public System.Type fieldType = null;
public string fieldName = "";
public object fieldValue = null;
}




}
}

工作流代码

namespace WFDataForm


{
public sealed partial class Workflow1: SequentialWorkflowActivity

{
public Workflow1()

{
InitializeComponent();
}

private string[] tab;
private string tabs="";

public string Tabs

{

get
{ return tabs; }

set
{ tabs = value; }
}
private bool whileTag=false;

private int sp = 0;

private void codeActivity1_ExecuteCode(object sender, EventArgs e)

{
if (sp < tab.Length)

{
new DynamicDataForm("a",tab[sp]).ShowDialog();
sp = sp + 1;
}
else

{
whileTag = true;
}


}

private void codeActivity2_ExecuteCode(object sender, EventArgs e)

{

tab = tabs.Split(new char[]
{ ',' });
}

}

}

引擎代码
private System.Workflow.Runtime.WorkflowRuntime wr;
System.Workflow.Runtime.WorkflowInstance instance;
private void button1_Click(object sender, EventArgs e)

{


Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("Tabs",textBox1.Text);

instance = wr.CreateWorkflow(typeof(WFDataForm.Workflow1), parameters);
instance.Start();

}

private void Form1_Load(object sender, EventArgs e)

{
wr = new System.Workflow.Runtime.WorkflowRuntime();
wr.StartRuntime();
wr.WorkflowCompleted += new EventHandler<System.Workflow.Runtime.WorkflowCompletedEventArgs>(wr_WorkflowCompleted);
}

void wr_WorkflowCompleted(object sender, System.Workflow.Runtime.WorkflowCompletedEventArgs e)

{
MessageBox.Show("完成");
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

{
wr.StopRuntime();
}

private void button2_Click(object sender, EventArgs e)

{
instance.Resume();
}
运行说明
在文本框中输入表明,用[,]分开,每多一个表,流程就会多一个逻辑结点

注意修改一下连接字串,以指定数据库
数据类型验证没有写,但类型分析已写完,只接加上就可以了
更多的扩展应用,在后面的文章中会展开了谈,本文全当热身
本例来自于[资料(2).rar]内容
本例代码https://files.cnblogs.com/foundation/WFDataForm.rar
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)