AVEVA .Net 菜单自定义

简介: AVEVA .Net 菜单自定义 AVEVA .Net Command and Menu Customisation eryar@163.com   摘要Abstract:以一个具体实例详细介绍AVEVA .Net中自定义菜单的原理及方法。

AVEVA .Net 菜单自定义

AVEVA .Net Command and Menu Customisation

eryar@163.com

 

摘要Abstract:以一个具体实例详细介绍AVEVA .Net中自定义菜单的原理及方法。掌握了自定义菜单的方法就可以对二次开发的程序进行分类和整理,便于用户使用。

关键字Key words:AVEVA .Net、Addin Commands、Menu Customisation、PDMS、二次开发

 

一、概述 Introduction

通过《AVEVA .Net Quick Start Guide》这篇文章,大家对AVEVA .Net的二次开发有了个大概认识,但是这样并不能编写出实际有用的二次开发插件(Addin)。本文再深入一步,介绍自定义菜单方法,在菜单中调用二次开发的插件,便于用户操作。

用户通过菜单、右键菜单命令、工具条来调用开发的插件。通用程序框架CAF(The Common Application Framework)通过类CommandBarManager来提供了创建菜单、工具条等的接口。也提供了与这些工具交互事件的接口,这种方法CAF虽然支持但不推荐。

通用程序框架CAF还支持通过UIC(用户界面自定义文件User Interface Customisation)文件来自定义菜单、工具条等,UIC文件是XML格式的。

基于XML定义的菜单及工具条需要有个机制将用户界面实体与需要调用的相关功能关联上。为了实现这人目的,插件(Addins)功能通过一些命令对象(command objects)暴露出来。插件通过类CommandManager来加载这些命令对象。XML定义中可以包含用户界面实体如菜单入口、工具条的按钮及与其相关的命令对象。选择相应的菜单或点击工具条上的按钮都可以导致相关联的命令被执行。

基于命令模型的一个好处就是将用户界面或显示层与逻辑层解耦。程序逻辑层就与显示层没有什么直接关系了。若程序的状态需要对用户界面上的操作做出反映,程序只需要修改命令的状态即可。命令对象知道它与哪个用户界面实体关联,所以确保其内部状态反映相应的用户界面。这对一些状态是很简单的,如“enabled”、“visible、“checked”;但对动态程序状态就有点复杂了,如“combo-box”。

 

二、编写命令类 Writing a Command Class

如下所示的代码是一个简单的命令类示例,用来管理一个可停靠窗口的可见性,代码中是控制AttributeBrowser 可停靠窗口。通用程序框架CAF提供了一个抽象的命令类Command,所有的命令类都必须派生自Command类。在其构造函数中应该设置属性Key,在UIC文件中是通过Key这个属性来找到相应的命令,后面将会以一个实例来说明。

 

  1 using  System; 
  2
  3 using  System.Collections.Generic; 
  4
  5 using  System.Text; 
  6
  7 using  Aveva.ApplicationFramework.Presentation; 
  8
  9 namespace  Aveva.Presentation.AttributeBrowserAddin 
 10
 11 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
 12
 13img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif/**//// <summary> 
 14
 15/// Class to manage the visibility state of the AttributeBrowser docked window 
 16
 17/// This command should be associated with a StateButtonTool. 
 18
 19/// </summary> 

 20
 21public class ShowAttributeBrowserCommand : Command 
 22
 23img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
 24
 25private DockedWindow _window; 
 26
 27img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif/**//// <summary> 
 28
 29/// Constructor for ShowAttributeBrowserCommand 
 30
 31/// </summary> 
 32
 33/// <param name="window">The docked window whose visibilty state will be managed.</param> 

 34
 35public ShowAttributeBrowserCommand(DockedWindow window) 
 36
 37img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
 38
 39// Set the command key 
 40
 41this.Key = "Aveva.ShowAttributeBrowserCommand"
 42
 43// Save the docked window 
 44
 45            _window = window; 
 46
 47// Create an event handler for the window closed event 
 48
 49            _window.Closed += new EventHandler(_window_Closed); 
 50
 51// Create an event handler for the WindowLayoutLoaded event 
 52
 53            WindowManager.Instance.WindowLayoutLoaded += new EventHandler(Instance_WindowLayoutLoaded); 
 54
 55}
 
 56
 57void Instance_WindowLayoutLoaded(object sender, EventArgs e) 
 58
 59img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
 60
 61// Update the command state to match initial window visibility 
 62
 63this.Checked = _window.Visible; 
 64
 65}
 
 66
 67void _window_Closed(object sender, EventArgs e) 
 68
 69img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
 70
 71// Update the command state when the window is closed 
 72
 73this.Checked = false
 74
 75}
 
 76
 77img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        /**//// <summary> 
 78
 79        /// Override the base class Execute method to show and hide the window 
 80
 81        /// </summary> 

 82
 83        public override void Execute() 
 84
 85img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
 86
 87            if (this.Checked) 
 88
 89img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
 90
 91                _window.Show(); 
 92
 93            }
 
 94
 95            else 
 96
 97img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
 98
 99                _window.Hide(); 
