Vici MVC allows you to create your own custom controls. These controls can then be used at runtime or they can be bound to a form if you create an associated field attribute for the control.
To create a custom control, you have to derive a class from the abstract Control class and override the GenerateHtml(), HandlePostback() and DataSource methods
To illustrate the creation of a custom control, we will create a simple control representing a text box:
public class CustomTextBoxControl : Control { private string _value = ""; private int _maxLength = Int32.MaxValue; private int _size = 0; public CustomTextBoxControl(string name) : base(name) { } public string Value { get { return _value; } set { _value = value ?? ""; } } public int MaxLength { get { return _maxLength; } set { _maxLength = value; } } public int Size { get { return _size; } set { _size = value; } } protected override string GenerateHtml(View view, string className, string classError) { string s = "<input type=\"text\" value=\"" + HttpUtility.HtmlEncode(_value) + "\""; s = AddIdAttribute(s); s = AddNameAttribute(s); s = AddClassAttribute(s, className, classNameError); s = AddEnabledAttribute(s); s = AddOnChangeAttribute(s); if (Size != 0) s += " size=\"" + Size + "\""; if (MaxLength != Int32.MaxValue) s += " maxlength=\"" + MaxLength + "\""; return s + "/>"; } protected override void HandlePostback(ClientDataCollection postData) { if (postData.Has(Name)) _value = postData.Get(Name); } public override object DataSource { get { return null; } set { } } }
Three methods are required for a custom control:
GenerateHtml() is called by the framework when the control needs to be rendered. The method should return plain XHTML.
Parameters:
The base Control class has some common properties such as "Id", "Name" and "Enabled". HTML attributes for these properties can be added by calling the following methods:
In the example above you can see how you should use these methods.
Parameters:
The abstract Control class has a few properties that are valid for all controls:
| Property | Type | Description | |
|---|---|---|---|
| Id | String | The XHTML id to render the control with. This should be unique across the rendered page. If not set, the framework will generate a unique id for you. | |
| Name | String | The name of the control, which is required and should only be set by the constructor | |
| Error | Boolean | If set to true, the control will be renderd with the CSS class defined by the CssClassError property. If false, the CSS class defined by CssClass will be used | |
| CssClass | String | The CSS class name to use when rendering the control (if the Error property is false) | |
| CssClassError | String | The CSS class name to use when rendering the control (if the Error property is true) | |
| AutoPost | Boolean | Setting this to true will render the attribute onchange="this.form.submit()" | |
| OnChange | String | Defines a line of javascript to execute when the control is changed on the client. The javascript will be prepended to the javascript generated by the AutoPost property | |
| Enabled | Boolean | Setting this to false causes the control to be renderd with the disabled="disabled" attribute | |
It's important to remember that the framework will not autmatically render the required attributes for custom controls. You should call the methods AddIdAttribute(), AddNameAttribute(), etc. This is necessary because not all of these attributes are valid for all kinds of controls. You may also want to handle these properties yourself (for example, when creating complicated composite controls).
To use your custom controls in the Vici MVC form handling framework, you should create a companion FormFieldAttribute class. This attribute tells Vici MVC which control to render when generating a form and how to handle the postback from the client.
Let's look at the implementation of the FormCheckboxAttribute:
public class FormCheckboxAttribute : FormFieldAttribute { public string OnClick; protected internal override bool IsRightType() { return FieldType == typeof(bool); } protected internal override object GetControlValue(Control control) { return ((CheckBoxControl)control).Checked; } protected internal override void SetControlValue(Control control, object value) { ((CheckBoxControl) control).Checked = (bool) value; } protected internal override Control CreateControl(string name) { CheckBoxControl control = new CheckBoxControl(name); control.OnClick = OnClick; return control; } protected internal override bool Validate(Control control) { return true; } }
You should create a class derived from FormFieldAttribute, and override the following methods:
The CreateControl() method should create a control of the required type. This can be a custom control or one of the [[Projects:Mvc:UserGuide:Controls|built-in controls]. You should set all the required properties on the control, according to properties of the attribute. In the example above, we have defined a named proprty OnClick which can be specified when using the attribute. This property is then passed on to the control.
Note the name parameter. This should be used when creating the control (it's always a required constructor parameter for any control)
This method should retrieve the value of a control and return it. Make sure the returned value can be converted to the type of the associated field. The type of the associated field can be retrieved by the FieldType property, which is defined in the base class (FormFieldAttribute)
This method sholud set the value of the control. The contents of the associated field is passed as parameter.
This method is called by the framework as a "sanity check", just to make sure you added the attribute to a field of the right type. If you return false, an exception will be thrown. The field type of the associated field is available in the FieldType property of the base class.
Validates the value (passed as a parameter). This method should only check if the value is valid for the field type this attribute is associated with. No business rules should be validated in this method (you can use the form's validation mechanism for that)