Showing posts with label Y/N Field. Show all posts
Showing posts with label Y/N Field. Show all posts

Tuesday, 28 July 2009

Dynamic Data Custom Field Template – Values List, Take 2

An alternative way of doing the Dynamic Data Custom Field Template – Values List this version uses the UIHint’s ControlParameters property to pass in values to the control.

[MetadataType(typeof(Value.Metadata))]
partial class Value
{
    internal class Metadata
    {
        public object Id { get; set; }
        [UIHint("ValuesList", null, "ValueList", "Y,N,N/A")]
        //[ValuesList("Y,N,N/A")]
        public object TestR { get; set; }
        [UIHint("ValuesList", null, "ValueList", "Y,N,Other")]
        //[ValuesList("Y,N,Other")]
        public object Test { get; set; }
    }
}

Listing 1 – Metadata using the UIHint’s ControlParameters

See the example of using UIHint’s ControlParameters in Listing 1. In the above example you can see that I am passing in the ValueList in the UIHint’s ControlParameters as a key value pair.

/// <summary>
/// Populates a list control with all the values from a parent table.
/// </summary>
/// <param name="listControl">The list control to populate.</param>
protected new void PopulateListControl(ListControl listControl)
{
    var uiHint = Column.GetAttribute<UIHintAttribute>();
    if (uiHint == null || uiHint.ControlParameters.Count == 0 || 
        !uiHint.ControlParameters.Keys.Contains("ValueList"))
        throw new InvalidOperationException(String.Format(
            "ValuesList for FieldTemplate {0} field is missing from UIHint",
            Column.Name));

    var valuesList = ValuesListAttribute(
        uiHint.ControlParameters["ValueList"].ToString());
    if (valuesList.Count() == 0)
        throw new InvalidOperationException(String.Format(
            "ValuesList for FieldTemplate {0} field, is empty",
            Column.Name));

    listControl.Items.AddRange(valuesList);
}

Listing 2 – PopulateListControl

In Listing 2 you can see the extraction of the ValuesList from the UIHint’s ControlParameters collection.

So Listings 1 & 2 will get you the same as the previous article but without the new attribute.

Take 2

In take two of this control binh said “But would you change a little to handle to have combobox with value and display value. The Value will be save to database and The Display value will be showed to user.” so I thought I would add this version here.

My personal view is this should be done either via an FK relationship or a Enum value. (Both my Your First FieldTemplate and Dynamic Data Preview 4 have an Enum FieldTemplate) but here goes.

In the Edit FieldTemplate this is all you need to do is modify the ValuesList method.

public ListItem[] GetValuesList(String values)
{
    var items = values.Split(new char[] { ',', ';' });
    var listItems = (from item in items
                     select new ListItem()
                     {
                         Text = item.Split(new char[] { '|' })[1],
                         Value = item.Split(new char[] { '|' })[0]
                     }).ToArray();
    return listItems;
}
Listing 3 – updated ValuesListAttribute
[MetadataType(typeof(Value.Metadata))]
partial class Value
{
    internal class Metadata
    {
        public object Id { get; set; }
        [UIHint("ValuesList", null, "ValueList", "1|Y,2|N,3|N/A")]
        public object TestR { get; set; }
        [UIHint("ValuesList", null, "ValueList", "1|Y,2|N,3|Other")]
        public object Test { get; set; }
    }
}

Listing 4 – sample metadata

Here you can see that the values and text are seperated by the pipe symbol ‘|’. However having done this you would now need to create a ValuesList (ReadOnly) FieldTemplate to get the ValuesList and the match the value in the field and then display the correct value, which in my opinion would be quite messy, so here I will stick to using Enums.

Download

Wednesday, 8 July 2009

Dynamic Data Custom Field Template – Values List

Here I have created a simple FieldTemplate for a recent project to allow you to give the user a predefined set of text values to choose from without a FK field relationship. An example of this could be a field with optional values of ‘Y’, ‘N’, ‘N/A’ or ‘Y’, ‘N’, ‘Other’ etc.

Requirements

  • Custom Attribute
  • Custom FieldTemplate

I have cover attributes many time on this blog so I’ll just post the code here:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ValuesListAttribute : Attribute
{
    public ValuesListAttribute() { }

    /// <summary>
    /// Construvtor take a list of values
    /// to show in the ListControl
    /// </summary>
    /// <param name="values">
    /// A ',' or ';' seperated list of values in the order
    /// that they should appear in the list control.
    /// </param>
    public ValuesListAttribute(String values)
    {
        var items = values.Split(new char[] { ',', ';' });
        Values = (from item in items
                  select new ListItem()
                  {
                      Text = item,
                      Value = item
                  }).ToArray();
    }

    public ListItem[] Values { get; set; }
}

Listing 1 – ValuesListAttribute

