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>
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;
}
}
[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);
}
}
[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 Ren<code>
der 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.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.