Skip to content

MIKE OPERATIONS managers

Introduction

This document focuses on how to develop MIKE OPERATIONS managers.

It assumes that the reader is familiar with programming against the MIKE OPERATIONS business layers. If this is not the case, the reader should first read and understand reference /1/ and /2/.

Accompanying this document is a zip-file with the source code of the Visual Studio solutions and projects discussed in the text.

What is a Manager?

A Manager is set of functionalities and data in the MIKE OPERATIONS shell. At the practical level it is a collection of plugins to the MIKE OPERATIONS Shell or framework, providing the data layer, business layer and UI layer logic and it is represented as a Product in the runtime.config file.

Most of the existing managers include an Explorer and one or more DataViews at the UI layer for the user to work interactively with the data, a business layer consisting of a Module and Lists providing access to the business entities of the managers and a data layer encapsulating the database tables used for storing the data.

But variations do exist:-

  • The Metadata manager does not have explorer but uses tools and property controls to make the information available to the user.

  • The Event Manager has no UI components and may also run without a database data layer and only serves the logic via a Windows Service component.

  • The Dashboard Manager stores information at a web-server and not in the database.

A walk-through

This section describes the steps for implementing a specific Manager, the MyNoteManager which exemplifies many of the aspects of creating a manager in the Platform without requiring difficult data handling logic.

A Manager will normally comprise of several (but not necessarily all) of the following elements:

  • A database

  • Data layer functionality

  • Business layer functionality (Modules and Tools)

  • UI layer functionality (Explorers, Data Views, Toolstrips, Visualizers, Menus, Dialogs etc.)

covering the functionality within a specific domain.

Design of the manager

MyNoteManager is a component to store and handle (view, add, edit, delete) simple notes of text in the database. It will allow the user to organize the notes in a logical folder or group-structure similar to existing managers.

A simple tool to search for notes containing a specific text string is also added as part of the solution.

In brief the requirements of the software are:

  • A note is a piece of text - like a textfile to be edited in Notepad

  • A user must be able to create, update and delete notes

  • A note has a name

  • Notes are logically organized in a tree-structure of groups

  • A group has a name

  • A note is uniquely named within a group (like files in a folder)

  • A note group is uniquely named within another group (like folders in a folder)

  • A user is able to cancel while editing a note

  • The name of the note can be set/changed in the UI. The property grid or in the tree

  • A SearchNote tool can find notes with a special word (text string) in a name or text.

Database scripts

If a database is involved, the necessary scripts to maintain the data model will be established. For the Note Manager, we will create a simple data model with a single table called “note” with columns “id”, “name”, and “text”. And since the notes are grouped, we will create a note group table to handle the groups.

The tables are related. A note has a group_id field linked to the id filed of the group table. The groups are nested (to allow them to form a tree structure) and therefore a group has a parent_id. Groups at the root of the tree have an empty parent_id (or the default value of ‘00000000-0000-0000-0000-000000000000’).

Listing 1 Sample PostgreSQL script

The code can be run using pgAdmin utility or from a command line like the one given below:

"C:\Program Files (x86)\PostgreSQL\9.0\bin\psql.exe" -h localhost -p 5432 -u postgres -v databasename=dhidss -v schemaname=workspace1 -f myscript.sql

Remember to at least create the tables in both template_workspace and workspace1 schemas.

The Visual Studio solution structure

Figure 1 shows a typical example of how to organize a Manager in a Visual Studio solution.

Figure 1 The solution structure

Basically, there should be at least one project (assembly) representing each of the traditional 3 layers in a Manager: Data, Business and UI and a separate project with public interfaces. Furthermore, it often makes sense to separate the basic functionality of the business layer (Modules) from that of the more dynamic business functionality in Tools. Likewise, in the UI layer, it often makes sense to create dedicated projects for e.g. Toolstrips and UITools.

To create a well layered structure, some constraints should be imposed on the project references. The references as shown in Table 1 should be sufficient and introducing more project references or DSS Framework references should be avoided.