100
101            }
 
102
103        }
 
104
105    }
 
106
107}
 
108
109


抽象基类Command提供了以下方法,其派生类中可以重载:

l void Execute():必须被重载,在执行命令时调用这个函数;

l CommandState GetState():这个函数由通用程序框架CAF调用,以便更新用户界面或上下文菜单。返回值是一个CommandState枚举值,反应了命令的状态。枚举值用来位来表示命令状态,这些状态可以使用位的或OR操作。

l String Description:命令的描述;

l void Refrest(string context):当CommandManager.ApplicationContext的属性更改时都会调用这个方法。这也就给了一个更新其Enabled或visible状态的机会。

抽象基类Command也有一些属性可以用来更新用户界面上的状态:

l bool Checked:若命令与像StateButtonTool这样的用户界面关联,则此属性值与用户界面上的状态会同步;

l bool Enabled:此属性值的改变将会影响所有与其关联的用户界面;

l ArrayList List:此属性允许命令可以与有字符列表的用户界面交流。如ComboBoxTool;

l int SelectedIndex:此属性表示被用记选中的列表中的索引值;

l object Value:此属性保存了当前关联的用户界面实体;

l bool ValueChanged:通用程序框架CAF在调用命令类的Execute方法之前,若用户界面的值改变时会设置此属性的值。当命令执行结束后此值会被清除;

l bool Visible:此属性值的改变将会影响所有与其关联的用户界面;

在通用程序框架CAF中注册一个命令是通过向CommanManagers.Commands的集合中添加一个命令实例来实现的。程序代码如下所示:

 

 1  //  Create and register addins commands 
 2 
 3  //  Get the CommandManager 
 4 
 5  CommandManager commandManager  =  (CommandManager)serviceManager.GetService( typeof (CommandManager)); 
 6 
 7  ShowAttributeBrowserCommand showCommand  =   new  ShowAttributeBrowserCommand(attributeListWindow); 
 8 
 9  commandManager.Commands.Add(showCommand); 
10 

 

 

三、命令事件 Command Events

命令基类Command提供了两个事件BeforeCommandExecute和CommandExecuted给程序员,用来响应命令的执行,即在命令执行前后做些处理。示例代码如下:

 

 1  Command anotherCommand  =  commandManager.Commands[ " KeyOfCommand " ]; 
 2 
 3  anotherCommand.BeforeCommandExecute  +=   new  System.ComponentModel.CancelEventHandler(anotherCommand_BeforeCommandExecute); 
 4 
 5  anotherCommand.CommandExecuted  +=   new  EventHandler(anotherCommand_CommandExecuted); 
 6 
 7  // The BeforeCommandExecute event handler is of type  
 8 
 9  // CancelEventHandler and is passed a CancelEventArgs object  
10 
11  // which enables the command execution to be cancelled by setting  
12 
13  // the Cancel property to true. 
14 
15  void  anotherCommand_BeforeCommandExecute( object  sender, System.ComponentModel.CancelEventArgs e) 
16 
17 
18 
19      e.Cancel  =   true
20 
21 
22 
23 

 

四、菜单自定义 Menu Customisation

用户使用插件的方式通常都是通过使用菜单或命令栏上的按钮。如前文所述,通用程序框架CAF提供了自定义菜单和命令栏的机制,即通过配置“User Interface Customisation”(UIC)文件。下面将会对UIC文件的细节进行描述,如怎样配置通用程序框架CAF来加载UIC文件,通过用户交互的自定义工具来编辑UIC文件等等。

 

