Custom Picker

Learn to create a simple text box with a custom picker

In the following example, you will:

  1. create a text box with a picker button as a custom ASP.NET control
  2. create a custom dialog as a ASPX page
  3. register the custom control in C1 CMS configuration
  4. use it on a data form

Creating a custom control

First, you need to find a place for your ASCX file on your website. We recommend that you place it in ~/Composite in its own subfolder.

  1. In ~/Composite, create this folder structure: CustomControls/CustomFormControl/controls.
  2. In the “controls” folder, create a custom control file “CustomFormInput.ascx”.
  3. Add the following code and save it:
<%@ Control Language="C#" Inherits="Composite.Plugins.Forms.WebChannel.UiControlFactories.TextInputTemplateUserControlBase"  %>
<%@ Import Namespace="Composite.Data.Validation.ClientValidationRules" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.IO" %>

<script type="text/javascript">
	if (!ViewDefinitions["Composite.Samples.CustomFormDialog"]) {
		ViewDefinitions["Composite.Samples.CustomFormDialog"] = new DialogViewDefinition({
			isMutable: true,
			handle: "Composite.Samples.CustomFormDialog",
			position: Dialog.MODAL,
			url: "${root}/CustomControls/CustomFormControl/dialogs/customformdialog.aspx",
			argument: {
				"selectedResult": null
			}
		});
	}
</script>

<script runat="server">
    private string _currentStringValue = null;

    protected void Page_Init(object sender, EventArgs e)
    {
        if (_currentStringValue == null)
        {
            _currentStringValue = Request.Form[this.UniqueID];
        }
    }
    
    protected override void BindStateToProperties()
    {
        this.Text = _currentStringValue;
    }

    protected override void InitializeViewState()
    {
        _currentStringValue = this.Text;
    }

    public override string GetDataFieldClientName()
    {
        return this.UniqueID;
    }

</script>
<ui:datainputdialog id="<%= this.UniqueID  %>" handle="Composite.Samples.CustomFormDialog" name="<%= this.UniqueID  %>" value="<%= Server.HtmlEncode(_currentStringValue) %>" readonly="true" />

Download CustomFormInput.ascx

Some code highlights:

  • The control inherits from the standard text box: Composite.Plugins.Forms.WebChannel.UiControlFactories.TextInputTemplateUserControlBase
  • The script run at the server contains standard code to initialize and properly set the control in the methods: Page_Init, BindStateToProperties, InitializeViewState, GetDataFieldClientName
  • The picker button is represented by the <ui:datainputdialog/> control.
  • The click on the button is handled by invocation of a custom dialog (Composite.Samples.CustomFormDialog).
  • As the dialog is custom, the control also includes a JavaScript that creates and initializes this dialog
  • The dialog is the ASPX page you'll create in the next step.
  • The path to the dialog is specified in the handler (${root}/CustomControls/CustomFormControl/dialogs/customformdialog.aspx), which you can change to your own if needed.

You also need to register the control in C1 CMS (see below).

Creating a custom dialog

  1. In ~/Composite/CustomControls/CustomFormControl, create a folder named “dialogs”.
  2. In the “dialogs” folder, create an ASPX page “customformdialog.aspx”.
  3. Add the following code and save the file:
<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://www.w3.org/1999/xhtml" xmlns:control="http://www.composite.net/ns/uicontrol">

<%@ Page Language="C#" %>

<control:httpheaders runat="server" />
<head>
	<title>Composite.Samples.CustomFormDialog</title>
	<control:styleloader runat="server" />
	<control:scriptloader type="sub" runat="server" />
	<script type="text/javascript" src="CustomFormDialogPageBinding.js"></script>
</head>
<body>
	<ui:dialogpage binding="CustomFormDialogPageBinding">
		<ui:pagebody>
			<ui:fields>
				<ui:fieldgroup>
					<ui:field>
						<ui:fielddesc>Text 1</ui:fielddesc>
						<ui:fielddata>
							<ui:datainput id="text1" />
						</ui:fielddata>
					</ui:field>
					<ui:field>
						<ui:fielddesc>Selector 1</ui:fielddesc>
						<ui:fielddata>
							<ui:selector id="selector1">
								<ui:selection label="Value 1" value="1" />
								<ui:selection label="Value 2" value="2" />
								<ui:selection label="Value 3" value="3" />
							</ui:selector>
						</ui:fielddata>
					</ui:field>
				</ui:fieldgroup>
			</ui:fields>
		</ui:pagebody>
		<ui:dialogtoolbar>
			<ui:toolbarbody align="right" equalsize="true">
				<ui:toolbargroup>
					<ui:clickbutton label="${string:Website.Dialogs.LabelAccept}" response="accept" focusable="true" default="true" id="buttonAccept" />
					<ui:clickbutton label="${string:Website.Dialogs.LabelCancel}" response="cancel" focusable="true" />
				</ui:toolbargroup>
			</ui:toolbarbody>
		</ui:dialogtoolbar>
	</ui:dialogpage>