Project References Comments
DHI.Solutions.\<Manager>.Interfaces DHI.Solutions.Generic Cross cutting concerns. Can be referenced from everywhere
DHI.Solutions.\<Manager>.Data DHI.Solutions.Generic DHI.Solutions.Generic.Data DHI.Solutions.\<Manager>.Interfaces
DHI.Solutions.\<Manager>.Business DHI.Solutions.Generic DHI.Solutions.Generic.Data DHI.Solutions.Generic.Business DHI.Solutions.\<Manager>.Data DHI.Solutions.\<Manager>.Interfaces
DHI.Solutions.\<Manager>.Tools DHI.Solutions.Generic DHI.Solutions.Generic.Tools DHI.Solutions.\<Manager>.Interfaces
DHI.Solutions.\<Manager>.UI DHI.Solutions.Generic DHI.Solutions.Generic.UI DHI.Solutions.\<Manager>.Interfaces Notice: no reference to the business layer
DHI.Solutions.\<Manager>.UI.Tools DHI.Solutions.Generic DHI.Solutions.Generic.Tools DHI.Solutions.Generic.UI DHI.Solutions.Generic.UI.Tools DHI.Solutions.\<Manager>.Interfaces
DHI.Solutions.\<Manager>.ToolStrips DHI.Solutions.Generic DHI.Solutions.Generic.UI DHI.Solutions.\<Manager>.UI DHI.Solutions.\<Manager>.Interfaces

Table Manager project references

The user should start by creating a MyNoteManager solution with 3 empty projects: MyNoteManager.Business. MyNoteManager.Data and MyNoteManager.Interfaces (delete the default classes that are generated when the projects are created – the code files will be added later).

Data layer

The MIKE CUSTOMIZED Platform offers a standard way to access database tables using NHibernate (an open source project for Object-Relational-Mapping). This impacts on how the data layer should be implemented. It is of course possible to code the data layer as you like, using any access method but the example below illustrates the ‘standard’ way.

The Data Layer is implemented in the MyNoteManager.Data project.

Figure 2 MyNoteManager.Data project

The source-components required to access the two underlying tables are:

  • A “FakeDTO” class which does nothing but exist in the DLL and enables the Platform to load the assembly with the common data access layer.

  • A ‘DAO’ class for each table. These classes inherit basic functionality for DHI.Solutions.Generic.Data for using the NHibernate data access layer, providing standard CRUD type data access.

  • An NHibernate mapping file for each table, expressing the link between Business layer classes and properties, underlying tables and field as well as the relationship between the tables.

FakeDTO

Listing 2 FakeDTO

The FakeDTO implements IDTO defined in the DHI.Solutions.Generic.Interfaces, however it is never used as the implementation, as also indicated in the above listing. It is organized in a subfolder to the project called DAO.

NHibernate mappings

These mapping files express in XML the links between business classes handling the entity of one row in a table and the table fields. One XML file exists for each table. They are organized in a subfolder to the project called Mappings.

Listing 3 NHibernate mapping for MyNote

The above XML says that:

  • Class MyNote in namespace MyNoteManager.Business, located in assembly MyNoteManager.Business links to fields in table “mynote”. They attribute lazy=”true” means NHibernate will only load related data upon request.

  • The property Id of the class is a Guid linking to field “id”

  • The property Name of the class is a string linking to field “name”

  • The property Text of the class is a Text linking to field “text”

  • The property Version of the class is a Guid linking to field “version”

  • The property Group expresses the relationship to table mynote_group on field “group_id”. Many notes can share the same group).

Group is not a simple type property, but actually MyNoteGroup property as will be seen in the business implementation later.

Listing 4 NHibernate mapping for MyNoteGroup

The above XML for MyNoteGroup indicates that:

  • Class MyNoteGroup in namespace MyNoteManager.Business, located in assembly MyNoteManager.Business links to fields in table “mynote_group”

  • The property Id of the class is a Guid linking to field “id”

  • The property Name of the class is a string linking to field “name”

  • The property Version of the class is a Guid linking to field “version”

  • The property Parent expresses the recursive relationship to table mynote_group on field “parent_id” (a group can hold many groups).

Parent is not a simple type property, but actually a MyNoteGroup object as we will see in the business implementation later.

DAO classes

The data access classes (DAO) are in this case a simple class inheriting from the generic DAO class which has been implemented independent of type.