[MetadataType(typeof(Value.Metadata))]
partial class Value
{
    internal class Metadata
    {
        public object Id { get; set; }
        [UIHint("ValuesList")]
        [ValuesList("Y,N,N/A")]
        public object TestR { get; set; }
        [UIHint("ValuesList")]
        [ValuesList("Y,N,Other")]
        public object Test { get; set; }
    }
}

Listing 2 – sample metadata

So now to the FieldTemplate we don’t need to have two versions ValuesList and ValuesList_Edit as the data type we will be using this on is always text so the ValuesList version will automatically use the standard Text FieldTemplate.

<%@ Control 
    Language="C#" 
    CodeBehind="ValuesList_Edit.ascx.cs" 
    Inherits="DD_ValuesListFieldTemplate.ValuesList_EditField" %>

<asp:DropDownList 
    ID="DropDownList1" 
    runat="server" 
    CssClass="droplist">
</asp:DropDownList>

<asp:RequiredFieldValidator 
    runat="server" 
    ID="RequiredFieldValidator1" 
    CssClass="droplist" 
    ControlToValidate="DropDownList1" 
    Display="Dynamic" 
    Enabled="false" />

Listing 3 – ValuesList_Edit.ascx

public partial class ValuesList_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        SetUpValidator(RequiredFieldValidator1);

        if (DropDownList1.Items.Count == 0)
        {
            // add [Not Set] in insert mode as the field would
            // otherwise just take on the first value in the list
            // if the user clicks save without changing it.
            if (!Column.IsRequired || Mode == DataBoundControlMode.Insert)
            {
                DropDownList1.Items.Add(new ListItem("[Not Set]", ""));
            }

            // fill the dropdown list with the 
            // values in the ValuesList attribute
            PopulateListControl(DropDownList1);
        }
    }

    /// <summary>
    /// Populates a list control with all the values from a parent table.
    /// </summary>
    /// <param name="listControl">The list control to populate.</param>
    protected new void PopulateListControl(ListControl listControl)
    {
        var uiHint = Column.GetAttribute<UIHintAttribute>();
        if (uiHint == null || uiHint.ControlParameters.Count == 0 || !uiHint.ControlParameters.Keys.Contains("ValueList"))
            throw new InvalidOperationException(String.Format(
                "ValuesList for FieldTemplate {0} field is missing from UIHint",
                Column.Name));

        var valuesList = ValuesListAttribute(uiHint.ControlParameters["ValueList"].ToString());
        if (valuesList.Count() == 0)
            throw new InvalidOperationException(String.Format(
                "ValuesList for FieldTemplate {0} field, is empty",
                Column.Name));

        listControl.Items.AddRange(valuesList);
    }

    public ListItem[] ValuesListAttribute(String values)
    {
        var items = values.Split(new char[] { ',', ';' });
        var listItems = (from item in items
                         select new ListItem()
                         {
                             Text = item,
                             Value = item
                         }).ToArray();
        return listItems;
    }

    // added page init to hookup the event handler
    protected override void OnDataBinding(EventArgs e)
    {
        if (Mode == DataBoundControlMode.Edit)
        {
            ListItem item = DropDownList1.Items.FindByValue(FieldValueString);
            if (item != null)
                DropDownList1.SelectedValue = FieldValueString;
        }

        if (Mode == DataBoundControlMode.Insert)
            DropDownList1.SelectedIndex = 0;

        base.OnDataBinding(e);
    }

    /// <summary>
    /// Provides dictionary access to all data in the current row.
    /// </summary>
    /// <param name="dictionary">The dictionary that contains all the new values.</param>
    protected override void ExtractValues(IOrderedDictionary dictionary)
    {
        // If it's an empty string, change it to null
        string val = DropDownList1.SelectedValue;
        if (val == String.Empty)
            val = null;

        dictionary[Column.Name] = ConvertEditedValue(val);
    }

    /// <summary>
    /// Gets the data control that handles the data field in a field template.
    /// </summary>
    /// <value></value>
    /// <returns>
    /// A data control that handles the data field in a field template.
    /// </returns>
    public override Control DataControl
    {
        get
        {
            return DropDownList1;
        }
    }
}

Listing 4 – ListValues_Edit.ascx.cs FieldTemplate

The FieldTemplate has a RequiredFieldValidator on it in case the field is required but as the user will be choosing from a list non of the other valuators make sense. Also note in the extract values method the value is replaced with null if an empty string is selected (the default in insert so no value will be added if the user does not explicitly select one.

In PopulateListControl we have replaced the base class FieldTemplateUserControl’s PopulateListControl with our own that will use the values passed into via the ValuesListAttribute (which is required for the FieldTemplate to function).

So there you have it a simple custom FieldTemplate for those situations where the database either uses a field with the values ‘Y’ and ‘N’ instead of a bit field or where you just want the user to choose from a simple list of possible cases.

Download