上一篇: 宿主工作流设计器(二)

      接着说我们宿主工作流设计器的话题,本节我们讲讲定制一个工具箱,允许从其中拖放工作流活动到我们的设计器当中,以及上下文菜单的定制。
      记得上一篇我们取得WorkFlowView的代码吗?有这么一段:
IDesignerHost designerHost = designSurface.GetService(typeof(IDesignerHost)) as IDesignerHost;

      我们看看desingerHost,它其实是整个工作流组建中的服务容器,里面承载了各种工作流设计器所需的服务,上一篇说DesignSurface也起到服务容器的作用,确切的说DesignSurface是desingerHost的上级容器,我们如果了解微软的Container/Componenet/Service设计思想就应该知道,下级容器会向上级容器提供服务,而注册点应该是一致的,我们可以看看整个设计器的架构图就清楚了。

      

      我们的工具箱拖放功能其实也是以服务的形式放到desingerHost中,而要使得工作流设计器支持这个功能,必须提供一个实现IToolboxService接口的服务类,然后调用designerHost.AddService方法注册到designerHost中,当然这个类必须以组件(Component)形式存在,以便我们把它作为工具箱放到我们自己的UI中。    
      下面是MSDN文章中一个工作流工具箱的实现:
      
ToolboxService

      在上面图中我们可以看到,DesingerHost中还有其他服务,我们需要的上下文菜单正是其中的MenuCommandService,这个服务允许我们在工作流设计器上弹出上下文菜单为用户提供一些便利的操作。比如为用户添加删除、切剪等菜单,我们可以写一个继承自MenuCommandService类的类来完成这些工作。然后同样注册到designerHost中。下面
      首先根据判断用户是否选择了设计器中的活动,然后返回菜单项:
private MenuItem[] GetSelectionMenuItems()
        
{
            List
<MenuItem> menuItems = new List<MenuItem>();

            
bool addMenuItems = true;
            ISelectionService selectionService 
= GetService(typeof(ISelectionService)) as ISelectionService;
            
if (selectionService != null)
            
{
                
foreach (object obj in selectionService.GetSelectedComponents())
                
{
                    
if (!(obj is Activity))
                    
{
                        addMenuItems 
= false;
                        
break;
                    }

                }

            }


            
if (addMenuItems)
            
{
                Dictionary
<CommandID, string> selectionCommands = new Dictionary<CommandID, string>();
                selectionCommands.Add(WorkflowMenuCommands.Cut, 
"切剪");
                selectionCommands.Add(WorkflowMenuCommands.Copy, 
"拷贝");
                selectionCommands.Add(WorkflowMenuCommands.Paste, 
"粘贴");
                selectionCommands.Add(WorkflowMenuCommands.Delete, 
"删除");


                
foreach (CommandID id in selectionCommands.Keys)
                
{
                    MenuCommand command 
= FindCommand(id);
                    
if (command != null)
                    
{
                        MenuItem menuItem 
= new MenuItem(selectionCommands[id], new EventHandler(OnMenuClicked));
                        menuItem.Tag 
= command;
                        menuItems.Add(menuItem);
                    }

                }

            }
      
      重写类MenuCommandService类中的ShowContextMenu方法弹出菜单:
     
public override void ShowContextMenu(CommandID menuID, int x, int y)
        
{
            
if (menuID == WorkflowMenuCommands.SelectionMenu)
            
{
                ContextMenu contextMenu 
= new ContextMenu();
                

                MenuItem[] items 
= GetSelectionMenuItems();
                
if (items.Length > 0)
                
{
                    contextMenu.MenuItems.Add(
new MenuItem("-"));
                    
foreach (MenuItem item in items)
                        contextMenu.MenuItems.Add(item);
                }


                WorkflowView workflowView 
= GetService(typeof(WorkflowView)) as WorkflowView;
                
if (workflowView != null)
                
{
                    contextMenu.Show(workflowView, workflowView.PointToClient(
new Point(x, y)));
                }

            }

        }
      这样,一个上下文菜单就完成了,当然,你还可以加入自己定义的上下文菜单项。如果你需要设计器中提供的原生菜单,你可以通过Verbs属性获得。

      同样你可以实现一个IMemberCreationService接口的服务来为你的设计器设计时行为生成C#代码,其他的更多服务看一参看MSDN,通过服务注入,你甚至可以定制出一个和VS提供的设计器一模一样的Workflow设计器。
    
      说到这里一个工作流设计器所需的功能已经开发完成了,但是我们希望为用户提供更加友善的设计界面,而不是非常专业的开发界面,为此,重新绘制工作流设计器中活动的外观是必要的,这部分内容后面章节会详细介绍。
posted on 2008-01-23 10:42  sharping  阅读(3575)  评论(6编辑  收藏  举报