NHibernate uses the DAO classes to construct business objects from the tabular information in the database when reading data and updating table properties when inserting or updating entities.

Listing 5 MyNoteDAO class for entity MyNote

Listing 6 MyNoteGroupDAO class for entity MyNoteGroup

The DAO classes are put in subfolder DAO to the data project.

Interfaces

The interfaces define the Business entities.

Figure 3 The Interfaces project in Visual Studio

As can be seen from Figure 3, interfaces are defined for the module holding the main business functionality, the two entities and a list for each of the two entities (corresponding to the tables).

IMyNote

This interface defines the properties of the business entity of the MyNote.

Listing 7 IMyNote interface

From the above listing it can be seen that:-

  • the IMyNote inherits from a number of generic interfaces:

  • IGroupedEntity – this defines the entity to have a GroupId property

  • INamedEntity – this defines the entity to have a Name property

  • IDTO- this interface defines the entity to have a Version property. Also it defines the entity as a Data Transfer object to be used by NHibernate in the data layer

  • ICloneable – .NET interface to include the Clone method

  • ISelectable - is used to identify the entity as an object which can be selected in the UI and displayed in the property grid.

IMyNoteList

This interface defines the properties of the business entity holding a list of MyNote entities. It corresponds to the table in the data layer.

Listing 8 IMyNoteList interface

From the above listing it must be noted that:-

  • the IMyNoteList inherits from a single generic interface:

  • IGroupedEntityList defines behaviour of a list of grouped entities.

IMyNoteGroup

This interface is organised in a similar way to IMyNote.

Listing 9 IMyNoteGroup interface

From the above listing it can be seen that:-

  • the IMyNoteGroup inherits from a couple of generic interfaces:

  • IGroup defines a standard group in the Platform with id and ParentId, allowing a tree-structure of nested groups

  • IDTO interface defines the entity to have a Version property. It also defines the entity as a Data Transfer object to be used by NHibernate in the data layer

  • ICloneable – .NET interface to include the Clone method

  • ISelectable is used to identify the entity as an object which can be selected in the UI and displayed in the property grid.

IMyNoteGroupList

This interface is almost identical to IMyNoteList but defines a list of groups instead.

Listing 10 IMyNoteGroupList interface

From the above listing it should be noted that:-

  • the IMyNoteGroupList inherits from a single generic interface:

  • IGroupedEntityList defines behaviour of a list of grouped entities.

IMyNoteModule

The business logic of the MyNoteManager should be placed in the module (apart from the properties and methods in the entities and lists above). For this purpose the IMyNoteModule interface is defined, extending the generic IModule interfaces with methods specific for this manager.

The initial version is quite simple and will be extended later when the business functionality is added. It simply inherits from IListModule and adds two properties.

Listing 11 IMyNoteModule interface

From the above listing it can be seen that:-

  • IMyNoteMoldule inherits from a single generic interface: IListModule.

  • This interface inherits from the base IModule interface defining a standard module. The IListModule simply adds a method, CreateNewList to return a list object for a list particular entity type.

  • The two properties MyNoteList and MyNoteGroupList provide access to the entities (equivalent to rows in the tables in the database).

Business layer

The Business layer project contains the implementation of the business logic. To start, the classes implementing the above defined interfaces are created.

Figure 4 The Business layer project

Apart from the C# files the project also includes a resource file allowing localization. Since MyNoteGroup can hold MyNote entities as well as other MyNoteGroup entities, one should start by defining this.

MyNoteGroup

The implementation of MyNoteGroup makes use of the generic BaseGroup class to do most of the work.

Figure 5 Overview of the MyNoteGroup class – collapsed to illustrate the code-parts

The following would still need to be done:

  1. A constructor. Since the class is either created by NHibernate when reading from the database or from the MyNoteGroupList when cfreating a new in code, the constructor is protected internal.

Listing 12 MyNoteGroup constructor

  1. Implementation of IClonable

Listing 13 MyNoteGroup.Clone

  1. Implementation handling the recursive relationship in the database – translating an Id to an entity and vice-versa, see Listing 14.

Listing 14 IMyNoteModule interface

The ParentId property is defined in the IGroup and it maps to field parent_id in the table. The NHibernate mappings for MyNoteGroup defined a many-to-one property named Parent also relating to table field parent_id. The combination of the two makes it possible for NHibernate to establish the links between different objects.

