自定义工作流设计器

第一部分
基础工作,建立代码结构框架
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


     

原文地址:https://www.cnblogs.com/lodestar/p/656119.html