基础工作,建立代码结构框架
1.创建项目WorkflowDesignerControl
1.1:WorkflowView和DesignSurface,workflowView是微软提供的工作流设计API,所有的操作都要在上面进行;DesignSurface是WorkflowView的设计时支持
WorkflowView需要从中获得一些资源。
1.2:工具箱和属性窗口也要放到WorkflowDesignerControl中
第一部分
基础工作,建立代码结构框架
1.创建项目WorkflowDesignerControl
1.1:WorkflowView和DesignSurface,workflowView是微软提供的工作流设计API,所有的操作都要在上面进行;DesignSurface是WorkflowView的设计时支持
WorkflowView需要从中获得一些资源。
1.2:工具箱和属性窗口也要放到WorkflowDesignerControl中
Toolbox toolbox = new Toolbox(this);
this.propertyGridSplitter.Panel1.Controls.Add(toolbox);
toolbox.Dock = DockStyle.Fill;
toolbox.BackColor = BackColor;
toolbox.Font = WorkflowTheme.CurrentTheme.AmbientTheme.Font;

2、在WorkflowDesignerControl加入ActivityLibrary的引用
DesignerHostingApplication中加入ActivityLibrary和WorkflowDesignerControl的引用
DesignerHostingApplication中加入System.Design,System.Drawing.Design,System.Workflow.Activities,System.Workflow.ComponentModel的引用
3.所有自定义的Activitie放入一个project,这样基本的代码架构就建立好了。
第二部分
winfrom中集成可编程的wf设计器
1.首先创建DesignerHostingApplication的解决方案
重命名from1.cs为DesignerShell.cs,并加入工具条
Toolstrip
Name: toolStrip
GripStyle: Hidden
RenderMode: System
Ensure the Dock property is set to Top
将WorkflowDesignControl加入toolStrip
Name: workflowDesignerControl
Dock: Fill
2.使设计器支持zooming
public void ProcessZoom(int zoomFactor)

{
this.workflowView.Zoom = zoomFactor;
this.workflowView.Update();
}

2.1:使用预定义的zoom levels 25%, 100% and 200%,zoom设计器in or out
在DesignerShell.cs中调用ProcessZoom
private void zoomDropDownMenuItem_Click(object sender, EventArgs e)

{
if (sender is ToolStripMenuItem)

{
ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;

int zoomFactor = 0;

bool result = Int32.TryParse(menuItem.Tag.ToString(), out zoomFactor);

if (result)

{
this.workflowDesignerControl.ProcessZoom(zoomFactor);
}
}
}


2.2:在toolstrip中加入dropdownButton并定义属性:
Name: zoomDropDown
DisplayStyle: Text
Text: Zoom
编辑DropDownButton,加入三个Item对应Text分别为:25% ,100%,200%
每个item分别定义name和tag,分别为;mni25PercentZoom,25;mni100PercentZoom,100;mni200PercentZoom,200;
并定义click事件
3如何在wf中添加Activities(能在workflow中添加或删除Activitie,并能修改activity的属性)
1.在WorkflowDesignerControl.cs中添加自定义的工具箱
public WorkflowDesignerControl()

