This blog post is intended for developers and people doing advanced customizations in Service Manager.
An earlier blog post illustrated how to use the <Form> element in Service Manager’s management pack infrastructure to create rich, custom forms for classes and relationships in the CMDB. Custom forms offer complete flexibility in displaying class and relationship information to end users, and they are well-suited to displaying data that spans multiple classes and relationships or requires unique UI elements.
When the data that needs to be displayed originates in an object of one class, presenting an editable table of property-value pairs is often sufficient. To prevent customers from having to develop these simple forms for each class added to a Service Manager installation, Service Manager ships with a Generic Form that renders a property-value display for any class that does not already appear in a custom form.
This blog post will provide background on the forms infrastructure used in our product and the options available to customize the Generic Form.
Part 1: Understanding the forms infrastructure
Let’s take a look at the <Form> element tag in the ServiceManager.ConfigurationManagement.Library management pack that causes the computer form to display for computer objects in the console.
<Form TypeName=“Microsoft.EnterpriseManagement.ServiceManager.ConfigurationManagement.Forms.ComputerForm“ Target=“Microsoft.Windows.Computer.ProjectionType“ ID=“ComputerForm“ Assembly=“ConfigurationManagementFormsAssembly“ Accessibility=“Public“>
Each attribute in the Form tag indicates the following:
xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office">
The qualified name of the .NET Class that contains the form code.
The class (<ClassType>) or type projection (<TypeProjection>) for which the form should display.
A unique identifier for the form element.
A reference to an <Assembly> MP element that points to the DLL containing the form code. The Assembly element is defined in the <Resources> section of an MP.
The Assembly element for this form is:
<Assembly ID=”ConfigurationManagementFormsAssembly” QualifiedName=”Microsoft.EnterpriseManagement.ServiceManager.ConfigurationManagement.Forms” FileName=”Microsoft.EnterpriseManagement.ServiceManager.ConfigurationManagement.Forms.dll” Accessibility=”Public” />
The accessibility of the form element, set to “Public” here so that this Form element can be referenced by other MPs.
The Target attribute of the form tag links the form to a class or a type projection. When the user selects the “Create” task associated with a view or the “Edit” task associated with an object or object projection, the class to be created or edited is determined. Our UI code then looks for a form that is either (1) targeted to that class or (2) targeted to a type projection that has a seed that is that class. If a form is found, it is displayed. If a form is not found, the check is repeated on each of the parent classes until a form is found.
This logic is summarized in the Figure 1 below:
Figure 1: Form selection process
Note that a form is designated to appear in one of two modes:
1. Pop-out mode, the default, indicates that the form will surface when the “Create” task or the “Edit” task is clicked.
2. Preview mode, which is enabled by adding a category with a special enumeration value and targeting it to the form, indicates that the form will display in the details pane when an item in a grid view is selected.
The search that is performed to find a form for a given object (as depicted in Figure 1) is limited to forms in the desired display mode. For example, when a grid view item is selected, it is determined that a form in preview mode is needed and a search for a form is performed using only the set of forms categorized as preview forms.
The enumeration value used to demarcate a preview form resides in the Microsoft.EnterpriseManagement.ServiceManager.UI.Console management pack. The following category definition, for example, would mark the form named “ClassForm” as a preview form.
<Category ID=“someuniqueID“ Target=“ClassForm“ Value=“Console!Microsoft.EnterpriseManagement.ServiceManager.UI.Console.OverviewForm“ />
Preview and pop-out forms will always be found for a given class because preview and pop-out versions of the Generic Form are targeted to System.Entity, the root class in Service Manager’s class model.
Part 2: The Generic Form
The Generic Form is a WPF UserControl that consists of up to three tabs:
1. A General tab displays all of the properties of the object that serves as the form’s data context. If the data that underlies the form is a projection object, properties are displayed for the seed class object in that projection. Properties in the tab are grouped under their respective classes starting from the top of the class hierarchy (System.Entity) and moving down.
When the object displayed in the form inherits from System.ConfigItem or System.WorkItem:
2. A Related Items tab presents an updatable display of objects related to the object, and
3. A History tab chronicles the changes that have been made to properties on the object and the object’s relationships to other objects.
There are two display modes for the Generic Form. The Generic Preview Form displays property information for the currently selected object in a grid view. Alternatively, the Generic Pop-Out Form displays property information when a class object or projection object is displayed within a form window. These two display modes are juxtaposed below (click to enlarge):
Figure 2: Generic Form displaying a Software Item object in preview mode (left) and pop-out mode (right)
Note that in preview mode, no related items tab or history tab is shown, and the properties in the form are not editable.
The Generic Form appears in four management pack form element (i.e.: <Form> tag) definitions. A preview form and a pop-out form are targeted to the System.Entity base class, one pop-out form is targeted to a type projection with seed class System.ConfigItem, and one pop-out form is targeted to a type projection with seed class System.WorkItem. The pop-out form definitions targeted to the Configuration Item and Work Item type projections are used to populate the Related Items Tab with a standard set of related objects on Configuration Item and Work Item classes.
This is summarized in Figure 3 below.
Figure 3: Occurrence of Generic Form <Form> elements in the class model
Part 3: The Extension Tab
When a pop-out form is displayed in a form window using the Create task or the Edit task, a check is made to determine:
1. The class of the object being displayed, and
2. The class to which the form that is being displayed is targeted.
These classes can differ if the form that was selected to display an object is targeted to one of the parent classes of that object (e.g.: displaying an object of a class derived from Change Request in the Change Request form).
If the form that is being displayed is a custom form and is not the Generic Form (which, by default, displays all of an object’s properties in the General tab), and classes 1 and 2 differ, an Extension tab is added to the custom form. This tab displays property-value pairs for all classes in the object’s class hierarchy that inherit from the form’s target class.
The tab also displays (again, only for custom forms) all of the properties of any extension classes in the class hierarchy of the object. These properties are grouped under the extended class.
Suppose, for example, that a sealed MP were imported with class definitions below:
<ClassType ID=“Incident_Extension“ Base=“CoreIncident!System.WorkItem.Incident“ Abstract=“false“ Accessibility=“Public“ Hosted=“false“ Extension=“true“>
<Property ID=“incident_extension_1“ Type=“string“ />
<Property ID=“incident_extension_2“ Type=“string“ />
<Property ID=“incident_extension_3“ Type=“string“ />
<ClassType ID=“Incident_Derived“ Base=“CoreIncident!System.WorkItem.Incident“ Abstract=“false“ Accessibility=“Public“ Hosted=“false“ Extension=“false“>
<Property ID=“incident_derived_1“ Type=“string“ />
<Property ID=“incident_derived_2“ Type=“string“ />
These definitions extend the System.WorkItem.Incident class with 3 string properties and add a class that derives from System.WorkItem.Incident with 2 string properties.
If a view were created on the Incident_Derived class and the user attempted to create a new Incident_Derived object using the Create task that appears for the view, the user would see the form in Figure 4 below (click to enlarge):
Figure 4: Generic Form displaying an Incident_Derived object with the extension tab. Extension properties and derived class properties appear in the extension tab.
Since any extension properties of an object are shown in the Extension tab, the Incident_Extension properties are shown in the Extension tab. The Incident_Derived properties also appear in the extension tab because the Incident form is targeted to System.WorkItem.Incident and the object being displayed is of the derived class Incident_Derived.
Below, Figure 5 displays all of the classes (in hierarchical order) of which the Incident_Derived object is a member. Our console assumes that only the non-extension properties that appear in the Incident Form’s target class (System.WorkItem.Incident) hierarchy will be displayed in the custom form. Since extension classes and derived classes outside this hierarchy have properties which may not be displayed in the form, the extension tab is added to display the properties of these extended and derived classes.
Figure 5: The properties in the blue classes are assumed to be present in the Incident custom form. Properties in the derived class (red) and the extension class (teal) are added to the extension tab.
To prevent the extension tab from displaying on a form, MP authors can target a category to the form with an Enumeration value in the Microsoft.EnterpriseManagement.ServiceManager.UI.Administration MP:
<EnumerationValue ID=“Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideExtensionTab“ Accessibility=“Public“ />
For example, to prevent the extension tab from displaying in the Incident form in the example above, the following MP could be imported:
<ManagementPack ContentReadable=“true“ SchemaVersion=“1.1“ xmlns:xsd=“http://www.w3.org/2001/XMLSchema“ xmlns:xsl=“http://www.w3.org/1999/XSL/Transform“>
<Category ID=“HideIncidentFormExtensionTab“ Target=“Incident!System.WorkItem.Incident.ConsoleForm“ Value=“Admin!Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideExtensionTab“ />
Part 4: Additional Generic Form Customizations
1. Disabling the preview pane for a class (and its descendants)
To disable the preview form for an object of a particular class, target a category with the enumeration value
<EnumerationValue ID=“Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideDetailsPane“ Accessibility=“Public“ />
(which appears in the Microsoft.EnterpriseManagement.ServiceManager.UI.Administration MP) to the class (not the form) for which the preview pane should not be displayed.
For example, to prevent the Generic Form preview pane (targeted to System.Entity) from appearing when a connector is selected in the grid view under Administration > Connectors, we use the following category:
<Category ID=“Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.ConnectorHideDetails“ Target=“SystemCenter!Microsoft.SystemCenter.Connector“ Value=“Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideDetailsPane“ />
2. Hiding properties in the Generic Form in Preview and Edit Modes
To remove properties that appear in the preview and pop-out versions of the Generic Form, two view types defined in the Microsoft.EnterpriseManagement.ServiceManager.UI.Authoring MP are used. The PreviewViewType excludes properties that appear in the preview version of the form while the EditViewType excludes properties that appear in the pop-out version of the Generic Form.
To hide properties in either form mode, an MP author creates a view based on the desired view type in an MP and targets it to the class that contains the properties that should be removed. The configuration supplied to the view specifies the classes for which the properties should not appear and the names of the properties that should not appear. If no target classes are specified, it is assumed that the properties on the target class should be excluded whenever they are displayed (i.e.: for a Generic Form displayed with any class object).
In our console, we use the following view definition to exclude properties of the System.User class in the Generic Preview Form when displaying objects of AD User Groups:
<View ID=“UserPreviewExclusionRule“ Accessibility=“Public“ Enabled=“true“ Target=“System!System.User“ TypeID=“Authoring!PreviewViewType“ Visible=“true“>
We use the view definition below to prevent the ObjectStatus property from appearing on the pop-out Generic Form for Configuration Items. If this view definition were not present, users would be able to change the status of a Configuration Item in the forms that appear for Software, Software Updates, and Printers (we use the Generic Form for those classes).
<View ID=“ConfigItemExclusionRule“ Accessibility=“Public“ Enabled=“true“ Target=“System!System.ConfigItem“ TypeID=“Authoring!EditViewType“ Visible=“true“>
Note that, here, the list of TargetClasses is omitted from the view configuration. As a result, the ObjectStatus property will be excluded whenever the pop-out Generic Form appears for a Configuration Item object.