MyNote

The implementation of MyNote makes use of the generic BaseGroupedEntity which handles the basic properties. The class has two member variables for holding the name and text properties.

Figure 6 Overview of the MyNote class – collapsed to illustrate the code-parts

The following are left to do:

  1. A constructor. Since the class is either created by NHibernate when reading from the database or from the MyNoteList when creating a new in code, the constructor is protected internal.

Listing 15 MyNote construtor

  1. Public properties special to MyNoteGroup compared to BaseGroupedEntity, i.e. a name and a text.

Listing 16 MyNote Name property

Listing 17 MyNote Text property

Note how the changes to the properties are announced with events.

  1. Implementation of IClonable

Listing 18 MyNote.Clone

  1. Implementation handling the relationship to the MyNoteGroup in the database – translating an Id to an entity and vice-versa.

Listing 19 Handling of MyNoteGroup in MyNote class

The GrouptId property is defined in the IGroupedEntity and it maps to the group_id field in the table. The NHibernate mappings for MyNote defines a many-to-one property named Group also relating to table field group_id. The combination of the two makes it possible for NHibernate to establish the links between different objects.

MyNoteList

The MyNoteList class inherits from the BaseGroupedEntityList which basically takes care of the implementation of the IBaseGroupedEntityList interface for a list with the combination of IMyNoteGroup and IMyNote entities. In addition to this, the IMyNoteList interface should be implemented.

Figure 7 Overview of MyNoteList class – collapsed to illustrate the code-parts

From the above figure it is worth noting that:-

  • The constructor is internal as a MyNoteList is created only by the CreateNewList\<T> on the module. It initializes the private class variables required by the methods and properties of the class.

Listing 20 MyNoteList constrcutor

  • A set of protected overrides are defined to implement MyNote specific logic replacing the empty implementation in the base class BaseGroupedEntityList.

Listing 21 MyNoteList protected overrides

It is worth noting here that:-

  • The EntityName could be hardcoded as it will probably not be localized.

  • _CreateNew is called by base.CreateNew to create a new entity of the type. If the internal constructor has special requirements one would handle it here (currently not the case).

  • The same MyNoteDAO is used for reading and writing of the entities.

  • _DeleteChildren is called during the base Delete in case an entity has relationships to other entities which also need to be cleaned up. (This is not the case here).

  • _ValidateEntity allows for custom entity validation other than the base implementation (which is empty), e.g. special requirements on the name, note allowing Text to be null, etc.

  • ConcurrencyEnabled – we override the default of “false” as MyNoteList shall allow version to be updated by the system. It will also ensure that version is checked before each save.

MyNoteGroupList

MyNoteGroupList is similar to the MyNoteList, except it inherits from BaseGroupEntityList.

Figure 8 Overview of MyNoteGroupList class – collapsed to illustrated the code parts

Note from the above overview that:-

  • The constructor is internal as a new should be created by the CreateNew\<T> methods on the module. It initializes some private member variables.

Listing 22 MyNoteGroupList constructor

  • A set of protected overrides implement class specific logic for the base class.

Listing 23 MyNoteGroupList protected overrides

Worth noting here is:-

  • The EntityName could be hardcoded as it is likely not going to be localized.

  • _CreateNew is called by base.CreateNew to create a new entity of the type. If the internal constructor has special requirements, one can handle it here (currently not the case).

  • The same MyNoteDAO is used for the reading and writing of the entities.

  • _DeleteEntities is called during the base Delete to find all the entities within the group to be deleted along with it. This implementation makes a query on the MyNoteList to find the MyNote entities with the appropriate GroupId.

MyNoteModule

The MyNoteModule implements the IMyNoteModule interface, but since this inherits from IListModule and IModule a number of methods and properties must be implemented.

Figure 9 Overview of MyNoteModule class – collapsed to illustrated the code parts

This module implementation illustrates:-

  • How to use ThreadSafe access to the entitiy lists. It should be noted from the above class overview that:

  • the use of entity providers as a generalization of the lists

  • the module controls two lists, MyNoteList and MyNoteGroupList.

The constructor of the Module is public.