五、配置要加载UIC文件的模块 Configuring a Module to Load a UIC File

每个基于通用程序框架CAF的插件都有一个XML格式的配置文件,包含了程序启动时需要加载的一系列UIC文件。此文件的默认路径就是安装目录,文件名的命令方式为<模块名>Customisation.xml。例如AVEVA Marine模块Hull Design就有一个名为HullDesignCustomisation.xml的配置文件,文件内容如下所示。默认情况下UIC文件也希望在相同的目录下。标专“$1”表示UIC文件的路径将会由当前工程名代替。

 

<? xml version="1.0" encoding="utf-8" ?>  

< UICustomizationSet  xmlns:xsd ="http://www.w3.org/2001/XMLSchema"  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" >  

< UICustomizationFiles >  

< CustomizationFile  Name ="Hull General"  Path ="AVEVA.Marine.UI.HullGeneral.uic"   />  

< CustomizationFile  Name ="Hull Design"  Path ="AVEVA.Marine.UI.HullDesign.uic"   />  

< CustomizationFile  Name ="Project"  Path ="$1.uic"   />  

< CustomizationFile  Name ="StatusControllerAddin"  Path ="StatusController.uic"   />  

</ UICustomizationFiles >  

</ UICustomizationSet >  

 

配置文件中UIC文件的顺序是很重要的,它表示了程序加载这些自定义界面的顺序。一个新的UIC文件可以加载到一个模块中,通过在其配置文件中简单添加一行即可。

与在模块的配置文件中添加UIC文件的功能类似的方法是在程序中编码实现对UIC文件的添加,通过CommandBarManager的方法AddUICustomisationFile来编码实现UIC文件的添加。程序代码如下所示:

 

1  //  Load a UIC file for the AttributeBrowser. 
2 
3  CommandBarManager commandBarManager  =  (CommandBarManager)serviceManager.GetService( typeof (CommandBarManager)); 
4 
5  commandBarManager.AddUICustomizationFile( " AttributeBrowser.uic " " AttributeBrowser " ); 
6 

 

通过具体实例将会看出,通过自定义对话框,配置文件中的UIC文件将会被管理,不用自己手动更改UIC文件中的内容。

 

六、UIC文件的编辑 Editing UIC File

UIC文件是通过通用程序框架CAF的内置交互工具来创建与编辑的,不需要亲自更其中内容。通过在工具栏上右键,选择Customize来启动自定义对话框,如下图所示:

wps_clip_image-4427

自定义对话框主要由七个部分组成:

① CommandBar Preview Area

② Active Customisation File

③ Tree showing CommandBars

④ List of tools

⑤ Property grid

⑥ Action buttons

⑦ Resource Editor

wps_clip_image-7897

wps_clip_image-27513

以下将会以具体实例来介绍相应的用法。更多细节请参考《AVEVA .NET Customisation User Guide》。通过自定义对话框,UIC文件中的内容将会被AVEVA管理,所以创建自定义的菜单或工具栏按钮,都从这个自定义对话框中编辑,还是很方便。

 

七、程序实例 Codes

本节以一个具体实例来说明AVEVA .Net的菜单的自定义及与相关命令的关联方法。步骤如下:

1. 创建一个C#的类库(Class Library),工程名为HelloWorld,并选择.NET Framework 3.5,如下图所示:

wps_clip_image-19242

2. 添加引用Aveva.ApplicationFramework.dll和 Aveva.ApplicationFramework.Presentation.dll,如下图所示:

wps_clip_image-11032

添加完后的引用库如下图所示:

wps_clip_image-24383

3. 编写一个插件类HelloAddin,派生自IAddin,并实现那四个虚函数,程序代码如下所示:

 

 1  using  System; 
 2 
 3  using  System.Collections.Generic; 
 4 
 5  using  System.Text; 
 6 
 7  using  Aveva.ApplicationFramework; 
 8 
 9  using  Aveva.ApplicationFramework.Presentation; 