{
InitializeComponent();

Toolbox toolbox = new Toolbox(this);
this.propertyGridSplitter.Panel1.Controls.Add(toolbox);
toolbox.Dock = DockStyle.Fill;
toolbox.BackColor = BackColor;
toolbox.Font = WorkflowTheme.CurrentTheme.AmbientTheme.Font;

WorkflowTheme.CurrentTheme.ReadOnly = false;
WorkflowTheme.CurrentTheme.AmbientTheme.ShowConfigErrors = false;
WorkflowTheme.CurrentTheme.ReadOnly = true;

this.propertyGrid.BackColor = BackColor;
this.propertyGrid.Font = WorkflowTheme.CurrentTheme.AmbientTheme.Font;

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

2.使WorkflowDesignerControl中的工具箱运行时加载Activitie(可以是自定义的)
在ToolBoxItems.txt中注册
例如我有个自定义的basic Activitie,如果要把这个Activiti加入工具箱中可以在ToolBoxItems.txt中这样写
ActivityLibrary.MessageActivity, ActivityLibrary
运行后就可以看到工具箱中有MessageActivity
3.在设计器中选择Activity并编辑属性
在WorkflowDesignerControl.cs中注册事件SelectionChanged
ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;

if (selectionService != null)

{
selectionService.SelectionChanged += new EventHandler(OnSelectionChanged);
}


实现OnSelectionChanged事件
private void OnSelectionChanged(object sender, EventArgs e)

{
ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;

if (selectionService != null)

{
this.propertyGrid.SelectedObjects = new ArrayList(selectionService.GetSelectedComponents()).ToArray();
}
}


这样,当WorkflowDesignerControl运行时,在右边下角会显示会选择所选择Activity的属性
4.使工作流设计器支持删除功能
在WorkflowDesignerControl.cs中加入方法DeleteSelected,支持在设计器中删除Activity.
public void DeleteSelected()

{
ISelectionService selectionService = (ISelectionService)this.GetService(typeof(ISelectionService));

if (selectionService != null)

{
if (selectionService.PrimarySelection is Activity)

{
Activity activity = (Activity)selectionService.PrimarySelection;

if (activity.Name != this.WorkflowName)

{
activity.Parent.Activities.Remove(activity);
this.workflowView.Update();
}
}
}
}


在界面工具条上添加Button,属性如下
Name: btnDelete
DisplayStyle: Text
Text: “Remove Activity”
在click事件中写入对WorkflowDesignerControl中DeleteSelected方法的调用
private void btnDelete_Click(object sender, EventArgs e)

{
this.workflowDesignerControl.DeleteSelected();
}

5.使工作流设计器实现保存,编译,运行和打开已保存工作流的功能。
在工具条上再次添加按钮名称分别为打开,保存,编译和运行,在这些按钮的事件触发程序中调用workflowDesignerControl中已经定义好的方法
5.1在workflowDesignerControl中添加方法,加载已经存在的工作流模板文件
public void LoadExistingWorkflow()

{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "xoml files (*.xoml)|*.xoml|All files (*.*)|*.*";
openFileDialog.FilterIndex = 1;
openFileDialog.RestoreDirectory = true;

if (openFileDialog.ShowDialog() == DialogResult.OK)

{
using (XmlReader xmlReader = XmlReader.Create(openFileDialog.FileName))

{
WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
this.workflow = (SequentialWorkflowActivity)serializer.Deserialize(xmlReader);
this.LoadWorkflow();

this.XomlFile = openFileDialog.FileName;
this.Text = "Designer Hosting Sample -- [" + openFileDialog.FileName + "]";
}
}
}


5.2:保存功能实现
private void SaveFile()

{
if (this.XomlFile.Length != 0)

{
this.SaveExistingWorkflow(this.XomlFile);
}
else

{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "xoml files (*.xoml)|*.xoml|All files (*.*)|*.*";
saveFileDialog.FilterIndex = 1;
saveFileDialog.RestoreDirectory = true;

if (saveFileDialog.ShowDialog() == DialogResult.OK)

{
this.SaveExistingWorkflow(saveFileDialog.FileName);
this.Text = "Designer Hosting Sample -- [" + saveFileDialog.FileName + "]";
}
}
}


5.3:编译功能实现
public bool Compile()

{
return this.Compile(true);
}

public bool Compile(bool showMessage)

{
if (!this.Save(false))

{
return false;
}

if (!File.Exists(this.XomlFile))

{
MessageBox.Show(this, "Cannot locate xoml file: " + Path.Combine(Path.GetDirectoryName(this.GetType().Assembly.Location), XomlFile), this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}

bool compileOK = true;

Cursor cursor = this.Cursor;
this.Cursor = Cursors.WaitCursor;

try

{
// Compile the workflow

String[] assemblyNames =
{ AdditionalAssembies };
WorkflowCompiler compiler = new WorkflowCompiler();
WorkflowCompilerParameters parameters = new WorkflowCompilerParameters(assemblyNames);
parameters.LibraryPaths.Add(Path.GetDirectoryName(typeof(ActivityLibrary.MessageActivity).Assembly.Location));
parameters.GenerateInMemory = true;
WorkflowCompilerResults compilerResults = compiler.Compile(parameters, this.XomlFile);

inMemoryAssembly = compilerResults.CompiledAssembly;

StringBuilder errors = new StringBuilder();

foreach (CompilerError compilerError in compilerResults.Errors)

{
errors.Append(compilerError.ToString() + '\n');
}

if (errors.Length != 0)

{
MessageBox.Show(this, errors.ToString(), this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
compileOK = false;
}
else if (showMessage)

{
MessageBox.Show(this, "Workflow compiled successfully. Compiled assembly:\n" + compilerResults.CompiledAssembly.GetName(), this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
finally

{
this.Cursor = cursor;
}

return compileOK;
}

注意:
parameters.GenerateInMemory = true;这时assembly只在内存中生成,不输出到文件
如果要生成.dll文件,需要修改为
parameters.GenerateInMemory = false;
parameters.OutputAssembly = string.Format("{0}.dll", this.WorkflowName);
6:在工具条的事件中调用这些方法
测试一下
如果还没有保存,运行后会先保存并编译。
补传 本文所示代码:demo
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本