Listing 24 MyNoteModule constructor

The local variable xThreadSafe reflects a Platform setting in DHI.Solutions.Core.config indicating whether thread safety should be used. By default this setting is “false”.

The public methods and properties of the module are implemented as depicted below.

Listing 25 MyNoteModule public properties and methods

Note from the above listing that:-

  • Name and Description use resources

  • Enabled simply returns true.

  • IsSystemModule must always return false (unless it is actually an implementation of the module in charge of login and other system handling)

  • When the module is loaded by the application during application startup, StartUp method is called and the application reference assigned.

The two lists controlled by the module simply give access to the private member variables. The implementation will allow use of thread safe access to the lists.

Listing 26 MyNoteModule lists

The IModule defines a method CreateNewList\<T> which shall enable the module to provide new lists of different types. This module handles IMyNoteList and IMyNoteGroupList types and simply creates a new list depending upon the type presented in the call.

Listing 27 MyNoteModule CreateNewList method

The IListModule introduces Entity Providers. An IEntityProvider is a class for obtaining enitites from a data source (data base, file, other…), i.e. a generalization of the IEnityList. IEntityList is IEntityProvider, but an IEntityProvider does not have to be an IEntityList.

In most cases in MIKE OPERATIONS will entity providers be in the form of IEntityLists. Listing 28 shows how MyNoteList and MyNoteGroupList are returned as entity providers.

Listing 28 MyNoteModule EntityProviders property

Finally the module has a couple of events, event handlers and private methods.

Listing 29 MyNoteModule event handlers and private methods

UI layer

The UI layer is handled in the MyNoteManager.UI project in the solution. The user should add the following:

  • MyNoteExplorer – to illustrate the groups and entities and show how to make use of a base explorer class.

  • MyNoteDataView - to illustrate a control to display and to edit the MyNote entity.

  • MyNoteToolStrip – a row of buttons with actions working on the selected MyNote entity in the data view.

  • A button to the toolstrip which saves modified notes.

Figure 10 MyNoteManager.UI project in Visual Studio

The example illustrates:

  • How the base explorer provides standard logic for manipulating groups and entities.

  • How the specific explorer can choose between standard options.

  • How the specific explorer can add actions on top of the standard ones.

  • How to handle permissions in relation to the logged in user – optionally greying out choices.

  • How toolstrips and toolstrip buttons are loaded automatically in the UI.

  • How the business entities can be shielded when added to the PropertiesGrid.

MyNoteExplorer

The explorer shows the MyNote entities in a tree-structure defined by the MyNoteGroup entities.

This explorer makes use of a base TreeExplorer class defined in DHI.Solutions.Generic.UI. This base class offers handling of standard operations like Cut, Copy, Paste, drag/drop and allows the individual managers to add custom operations relevant to the entities of the managers.

To start an explorer in the MyNoteManager.UI project, a Windows Form should be added to the project and the code needs to be modified so it starts as shown in the listing below.

Listing 30 MyNoteExplorer – class definition

Note that:

  • Using DHI.Solutions.Generic.UI allows inheriting from TreeExplorer.

  • The explorer holds a reference to the MyNoteManager module which provides access to the entities to display in the explorer.

The rest of the code for this explorer form is two public overrides and a private method.

Listing 31 MyNoteExplorer public overrides

Listing 32 MyNoteExplorer initialization

It should be noted from the above listings that:-

  • _InitializeComponent makes an initial size.

  • Initialize() will:

  • find the module from the Application on the Shell

  • define an imagelist of icons from the resources

  • start a tree branch of the MyNoteGroup and MyNote entities via the GroupedListEntityTreeExplorerBranch

  • Assign a MyNoteGroupExplorerPerspective to the branch to handle the visualization of the tree. This perspective also is assigned a set of icons to use for the tree nodes

The code shows that the TreeExplorer has the ability to be displayed in different ways via perspectives. The most common perspective, which is a GroupedEntityExplorerPerspective plus some custom actions have been used here.

Other perspectives are FlatEntityExplorerPerspective and GroupedListEntityTreeExplorerBranch.

The MyNoteGroupExplorerPerspective is a class on its own.

Listing 33 MyNoteGroupExplorerPerspective – class definition

