Tuesday 15 July 2014

k2 Custom SmartControl: XML Definition

This is an extension of the previous post, so if you haven't set up a Visual Studio k2 CustomControl project go back and do so here.

Picking up where we left off, add a folder to your project and call it MySmartControl, as the name insinuates this will be where all your smart control assets will live. to get started, lets add the following to our custom control
  • an icon that will only be visible in design time, use the one above
  • an xml definition which describes our control and how it will interact in the k2 designer
  • a .cs file that is the server representation 
  • a .js file that is the client representation 
Now remember that everything other then your .cs file has to have it's build action set to Embedded Resource, you accomplish this by right clicking on the asset and hitting properties or the F4 key.

with that complete your solution explorer should look something like


Now lets get started with the xml definition file.
Think of this as the description of the endpoints that the k2 designer will use to interact with your smart control through the forms and rules. there really is no logic here, just definitions of things like:
  • Properties that can be set at design time
  • A value that your control can have
  • Events that your control can react to through the rules
  • Methods that can be fired from the rules
  • Styling
along with these interaction definitions there are also passive definitions, such as what will the controls category be, display name, system name, the full name etc.

So to make a very simple xml definition lets take a look at the following.

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

<ControlType>
  <!--the control type, options are Display, Input, Listing and Action.
      If you want to be able to set and get a value on your control it
      can’t be of type Display.-->
  <Category>Input</Category>

  <!--The grouping category where the control will be listed inside
      the Designer-->
  <Group>Custom</Group>

  <!--the Name that will show up in the Designer-->
  <DisplayName>My Smart Control</DisplayName>
 
  <!--This is the short name for the control type that is platform independent.
      It is the name of the control type stored in Form and View definitions. -->
  <Name>MySmartControl</Name>

  <!--The full name of the control used to load and instantiate the control.
      Format: {TypeFullName},{AssemblyName}-->
  <FullName>MyCustomControls.MySmartControl, MyCustomControls</FullName>

  <!--***********************************************************************-->
 
  <!--JavaScript Functions responsible for
      getting and setting the value of our Control-->
  <GetValueMethod>MyCustomControls.MySmartControl.getValue</GetValueMethod>
  <SetValueMethod>MyCustomControls.MySmartControl.setValue</SetValueMethod>

  <!--The typd of data that your control's value can be set to
      The Following are options:
      AudoGuid    AutoNumber    DateTime  Decimal   File  Guid  Text     
      Hyperlink   MultiValue    Image     YesNo     Xml   Memo  Number -->
  <DataTypes>
    <DataType>Text</DataType>
    <DataType>Memo</DataType>
  </DataTypes>

  <!--***********************************************************************-->

  <!--Events lists all the events that the control exposes. These events are listed in the Rules editor.
      Event handlers for non-standard JQuery events must be implemented in the control's .js file -->
  <Events>
    <Event>OnClick</Event>
    <Event>OnChange</Event>
  </Events>

  <!--DefaultEventName is the default event that the Rules composer will select when the designer creates
      a rule for the control-->
  <DefaultEventName>OnClick</DefaultEventName>

  <!--***********************************************************************-->
 
  <!--JavaScript Functions responsible for
      getting and setting properties of our Control-->
  <SetPropertyMethod>MyCustomControls.MySmartControl.setProperty</SetPropertyMethod>
  <GetPropertyMethod>MyCustomControls.MySmartControl.getProperty</GetPropertyMethod>

  <!--A Collection of properties that can be set at Design time-->
  <Properties>
    <!--Control Name is a property on the k2 Base Control,
        Thus it doesn't neeed a backing Property explicitly defined in
        our .cs file-->
    <Prop ID="ControlName" mappable="false" refreshdisplay="true"
          ValidationPattern="\S"  ValidationMessage="InvalidName"         
          friendlyname="Name" type="string"
          category="Detail" inputlength="255" />
   
    <!--ControlProperty01 is our own custom property so it does have
          to be explicitly defined in our .cs file-->
    <Prop ID ="ControlProperty01" mappable="true" refreshdisplay="true" ReadOnly="false"
          friendlyname="Control Property01" type="string"  category="Detail"
          inputlength="255">
      <Value>prop01</Value>
    </Prop>
   
  </Properties>

  <!--Prop Attributes-->
 
  <!--ID: the Name of the property that has to be mapped to a
          corrisponding server side Property-->
 
  <!--mappable: a boolean attribute that specifies if the property can be set
                or retrieved from within the form rules-->
 
  <!--refreshDispaly: if set to true will reload the control, using the
                      Server Side RenderControl(HtmlTextWriter) Method-->
 
  <!--freindlyName: the display name that is shown in the k2 designer-->
 
  <!--type: the type that the property can be, options are string, int, -->
 
  <!--ReadOnly: if the value can be set through the properties pane in the
                k2 designer or not-->

  <!--category: the grouping in the properties pane of the k2 designer-->
 
  <!--ValidationPattern: a regex that validates property input-->
 
  <!--ValidationMessage: a magic string for a message that will pop up
                         should the validation pattern fail-->

  <!--***********************************************************************-->

  <!--Javascript function responsible for handling all defined methods-->
  <ExecuteMethod>MyCustomControls.MySmartControl.execute</ExecuteMethod>
 
  <!--Methods are mappings from the k2 rules to methods set up in
      the client side javascript file, this allows you execute javascript
      code from the k2 rules-->
  <Methods>
   
    <Method ResultType="None">
      <!--Name: is the internal name used by k2, it's also the name that the
          client side .js file will use to switch on-->
      <Name>ShowAlert</Name>
     
      <!--DisplayName is the nice name that will show up in the control
          settings when the method is being set up in the k2 rules-->
      <DisplayName>Show Alert</DisplayName>

      <Description>
        This method takes in a string and displays it in a standared JavaScript alert
      </Description>

      <!--Parameters is a collection of input parameters that can be passed into a method-->
      <Parameters>
        <!--The Datatype will be displayed to the user in the k2 form, but will be passed to
            the .js file as a string, so you'll have to parse numbers booleans seem ok-->
        <Parameter DataType="Text">
          <!--Name is the internal identifier of the parameter being passed in, it is a
          best practice to always use lower case names, this is because no matter what that's
          how they can be used in the javascript-->
          <Name>message</Name>
          <DisplayName>Message</DisplayName>
          <Description>The message to be displayed</Description>
          <IsRequired>true</IsRequired>
        </Parameter>
      </Parameters>
    </Method>

    <!--by setting the result type to something other then "None" we can do an output mapping
        int the k2 form rules-->
    <Method ResultType="Number">
      <Name>Add</Name>
      <DisplayName>Add</DisplayName>
      <Description>Adds two numbers</Description>
      <Parameters>
        <Parameter DataType="Number">
          <Name>addendone</Name>
          <DisplayName>Addend One</DisplayName>
          <Description>The first number to be added</Description>
          <IsRequired>true</IsRequired>
        </Parameter>
        <Parameter DataType="Number">
          <Name>addendtwo</Name>
          <DisplayName>Addend Two</DisplayName>
          <Description>The second number to be added</Description>
          <IsRequired>true</IsRequired>
        </Parameter>
        <Parameter DataType="Boolean">
          <Name>double</Name>
          <DisplayName>Double Sum</DisplayName>
          <Description>Multiply the sum by two</Description>
          <!--keep in mind that if it's not specified the value doesn't 
              default to false, but is undefined-->
          <IsRequired>false</IsRequired>
        </Parameter>
      </Parameters>
    </Method>
  </Methods>

</ControlType>

The XML Definition file, defines the endpoints that are used to communicate between the K2 environment and the actual control. These endpoints are exposed in the K2 designer as properties, events and methods:

  • Properties: are fields that store values, they are set during design time and used to set things control name, is enabled or visible or any number of custom properties that we implement. To get an idea of properties that are available inspect the K2 BaseControl class. If a property is not available on the base control it can defined in our custom control server class.
  • Events: are interactions that the control can initiate within the rules, basically a way for the control to fire logic defined in the K2 Form, for example on clicking the control display a K2 modal window.
  • Methods: are a way for the K2 Form rules to execute logic that is contained within the custom control.
  • Interaction JS Methods: these are the getters and setters defined in your Client Side .js file for interaction with the control value as well as the control properties, we defined them get/setValueMethod and get/setPropertyMethod xml elements.

Now it's important to differentiate between the server (.cs ) and client (.js) parts of our control. the server is what renders the control initially, whereas the client part is responsible for the on form interactions. this means that things like properties have to be maintained in both instances.

Next let's look at the Server side part of our control.