10 
11  namespace  HelloWorld 
12 
13 
14 
15  public   class  HelloAddin : IAddin 
16 
17 
18 
19  #region  IAddin Members 
20 
21  public   string  Description 
22 
23 
24 
25               get  
26 
27 
28 
29  return   " AVEVA .Net Menu Customisation Demo. "
30 
31 
32 
33 
34 
35  public   string  Name 
36 
37 
38 
39               get  
40 
41 
42 
43  return   " HelloAddin "
44 
45 
46 
47 
48 
49  public   void  Start(ServiceManager serviceManager) 
50 
51 
52 
53  //  Stop for attaching to the process. 
54 
55              System.Windows.Forms.MessageBox.Show( " Debug " ); 
56 
57 
58 
59  public   void  Stop() 
60 
61 
62 
63 
64 
65  #endregion  
66 
67 
68 
69 
70 
71 


4. 添加一个用户控件(User Control)而不是一个窗口(Windows Form),如下图所示:

wps_clip_image-5158

5. 自定义用户控件上内容,本例仅在其上添加最简单的label为例,添加后并将其内容改为“Hello World”,如下图所示:

wps_clip_image-22989

6. 添加命令类HelloWorldCommand,派生自抽象基类Command,并实现几个关键的方法。如在其构造函数中添加Key属性,Key属性在后面添加菜单时很重要。还有必须实现的Execute方法。程序代码如下所示:

 

 1  using  System; 
 2 
 3  using  System.Collections.Generic; 
 4 
 5  using  System.Text; 
 6 
 7  using  Aveva.ApplicationFramework.Presentation; 
 8 
 9  namespace  HelloWorld 
10 
11 
12 
13  class  HelloWorldCommand : Command 
14 
15 
16 
17  private  DockedWindow myWindow; 
18 
19  //  Default Constructor. 
20 
21  public  HelloWorldCommand(DockedWindow window) 
22 
23 
24 
25  //  Set the command key. 
26 
27  //  This is very import!!! 
28 
29  this .Key  =   " Aveva.HelloWorldCommand "
30 
31  //  Save the docked window. 
32 
33              myWindow  =  window; 
34 
35  //  Create an event handler for the window closed event. 
36 
37              myWindow.Closed  +=   new  EventHandler(_window_Closed); 
38 
39  //  Create an event handler for the windowLayoutLoaded event. 
40 
41              WindowManager.Instance.WindowLayoutLoaded  +=   new  EventHandler(Instance_WindowLayoutLoaded); 
42 
43 
44 
45  void  _window_Closed( object  sender, EventArgs e) 
46 
47 
48 
49  this .Checked  =   false
50 
51 
52 
53  void  Instance_WindowLayoutLoaded( object  sender, EventArgs e) 
54 
55 
56 
57  //  Update the command state to match initial window visibility. 
58 
59  this .Checked  =  myWindow.Visible; 
60 
61 
62 
63  //  This method must be overriden to provide the command execution functionality. 
64 
65  public   override   void  Execute() 
66 
67 
68 
69  //  Always show the DockedWindow. 
70 
71              myWindow.Show(); 
72 
73 
74 
75 
76 
77 
78 
79 


7. 在派生自IAddin的类中的Start方法中添加创建可停靠窗口的代码,并将命令添加通用程序框架的命令集合中去,程序如下所示:

 

 1  public   void  Start(ServiceManager serviceManager) 
 2 
 3 
 4 
 5  //  Stop for attaching to the process. 
 6 
 7              System.Windows.Forms.MessageBox.Show( " Debug " ); 
 8 
 9  //  Get the WindowManager service. 
10 
11              WindowManager windowManger  =  (WindowManager)serviceManager.GetService( typeof (WindowManager)); 
12 
13  //  Create a docked window to host and Hello World User control. 
14 
15              DockedWindow myWindow  =  windowManger.CreateDockedWindow( " Aveva.HelloAddin.UserControl "
16 
17  " HelloWorld "
18 
19  new  HelloAddinControl(), 
20 
21                  DockedPosition.Right); 
22 
23  //  Create and register Addin's command. 
24 
25              CommandManager commandManager  =  (CommandManager)serviceManager.GetService( typeof (CommandManager)); 
26 
27              HelloWorldCommand showCommand  =   new  HelloWorldCommand(myWindow); 
28 
29              commandManager.Commands.Add(showCommand); 
30 
31 
32 
33 


8. 编译工程(Build HelloWorld),并将生成的动态库(HelloWorld.dll)复制到AVEVA的安装目录;