From the class definition and private members one can see that:-

  • The perspective is an internal class as it is only used by the MyNoteExplorer.

  • It has a private variable linking to the Module.

  • It holds a cache of entities represented in the tree.

  • The two public constants define the custom action and a group of custom actions to be used in the right-click menu in the explorer. Code discussed later in this document, will define the logic behind the actions.

The constructor is simple – it will get the reference to the module and initialize the cache. Likewise a public override of the Manager Name is just as straight forward.

Listing 34 MyNoteGroupExplorerPerspective - initialization

The core logic of the perspective comes in override GetNodeActions. This method should be called at a right-click of a tree-node and a menu consisting of standard and custom actions is presented. So the method will:-

  • Choose which of the base actions provided should be used by this manager, see Listing 35.

  • Adds the custom action for creating a new MyNote in a dataview, including a delegate function for carrying out the action, see Listing 36.

  • Add the custom action for opening/editing a MyNote in a dataview, including a delegate function for carrying out the action, see Listing 37.

Listing 35 MyNoteGroupExplorerPerspective override GetNodeAction (1/3)

The standard actions will result in a right-click menu (will differ, depending whether the root node, a group node or a MyNote node is selected), which allows the user to Refresh a sub-tree (reading from the database), Cut/Copy/Paste nodes in the tree (and likewise entities in the database), add, delete or rename a group and rename entities. (MyNote) drags/drops nodes in the tree (equivalent to regular cut/copy/paste).

In addition to this, one also needs to be able to create a new MyNote entity (available when clicking a group) as well as Edit a MyNote entity (available when clicking an existing MyNote node).

Both of these actions can be added by defining a NodeAction and assigning a couple of properties:

  • Text - the menu text to display (from a Resource string)

  • Enabled – a flag to tell whether it is an active menu item or not

  • ActionCode – a constant code (string) for the menu item

  • ActionGroup – a constant (string) defining the group of menu items to assign it to. With group of items I, the resulting list of node actions will be separated by a menu divider

  • Execute – a delegate function to carry out the work when the menu item is clicked

The Add MyNote menu item will be enabled when the user clicks on a group or the root of the tree, while the Edit menu option is available, provided a single MyNote node has been elected in the tree.

The delegate functions vary slightly in that:-

  • Add will create a new MyNote entity using the MyNoteList the module, before opening a new MyNoteDataView and adding the MyNote entity to it.

  • Edit will search existing views to check if it is not already open, before making a new MyNoteDataView and adding the entity to it.

Finally, GetNodeActions will return the created list of actions and the menu will be drawn.

Listing 36 MyNoteGroupExplorerPerspective override GetNodeAction (2/3)

The above listing shows that:

  • The Add action is defined and added to the menu if group or branch nodes are selected (1) – but only enabled if a single such node is selected (2).

  • The delegate function for the action is defined inline and assigned to the Execute property (3).

  • The delegate function will create a new note entity using the MyNoteList on the module (4), create and open a MyNoteDataView in the shell and assign the new note entity to it (5).

Listing 37 MyNoteGroupExplorerPerspective override GetNodeAction (3/3)

The above listing shows how:-

  • The Edit action is only activated and enabled for a single node (1).

  • The delegate is defined inline and assigned to the Execute property (2).

  • The delegate will locate any existing dataview for the note among the open views (3) or open a new and add the note to the view (4).

Finally, in the MyNoteExplorer two methods can be used to obtain the entities when clicking/selecting in the tree. The public override method GetSelectable constructs a list of objects being selected in the tree. If a group the MyNoteGroup from the node.Tag property is returned, if it is a MyNote node, a wrapper object is created in order to select the properties to avail to the user in the PropertiesGrid control. The private method _GetMyNoteSelectable uses the local cache for a quick lookup of already created wrapper entities – or for creating new wrapper objects.

Listing 38 MyNoteGroupExplorerPerspective override GetSelectable

Note from the listing that:-

  • _myNotePropertiesCache is defined as a private member in the explorer (see Listing 33).

  • GetSelectable identified selected MyNote or MyNoteGroup entities.

The MyNoteProperties class is the wrapper object which defines how properties of MyNote are to be displayed in the PropertiesControl, by category, description and display name attributes. It also defines how the OnPropertyChanged event from the PropertiesControl is to be handled and which properties are to be editable in the grid.

