信息系统开发平台OpenExpressApp - Command扩展机制

  下图为OpenExpressApp的系统架构图,其中在业务层中Command是作为一种系统内部提供以及可供外部扩展的一种机制。OpenExpressApp框架对功能的主要扩展之一就是Command机制,OEA提供的Command可以实现用户交互,更好的分离业务逻辑,带来更好的维护性和 可扩展性。

Command位于架构图业务层

Command的由来

  

MVC是一种经典的架构模式,如上图所示:

模型(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型 ”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作(OEA现在的类库上有UI相关信息只是基于属性的一种元模型实现,它和类模型不是一个概念,大家需要区分开来),但是模型中数据的变化一般会通过一种通知机制被公布(例如:WPF中绑定属性内部实现了通知机制)。

视图(View) 能够展现数据。在视图中一般没有业务上的逻辑。

控制器(Controller) 控制器可以访问视图和模型,用于控制应用程序的业务流程。控制器提高了应用程序的灵活性和可配置性,它可以用来连接不同的模型和视图去完成用户的需求。给 定一些可重用的模型和视图,控制器可以根据用户的需求选择适当的模型机型处理,然后选择适当的的视图将处理结果显示给用户。

OEA中的Command就是控制器,通过Command可以访问视图和模型,控制应用程序的业务。

主要类图

CommandBase

CommandBase作为所有命令类的基类,主要定义了CanVisible、CanExecute和Execute几个方法, Execute执行方法在子类中实现。

Code


ViewCommand、WPFViewCommand

ViewCommand、WPFViewCommand在CanVisible、CanExecute和Execute三个方法中传入的参数是ObjectView类型,通过ObjectView可以访问视图和模型。

Code

WPFListViewCommand

WPFListViewCommand在CanVisible、CanExecute和Execute三个方法中传入的参数是ListObjectView类型。由于对ListObjectView进行扩展的比较多,所以单独实现了一个类。

WPFAutoCommand

WPFAutoCommand在生成窗体的View后自动调用的Command,可以在这个命令中挂接事件等。如以下代码示例:

Code

PropertyEditorCommand

PropertyEditorCommand将属性编辑器PropertyEditor作为参数,框架内部的附件操作命令就是这类命令。

代码目录结构

Command在OEA中的目录结构如下图:

Pattern

Pattern目录下为codeproject上的一个扩展WPF Command的一个实现,我用它来作为OEA的command应用模式。这里就不做进一步介绍了,感兴趣的可以去那个网站看看

CommandAdapter

OEA是通过CommandAdapter来把CommandBase适配到Pattern

Code

ObjectEditCommand、TreeEditCommand、FileAttachmentCommand、LookupCommand、ViewExtCommand

这些Command都是OEA内置对对象、树形、附件、下拉列表、View的基本操作的支持,具体代码可以去看看源码,这里就不一一列出来了。

Code
    public class CommandNames
    {
        
public const string Add = "Add";
        
public const string CopyAndNew = "CopyAndNew";
        
public const string AddChild = "AddChild";
        
public const string DeleteBillObject = "DeleteBillObject";
        
public const string DeleteListObject = "DeleteListObject";
        
public const string DeleteChildObject = "DeleteChildObject";
        
public const string Cancel = "Cancel";
        
public const string Refresh = "Refresh";
        
public const string Save_Bill = "Save_Bill";
        
public const string Save_List = "Save_List";

        
public const string InsertBefore = "InsertBefore";
        
public const string InsertFollow = "InsertFollow";
        
public const string MoveDown = "MoveDown";
        
public const string MoveUp = "MoveUp";
        
public const string LevelUp = "LevelUp";
        
public const string LevelDown = "LevelDown";
        
public const string ExpandAll = "ExpandAll";
        
public const string CollapseAll = "CollapseAll";

        
public const string ClearQueryCondition = "ClearQueryCondition";
        
public const string QueryObject = "QueryObject";
        
        
//Lookup
        public const string ClearLookupPropertyValue = "ClearLookupPropertyValue";

        
//view
        public const string MaxShowView = "MaxShowView";

        
//select
        public const string SelectAll = "SelectAll";

        
//FileAttachment
        public const string AddFile = "AddFile";
        
public const string OpenFile = "OpenFile";
        
public const string FileSaveAs = "FileSaveAs";
        
public const string ClearFile = "ClearFile";
    }

如何使用

  1. 增加Command继承类,实现CanVisible、CanExecute和Execute方法
  2. 在类定义上增加属性标记,让OEA注册这个Command到资源库中
  3. 运行时由AutoUI自动生成对应的Command的按钮或者菜单项

Command类

  如果我们需要对树形操作增加一个命令全部展开,那么首先需要生成一个类ExpandAllCommand,由于这个命令是对树形列表视图进行操作,所以选择从WPFListViewCommand继承过来。生成类后再在类上加上Command属性来注册命令。更多的示例可以查看OEA内部支持的一些Command。

Code
    [Command(CommandNames.ExpandAll, Label = "全部展开", ToolTip = "全部展开")]
         public class ExpandAllCommand WPFListViewCommand
        {
            
public override bool CanVisible(ListObjectView view)
            {
                
return (null != view) && ((view is ListObjectView) && ((ListObjectView)view).IsTree);
            }

            
public override void Execute(ListObjectView view)
            {
                (view.Control 
as MultiObjectTreeView).ExpandAll();
            }
        }

  在类定义上增加了Command属性后,OEA会把这个Command到资源库中,以下将介绍以下属性以及OEA如何生成Command对应的按钮或者菜单项。

基于属性的模型支持

  OEA目前对UI模型和Command模型的支持都是基于属性来定义的,Command通过CommandAttribute来定义

Code

  另外为了方便的支持控制系统Command的是否可以使用,增加了NotAllowRemoveNotAllowNewNotAllowEdit三 个属性。如果类定义上标识了这些属性,OEA在生成Command对应按钮时会进行判断是否使用这些Command。在 OpenExpressApp.MetaModel项目ApplicationModel.cs中的业务对象元信息BusinessObjectInfo 对象中有以下方法:

Code

注册Command

在OpenExpressApp.Module项目BaseModule初始化时遍历程序集类型注册Command

Code
    /// <summary>
    
/// 所有模块的基类
    
/// 
    
/// 加入业务模型 命令等
    
/// </summary>
    public class BaseModule : IModule
    {
          /// 加入Module类在程序集内的 业务模型 命令等
        public virtual void Initialize()
        {
            
//如果是继承自这个类的类
            if (this.GetType() != typeof(BaseModule))
            {
                var allTypes 
= this.GetType().Assembly.GetTypes();
                
foreach (var item in allTypes.Where(t => t.HasMarked<BusinessObjectAttribute>()))
                {
                    
//加入业务模型
                    BusinessObjectInfo bOInfo = ApplicationModel.AddBusinessObject(item);
                    
//为业务模型加入默认命令
                    bOInfo.AddNotVisibleCommand();
                }

                
foreach (var item in allTypes.Where(t => t.HasMarked<CommandAttribute>()))
                {
                    
//加入自定义命令
                    ApplicationModel.Commands.Add(Activator.CreateInstance(item) as CommandBase);
                }
            }
        }
    }

AutoUI使用Command生成按钮

  Command定义完后需要通过按钮或者菜单项在UI中表现出来,OEA通过AutoUI功能进行自动生成按钮来实现,在《AutoUI自动生成界面》中介绍的CreateMainToolBar和CreateChildToolBar中会基于Command的一些属性来过滤可以使用的命令CreateMainToolBar代码如下:

Code

 

更多内容: 开源信息系统开发平台之OpenExpressApp框架.pdf

 

欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]

posted on 2009-11-16 14:36  周 金根  阅读(2193)  评论(5编辑  收藏

导航