</body>
</html>

Download customformdialog.aspx

Some code highlights:

  • The standard C1 CMS's markup is used to build the UI of the dialog.
  • The dialog contains to fields: "Text 1" (text box) and "Selector 1" (drop down selector)
  • The selector contains three values: "Value 1", "Value 2", "Value 3".

Also create a JavaScript that will do the binding between values in the dialog's fields and those on the data form:

  1. Create a JavaScript file “CustomFormDialogPageBinding.js”.
  2. Add the following code and save the file:
CustomFormDialogPageBinding.prototype = new DialogPageBinding;
CustomFormDialogPageBinding.prototype.constructor = CustomFormDialogPageBinding;
CustomFormDialogPageBinding.superclass = DialogPageBinding.prototype;

/**
 * @class
 */
function CustomFormDialogPageBinding () {

	/**
	 * @type {SystemLogger}
	 */
	this.logger = SystemLogger.getLogger ( "CustomFormDialogPageBinding" );
	
	/**
	 * @type {string}
	 */
	this._value = null;

}

/**
 * Identifies binding.
 */
CustomFormDialogPageBinding.prototype.toString = function () {
	
	return "[CustomFormDialogPageBinding]";
}

/**
 * @overloads {PageBinding#setPageArgument}
 * @param {object} arg
 */
CustomFormDialogPageBinding.prototype.setPageArgument = function ( arg ) {
	
	CustomFormDialogPageBinding.superclass.setPageArgument.call ( this );

	this._value = arg.selectedResult;
}

/**
 * @overloads {DialogPageBinding#onBeforePageInitialize}
 */
CustomFormDialogPageBinding.prototype.onBeforePageInitialize = function () {
	
	var map = this.bindingWindow.bindingMap;

	var list = this._value.split(',');

	var field1 = list[0];
	var field2 = list[1];

	if (field1)
		map.text1.setValue(field1);
	if (field2)
		map.selector1.setValue(field2);
	
	CustomFormDialogPageBinding.superclass.onBeforePageInitialize.call ( this );
}


/**
 * @overloads {DialogPageBinding#onDialogAccept}
 */
CustomFormDialogPageBinding.prototype.onDialogAccept = function () {
	
	this.result = new List();

	var field1 = this.bindingWindow.bindingMap.text1.getValue();
	var field2 = this.bindingWindow.bindingMap.selector1.getValue();

	this._value = field1 + "," + field2;

	this.result.add(this._value);
	
	CustomFormDialogPageBinding.superclass.onDialogAccept.call ( this );
}

Download CustomFormDialogPageBinding.js

Some code highlights:

  • The functions are "inherited" from the standard C1 CMS's ones used to handle the initialization and binding in JavaScript.

Registering the custom control in Composite.config

To be able to use the custom text box (CustomFormInput) you need to register it in Composite.config specifying the virtual path to it on the website:

  1. Edit ~/App_Data/Composite/Composite.config
  2. Locate this configuration element:
    /configuration/Composite.C1Console.Forms.Plugins.UiControlFactoryConfiguration/Channels/Channel[@name='AspNet.Management']/Namespaces/Namespace[@name='http://www.composite.net/ns/management/bindingforms/std.ui.controls.lib/1.0']/Factories.
  3. Add this element below after the last ‘Add’ element:
    <add 
    userControlVirtualPath="~/Composite/CustomControls/CustomFormControl/controls/CustomFormInput.ascx" 
    cacheCompiledUserControlType="false" 
    type="Composite.Plugins.Forms.WebChannel.UiControlFactories.TemplatedTextInputUiControlFactory, Composite" 
    name="CustomFormInput" />
  4. Save the file.

The custom control (CustomFormInput.ascx) has been registered as the ‘CustomFormInput’ element, which now can be used in the form markup.

Using the custom control with the custom picker on a data form

  1. Create a global data type.
  2. Add fields making sure at least one of which is of the String type. It will be used for the custom control.
  3. Edit the form markup of this data type.
  4. Locate the TextBox control you’ll be using for the custom control.
  5. Replace the ‘ TextBox’ in the control markup with ‘ CustomFormInput’ so that it looks like this:
    <CustomFormInput Label="Text" Help="" SpellCheck="true">
      <CustomFormInput.Text>
        <cms:bind source="Text" />
      </CustomFormInput.Text>
    </CustomFormInput>
  1. Save the changes.

If you want to make the widget available for selection as a standard one in the data field editor, you need to create and register a widget provider for this custom widget.

Using the data form with custom the control and picker

  1. Add a data item of this global type.
  2. In the custom text box field, click the picker button. The dialog appears.
  3. Type in some text in the field ‘Text 1’.
  4. Select a value from the drop down ‘Selector 1’.
  5. Click OK. Both values appear in the Add Data form separated with a comma.
  6. Save the data item.