Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Lookup Data Web Control

0.00/5 (No votes)
28 Jul 2008 1  
This is based on key and value pairs that you can select appropriate key and value pair from data source

Introduction

This is a composite control and easy to use. I have seen many articles just to improve this control. Many articles suggest Popup window. But I found that many users don't like popup.
I use JavaScript to deal with it so when you select a row from data source it prevents round trip.

Using the code

Just drag and drop the control on the page then assign the control properties and enjoy…!

Page source code:

 <body style="font-family: Verdana; font-size: 8pt;">
 <form id="form1" runat="server">
 <cc1:LookUpData ID="LookUpData1" runat="server" DataSourceID="SqlDataSource1" 
     KeyControlWidth="40" ValueControlWidth="80">
  <Columns>
   <cc1:Column ColumnType="Key" DataField="Id" HeaderText="Id">
   </cc1:Column>
   <cc1:Column ColumnType="Value" DataField="Name" HeaderText="Name">
    <ItemStyle Width="150px" />
   </cc1:Column>
   <cc1:Column DataField="Age" HeaderText="Age">
    <ItemStyle Width="50px" />
   </cc1:Column>
  </Columns>
 </cc1:LookUpData>
 <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString=
     "<%$ ConnectionStrings:ConnectionString %>" SelectCommand=
     "SELECT * FROM [Users]"></asp:SqlDataSource>
 </form>
</body>

2.JPG