9. 修改配置文件,使其加载该插件,修改方法如下图所示:

wps_clip_image-4719

10. 添加自定义菜单,方便插件的调用。在工具栏的任意位置点击鼠标右键,选择Customize,出现自定义的对话框,并在Active Customization File 的选项框中选择Module,如下图所示:

wps_clip_image-26549

在Menubar中添加自定义菜单项,将其名称改为MenuTest,如下图所示:

wps_clip_image-22156

在对话框中间任意位置点鼠标右键,添加一个按钮(button),如下图所示:

wps_clip_image-14721

修改按钮的标题为ButtonTest,修改其命令(Command),在Core Command中选择我们创建的命令类的Key,如下图所示:

wps_clip_image-20459

将按钮拖到左边的菜单下后,Apply结束。如下图所示:

wps_clip_image-9665

11. 自定义后的菜单如下图所示:

wps_clip_image-5167

 

八、结论 Conclusion

通过实例对AVEVA .Net的二次开发有了便全面的认识,可以通过自定义菜单方便调用二次开发的插件。自定义菜单或者工具栏按钮主要是通过自定义对话框来实现,不需要程序员手动修改UIC文件,交互操作使用方便。

若有术语用词不当之处,敬请指出。eryar@163.com

 

九、参考资料 Bibliography

1. AVEVA .Net Customisation User Guide 本文基本上是对这个Guide的部分翻译。

2. GoF book: Design Patterns Elements of Reusable Object-Oriented Software 对Command模式感兴趣的可以一读。

 

目录
相关文章
|
7月前
|
开发框架 JSON .NET
ASP.NET Core 自定义配置警告信息
自定义配置警告信息需要在 startup 类中的 ConfigureService 方法中进行配置示例: // 注册 控制器服务 services.AddControllers(configure: setup => { setup.ReturnHttpNotAcceptable = true; ...
50 0
|
8月前
|
XML 存储 JSON
使用自定义XML配置文件在.NET桌面程序中保存设置
本文将详细介绍如何在.NET桌面程序中使用自定义的XML配置文件来保存和读取设置。除了XML之外,我们还将探讨其他常见的配置文件格式,如JSON、INI和YAML,以及它们的优缺点和相关的NuGet类库。最后,我们将重点介绍我们为何选择XML作为配置文件格式,并展示一个实用的示例。
99 0
|
11天前
|
XML API 数据库
七天.NET 8操作SQLite入门到实战 - 第六天后端班级管理相关接口完善和Swagger自定义配置
七天.NET 8操作SQLite入门到实战 - 第六天后端班级管理相关接口完善和Swagger自定义配置
|
6月前
|
Windows
基于.Net Core实现自定义皮肤WidForm窗口
基于.Net Core实现自定义皮肤WidForm窗口
62 0
|
7月前
|
开发框架 中间件 .NET
ASP.NET CORE 自定义中间件
ASP.NET CORE 自定义中间件
46 0
|
8月前
|
存储
.NET Core - 自定义配置数据源:低成本实现定制化配置方案
.NET Core - 自定义配置数据源:低成本实现定制化配置方案
|
8月前
.NET Core-自定义配置数据源
前面,我们学习了配置框架的4种配置方式,那么你知道如何实现自定义的配置数据源吗?知道如何低成本实现定制化配置方案吗?下面我们就一起来学习一下吧。
|
11月前
|
C#
.NET Core反射获取带有自定义特性的类,通过依赖注入根据Attribute元数据信息调用对应的方法
.NET Core反射获取带有自定义特性的类,通过依赖注入根据Attribute元数据信息调用对应的方法
127 0
|
开发框架 中间件 .NET
asp.net core 自定义中间件【以dapper为例】
asp.net core 自定义中间件【以dapper为例】
133 0
|
前端开发 BI C#
手麻系统源码,C# .net 桌面软件,采用下拉式汉化菜单,界面友好,实用性强
提供手术病人检索、手术申请、手术安排、急诊手术,查看手术申请单、查看手术通知单,填写病人术前会诊记录、谈话记录、麻醉记录,器械准备、手术记录、附加手术、器械清点及术后护理信息等功能。 提供手术查询、手术报表查询、术后信息统计等查询功能。
手麻系统源码,C# .net 桌面软件,采用下拉式汉化菜单,界面友好,实用性强