In this example only the Name and Text properties are shown – and only Name can be edited.

MyNoteDataView

This data view is the main view of the MyNote entity. It displays 3 properties of the MyNote:

  • Name

  • Text

  • Version

The latter is read only and only present to illustrate that saving an entity automatically updates the Version. Name and Text can be edited.

To add the form to the MyNoteManager.UI project the user should start by adding a Windows Form and change the code to allow the form to also implement IDataViewControl. This interface from DHI.Solutions.Generic defines the data view type as a DataViewContro,l which has special rules for docking in the Shell.

The user can start by adding a toolstrip container to the form spanning the entire form – and name it “_toolStripContainerMain “. Then three labels must be added (“Name”, “Text” and “Version”) as well as three text boxes (tbName, tbText and tbVersion). tbText is multi-line and tbVersion has enabled=false.

The graphical design of the form is then completed.

Figure 11 Design of MyNoteDataView

Besides implementing IDataViewControl, the form has a public property and a public method of its own:

  • MyNote property for getting and setting the entity to be handled by the form.

  • Save method to perform the saving action – when closing the form with unsaved data (in the _DataViewControls_ControlRemoving handler) or when clicking on the save toolstrip button (will be discussed later in this document).

These are described below.

When the form is initialized a reference is set to the Shell and to the MyNoteManager module and an event handler is set up for closing the form, see the listing below.

Listing 39 MyNoteDataView - initialization

The event handler for closing (or rather removing the control from the list of dataview controls) merely checks if the MyNote entity of the form is modified and offers the user a chance to save the entity – by calling the Save method of the form, see listing below.

Listing 40 MyNoteDataView – handler for closing

The MyNote property gets the private member variable of MyNote from the Form. Or it is used to set the MyNote on the form. While doing so it makes a clone of the values of it – to be able to reset the properties if saving fails. It also sets up a property handler for the OnPropertyChanged event of the private member variable and initializes the text boxes of the form, along with the title of the form (text in the tab-page).

The event handler for OnPropertyChanged event simply maintains the asterix in the window title to indicate if the note is modified.

The Save method (see Listing 42) will either Add or Update the entity on the MyNoteList of the module. If successful, the windows title and the Version text field are updated and the _originalMyNote replaced by a new copy. If not, the properties of MyNote are reset to the _originalMyNote values and the user will be informed with a MessageBox.

Listing 41 MyNoteDataView – MyNote property

Listing 42 MyNoteDataView – Save method

The following should be noted from the above listing:

  • The note is added if it does not already exist in the list – or updated.

  • The caption of the dataview is set after add or update is performed.

  • The value of the Version text box field is updated after add or update, reflecting the value created during the database action.

  • If add or update fails, the content of _myNote is reset from _originalMyNote.

MyNoteToolStrip

ToolStrips are plugins in the Platform. The Shell handles them and automatically adds them to the relevant dataviews. A toolstrip contains one or more buttons with actions on the dataview.

This toolstrip contains only one button (see the next section).

Listing 43 MyNoteToolStrip - initialization

To make a toolstrip the user simply needs to add a Component class to the MyNoteManager.UI project and modify the code to the above listing. The following must be noted from the listing:

  • The class attribute SupportedTypes identifies the data view type(s) for this toolstrip as applicable. In this case only one (1).

  • The class inherits from BaseToolStrip from DHI.Solutions.Generic.UI (2).

  • During initialization, the SaveButton is added with a reference to the toolstrip and a reference to the dataview obtained using GetEmbeddedControl.

SaveButton

The SaveButton is a standard windows ToolStripButton but it also implements IToolStripButton from DHI.Solutions.Generic.Interfaces; making it a known plugin type.

Figure 12 Overview of SaveButton class – collapsed to illustrated the code parts

The constructor is shown in the listing below.

Listing 44 SaveButton constructor

The constructor will:

  • make references to the toolstrip, the dataview and the note (1),

  • update the state of the button (2) and

  • set up an event handler for the OnPropertyChanged event of MyNote (3) which will call the _UpdateButton method for enabling/disabling the button.