Control code behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Web.UI;
using System.ComponentModel;
using System.Web.UI.WebControls;
using System.Data;
using System.Collections;
using System.Drawing.Design;
namespace WebControls.LookupData
{
 [ParseChildren(true),
 DefaultProperty("Key"),
 ToolboxData("<{0}:LookUpData runat="server"></{0}:LookUpData>"),
 ToolboxBitmap(typeof(TextBox))]
 public class LookUpData : DataBoundControl, ICallbackEventHandler
 {
  #region Constructors
  public LookUpData()
  {
  }
  #endregion
  #region Public Properties
  [Category("Columns"), DefaultValue((string)null),
  Editor(typeof(ColumnCollectionEditor), typeof(UITypeEditor)),
  DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
  PersistenceMode(PersistenceMode.InnerProperty)]
  public virtual DataControlFieldCollection Columns
  {
   get
   {
    if (this.columns == null)
    {
     this.columns = new DataControlFieldCollection();
     this.columns.FieldsChanged += new EventHandler(this.OnFieldsChanged);
     if (base.IsTrackingViewState)
     {
      ((IStateManager)this.columns).TrackViewState();
     }
    }
    return this.columns;
   }
  }
  private void OnFieldsChanged(object sender, EventArgs e)
  {
   if (base.Initialized)
   {
    base.RequiresDataBinding = true;
   }
  }
  /// <summary>
  /// Get key from lookup data control.
  /// </summary>
  [ReadOnly(true), Browsable(false)]
  public string Key
  {
   get
   {
    if (keyControl != null)
    {
     return keyControl.Text;
    }
    return null;
   }
  }
  [DefaultValue(40), Category("Appearance")]
  public short KeyControlWidth
  {
   get
   {
    if (this.ViewState["KeyControlWidth"] == null)
     return 40;
    return (short)this.ViewState["KeyControlWidth"];
   }
   set
   {
    this.ViewState["KeyControlWidth"] = value;
    if (keyControl != null)
     keyControl.Width = Unit.Pixel(value);
   }
  }
  /// <summary>
  /// Get value from lookup data control.
  /// </summary>
  [ReadOnly(true), Browsable(false)]
  public string Value
  {
   get
   {
    if (valueControl != null)
    {
     return valueControl.Text;
    }
    return null;
   }
  }
  [DefaultValue(80), Category("Appearance")]
  public short ValueControlWidth
  {
   get
   {
    if (this.ViewState["ValueControlWidth"] == null)
     return 80;
    return (short)this.ViewState["ValueControlWidth"];
   }
   set
   {
    this.ViewState["ValueControlWidth"] = value;
    if (valueControl != null)
     valueControl.Width = Unit.Pixel(value);
   }
  }
  #endregion
  #region Private Methods
  private void searchControl_Click(object sender, EventArgs e)
  {
   DataSourceView dataSource = this.GetData();
   dataSource.Select(new DataSourceSelectArguments(),
    DataSourceCallback);
  }
  public override object DataSource
  {
   get
   {
    return ViewState["DataSource"];
   }
   set
   {
    ViewState["DataSource"] = value;
   }
  }
  private void DataSourceCallback(IEnumerable data)
  {
   string keyHeaderText = GetKeyHeaderText();
   string valueHeaderText = GetValueHeaderText();
   if (data != null & keyHeaderText != null && valueHeaderText != null)
   {
    bool hasResult = false;
    IEnumerator reader = data.GetEnumerator();
    while (reader.MoveNext())
    {
     DataRowView lastReading = reader.Current as DataRowView;
     if (lastReading != null && lastReading[keyHeaderText].ToString() == keyControl.Text)
     {
      valueControl.Text = lastReading[valueHeaderText].ToString();
      hasResult = true;
      break;
     }
    }
    if (!hasResult)
    {
     ClearControls();
     this.hiddenFieldControl.Value = "true";
     this.gridViewControl.DataSource = data;
     this.gridViewControl.DataBind();
    }
    else
    {
     this.hiddenFieldControl.Value = "false";
     this.gridViewControl.DataSource = null;
    }
    keyControl.Focus();
   }
  }
  private void gridViewControl_RowDataBound(object sender, GridViewRowEventArgs e)
  {
   ClientScriptManager scriptManager = this.Page.ClientScript;
   string callbackScript = scriptManager.GetCallbackEventReference(this,
    e.Row.RowIndex.ToString(),
    "ReceiveServerData", "function ReceiveServerData(arg, context){ " +
    "var argArray = arg.split('0$0'); if(argArray.length == 2){" +
    "document.getElementById('" +
        this.keyControl.ClientID + "').value = argArray[0]; " +
    "document.getElementById('" +
        this.valueControl.ClientID + "').value = argArray[1]; } " +
    "document.getElementById('div" +
        this.ClientID + "').style.display = 'none'; } ", true);
   if (e.Row.RowType == DataControlRowType.DataRow)
   {
    e.Row.Attributes.Add("onmouseover", "this.style.color = '" +
        ColorTranslator.ToHtml(Color.Blue) + "'");
    e.Row.Attributes.Add("onmouseout", "this.style.color = '" +
       ColorTranslator.ToHtml(Color.Black) + "'");
    e.Row.Attributes["onclick"] = callbackScript;
    e.Row.Style.Add("cursor", "hand");
   }
  }
  private string GetKeyHeaderText()
  {
   if (columns != null)
   {
    foreach (Column column in Columns)
    {
     if (column.ColumnType == ColumnType.Key)
     {
      return column.HeaderText;
     }
    }
   }
   return null;
  }
  private string GetValueHeaderText()
  {
   if (columns != null)
   {
    foreach (Column column in Columns)
    {
     if (column.ColumnType == ColumnType.Value)
     {
      return column.HeaderText;
     }
    }
   }
   return null;
  }
  private void ClearControls()
  {
   keyControl.Text = string.Empty;
   valueControl.Text = string.Empty;
  }
  #endregion
  #region Override Properties
  public override ControlCollection Controls
  {
   get
   {
    this.EnsureChildControls();
    return base.Controls;
   }
  }
  #endregion
  #region Override Methods
  protected override void CreateChildControls()
  {
   this.keyControl = new TextBox();
   this.keyControl.Width = Unit.Pixel(40);
   this.Controls.Add(this.keyControl);
   this.valueControl = new TextBox();
   this.valueControl.Width = Unit.Pixel(80);
   this.Controls.Add(this.valueControl);
   this.searchControl = new Button();
   this.searchControl.Click += new EventHandler(searchControl_Click);
   this.searchControl.Text = "...";
   this.searchControl.Width = Unit.Pixel(23);
   this.searchControl.Height = Unit.Pixel(23);
   this.Controls.Add(this.searchControl);
   this.gridViewControl = new GridView();
   this.gridViewControl.AutoGenerateColumns = false;
   if (columns != null)
   {
    foreach (Column column in Columns)
    {
     this.gridViewControl.Columns.Add(column);
    }
   }
   this.gridViewControl.AllowPaging = true;
   this.gridViewControl.PageIndexChanging +=
       new GridViewPageEventHandler(gridViewControl_PageIndexChanging);
   this.gridViewControl.RowDataBound +=
       new GridViewRowEventHandler(gridViewControl_RowDataBound);
   this.gridViewControl.CellPadding = 3;
   this.gridViewControl.CellSpacing = 0;
   this.gridViewControl.BorderWidth = 1;
   this.gridViewControl.BorderColor = Color.FromName("#000000");
   this.gridViewControl.BorderStyle = BorderStyle.Solid;
   this.gridViewControl.FooterStyle.BackColor = Color.FromName("#A4DFFC");
   this.gridViewControl.FooterStyle.ForeColor = Color.FromName("#000000");
   this.gridViewControl.RowStyle.BackColor = Color.FromName("#EEEEEE");
   this.gridViewControl.RowStyle.ForeColor = Color.FromName("#000000");
   this.gridViewControl.AlternatingRowStyle.BackColor = Color.FromName("#DDDDDD");
   this.gridViewControl.AlternatingRowStyle.ForeColor = Color.FromName("#000000");
   this.gridViewControl.HeaderStyle.Font.Bold = true;
   this.gridViewControl.HeaderStyle.BackColor = Color.FromName("#BBBBBB");
   this.gridViewControl.HeaderStyle.ForeColor = Color.FromName("#000000");
   this.gridViewControl.PagerStyle.BackColor = Color.FromName("#BBBBBB");
   this.gridViewControl.PagerStyle.ForeColor = Color.FromName("#000000");
   this.gridViewControl.HeaderStyle.Height = Unit.Pixel(20);
   this.Controls.Add(this.gridViewControl);
   this.hiddenFieldControl = new HiddenField();
   this.hiddenFieldControl.Value = "false";
   this.Controls.Add(this.hiddenFieldControl);
  }
  void gridViewControl_PageIndexChanging(object sender, GridViewPageEventArgs e)
  {
   this.gridViewControl.PageIndex = e.NewPageIndex;
   DataSourceView dataSource = this.GetData();
   dataSource.Select(new DataSourceSelectArguments(),
    DataSourceCallback);
  }
  protected override void RenderContents(HtmlTextWriter writer)
  {
   this.AddAttributesToRender(writer);
   writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0");
   writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0");
   writer.RenderBeginTag(HtmlTextWriterTag.Table);
   writer.RenderBeginTag(HtmlTextWriterTag.Tr);
   writer.RenderBeginTag(HtmlTextWriterTag.Td);
   this.keyControl.RenderControl(writer);
   this.valueControl.RenderControl(writer);
   this.searchControl.RenderControl(writer);
   writer.RenderEndTag();
   writer.RenderEndTag();
   if (this.hiddenFieldControl.Value == "true")
   {
    ClientScriptManager scriptManager = this.Page.ClientScript;
    string callbackScript = scriptManager.GetCallbackEventReference(this,
     "",
     "ReceiveServerData", "function ReceiveServerData(arg, context){ " +
     "var argArray = arg.split('0$0'); if(argArray.length == 2){" +
     "document.getElementById('" +
         this.keyControl.ClientID + "').value = argArray[0]; " +
     "document.getElementById('" +
         this.valueControl.ClientID + "').value = argArray[1]; } " +
     "document.getElementById('div" +
         this.ClientID + "').style.display = 'none'; } ", true);
    writer.RenderBeginTag(HtmlTextWriterTag.Tr);
    writer.RenderBeginTag(HtmlTextWriterTag.Td);
    writer.RenderBeginTag(HtmlTextWriterTag.Div);
    writer.AddAttribute(HtmlTextWriterAttribute.Id, "div" + this.ClientID);
    StringBuilder styleBuilder = new StringBuilder();
    styleBuilder.Append("z-index: 100;");
    styleBuilder.Append("margin-top: 2px;");
    styleBuilder.Append("position: absolute;");
    styleBuilder.Append("background-color: #FFFFFF;");
    writer.AddAttribute("style", styleBuilder.ToString());
    writer.AddAttribute("onmouseleave", callbackScript);
    this.gridViewControl.RenderControl(writer);
    writer.RenderEndTag();
    writer.RenderEndTag();
    writer.RenderEndTag();
   }
   writer.RenderEndTag();
  }
  #endregion
  #region Private Fields
  private string eventArgument;
  private TextBox keyControl = null;
  private TextBox valueControl = null;
  private Button searchControl = null;
  private GridView gridViewControl = null;
  private DataControlFieldCollection columns;
  private HiddenField hiddenFieldControl = null;
  #endregion
  #region ICallbackEventHandler Members
  public string GetCallbackResult()
  {
   string result = null;
   if (!string.IsNullOrEmpty(eventArgument) && !string.IsNullOrEmpty(this.eventArgument))
   {
    result = gridViewControl.Rows[int.Parse(this.eventArgument)].Cells[0].Text +
     "0$0" + gridViewControl.Rows[int.Parse(this.eventArgument)].Cells[1].Text;
   }
   this.hiddenFieldControl.Value = "false";
   return result;
  }
  public void RaiseCallbackEvent(string eventArgument)
  {
   this.eventArgument = eventArgument;
  }
  #endregion
 }
}

Core of control

As this is a composite control, we need override Render method. In fact, the main core function of the control is CreateChildControls. So, whenever the control is initialized, it will call this method after Init and before PreRender events. I have created all my child controls here. The code is self explanatory.

Control without PostBack

I don't want my control to have round trip when user selects a row so I implemented ICallbackEventHandler.

Points of Interest

That sounds interesting...! So, let's start exploring the magic behind this control. It is a composite control. It's a combination of DataBoundControl, ICallbackEventHandler, CollectionEditor, BoundField and others. As it's a composite control, I have derived my class from DataBoundControl class.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here