The _SaveButton_Click handler calls the MyNoteDataView.Save to perform the updates.

Permissions on actions

The Platform offers a standard way to define permissions on actions in the UI. The base TreeExplorer used this standard behaviour and will enable/disable, show/hide menu option according to definitions in the database.

Table “action” in each workspace defines each menu action with an ActionCode, link the Manager and user role and defines whether to hide or disable a menu action depending on the user role.

Each user (except user admin) has a role in a workspace; workspace_lead, workspace_member or workspace_reviewer. The latter usually only has read access on the tables in the database and should therefore be prevented from using menu actions which will change entity data.

The PostgreSQL script (see Listing 45) will define the permissions for the actions used in MyNoteExplorer for the 3 user roles.

Function set_action inserts definitions of actions for the three roles for a particular manager and action. Each entry has a unique Id generated on the fly. All actions are displayed for all users, but they are disabled for the role workspace_reviewer.

The function for each of the actions causing updates is called once – for both the built-in actions and the custom EDITMYNOTE action. For reviewer this means the right-click menus in the explorer will look like those shown in Figure 13.

Figure 13 Right-click menus for the workspace_reviewer role on root, group and MyNote nodes

Listing 45 SQL scripts for defining action permissions

Hints and best practices

This section provides more details on different aspects related to the development of adapters.

Testing without the UI

The Script Manager can be used to test the business and data layer before starting the UI development. For this to work it is required to perform the following functions:

  • Update the runtime.config by adding a section like this one shown here:

  • Start the application

  • Make and run a script like depicted below.

In the debugger inspection of the progress, line by line can be carried out.

Runtime.config

The MIKE OPERATIONS Platform is a highly configurable platform that can be extended in numerous ways , through custom made tools, views, explorers and job tasks. Although the platform can be used as an application in itself, the primary purpose for it, is to serve as a framework for making specialised applications by means of adding custom tools, job tasks, views, explorers, modules and extensions to the Platform’s user interface shell. All these custom components are called plugins – the plug in functionality to the Platform thus provides the user with a useful application.

All the functionality provided by the Platform comes in the form of plugins. Plugins are much more than custom-made components, they are in fact carriers of all the functionality that comes with the Platform or the application created on top of the Platform.

Plugins are loaded by the Platform based on their presence in the runtime.config configuration file which is located in the application’s installation folder. The only way to load a plugin, is to have it listed in the runtime.config file.

The overall structure of the runtime.config is depicted in Figure 14.

Figure 14 Runtime.config structure

Note from the figure that:-

  • Plugins are grouped in products where a product typically compares to a Platform manager as for example, the Time series Manager.

  • Each product can contain multiple plugins.

  • By convention all plugins not belonging to one of the standard managers, will be placed under the CustomPlugins product node – as indicated by thered text in Figure 14 above.

Each plugin is described by means of three parameters:

  1. Name - should be the fully qualified name of the .NET class implementing the plugin.

  2. Type - defines the type of plugin. The value shall constitute the fully qualified name of the .NET interface that the plugin implements.

  3. Assembly - defines the assembly hosting the plugin. The value shall be the name of the assembly.

Table 2 below defines the possible basic plugin types.

Note: the interface specified as Type in the runtime.config plugin definition shall match or inherit one of these entries.

Plugin interface Type name Description
DHI.Solutions.Generic.IDataViewControl Designates a plugin that acts as a view
DHI.Solutions.Generic.IDTO IDTO is strictly speaking not a plugin, but rather an identification of a class that holds mapping information between tables in the database and .NET classes
DHI.Solutions.Generic.IExplorerControl Designates a plugin that shall act as an explorer
DHI.Solutions.Generic.IMenu Designates a plugin that shall act as a menu
DHI.Solutions.Generic.IModule Designates a plugin that shall act as a business layer module
DHI.Solutions.Generic.IPropertiesControl Designates a plugin that shall act as a property control
DHI.Solutions.Generic.IShellExtension Designates a plugin that shall act as a shell extension, i.e. extending the functionality of the Platform’s UI shell
DHI.Solutions.Generic.ITool Designates a plugin that shall act as a tool
DHI.Solutions.Generic.IToolStrip Designates a plugin that shall act as a tool strip

Table Plugin types