Click here to Skip to main content
15,904,655 members
Articles / Web Development / ASP.NET
Article

AlphaNavigator: Hotmail style strip of letters representing entries starting with a certain letter

Rate me:
Please Sign up or sign in to vote.
3.80/5 (5 votes)
9 May 20051 min read 57K   651   26   9
This is a fully contained control that when used will give the designer a strip of letters representing entries starting with a certain letter. The characters that are found become hyperlinks. This control has a custom event handler for discovering which letter was clicked.

Image 1

Introduction

I was asked to create a hotmail style (contacts section) alpha navigation strip. Seeing an opportunity for reuse I created a control instead of just a straight code. This control is in beta mode, as I’ll be adding more to its robustness, but I want to say that the current state of the control is completely stable and usable. This control takes a couple of variables, specifically the DB table and the column from which it will be compose its list of letters with links.

Using the code

The following is an example of the code needed to use the control. First reference the AlphaNavigator.dll, then add it to your Toolbox. Next drag a new instance onto the page and in the properties/events panel set the name for the LetterClick event.

C#
protected AlphaNavigator.AlphaNavigator AlphaNavigator1;
private void Page_Load(object sender, System.EventArgs e){
    this.AlphaNavigator1.LetterClick += 
            new System.EventHandler(this.AlphaNavigator1_LetterClick);
    string sSql = "SELECT DISTINCT SUBSTRING(Column,1,1) " +
        "FROM Table ORDER BY SUBSTRING(Column,1,1) ";
    OdbcConnection sqlConn = null;
    sqlConn = new OdbcConnection("Driver={MySQL ODBC 3.51 Driver};" + 
        "dsn=DNSNAME;database=DBNAME;uid=USER;password=PASS;");
    sqlConn.Open();
    OdbcCommand sqlCmd;
    OdbcDataReader myReader;
    sqlCmd = new OdbcCommand(sSql,sqlConn);
    sqlCmd.CommandTimeout = 10;
    myReader  = sqlCmd.ExecuteReader();
    AlphaNavigator1.DataSource = myReader;
}
private void AlphaNavigator1_LetterClick(object sender,System.EventArgs e){
    Response.Write("Selected Letter:" + AlphaNavigator1.SelectedLetter);
}

AlphaNavigator control

This is the main code of the control. The Render method is overridden. The code simply queries the DB and loops through the rows while adding to an array the items that exist. Once this is complete the GUI is drawn:

C#
protected override void Render(System.Web.UI.HtmlTextWriter writer) {
    StringDictionary abc = AlphaLinks();
    string alphabet = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    if (this.SelectedLetter != ""){
        System.Web.UI.HtmlControls.HtmlAnchor hypLink = 
                     new System.Web.UI.HtmlControls.HtmlAnchor();
        hypLink.HRef = 
                     "javascript:" + this.Page.GetPostBackEventReference(this, 
                                                                  "LetterClick");
        hypLink.Name = this.UniqueID;
        hypLink.InnerHtml = "All";
        Controls.Add(hypLink);
    } else {
        Label lblAll = new Label();
        lblAll.Text = "All";
        Controls.Add(lblAll);
    }
    foreach (char C in alphabet){
      Label lblSpace = new Label();
      lblSpace.Text = " ";
      Controls.Add(lblSpace);

      string sCurrentChar = C.ToString();
      if ((abc[sCurrentChar] == "on") && (this.SelectedLetter != sCurrentChar)){
          System.Web.UI.HtmlControls.HtmlAnchor hypLink = 
                                   new System.Web.UI.HtmlControls.HtmlAnchor();
          hypLink.HRef ="javascript:" + this.Page.GetPostBackEventReference(this, 
                                                   "LetterClick" + sCurrentChar);
          hypLink.Name = this.UniqueID + "_" + sCurrentChar;
          hypLink.InnerHtml = "" + sCurrentChar + "";
          Controls.Add(hypLink);
      } else {
          Label lblLetter = new Label();
          lblLetter.Text = sCurrentChar;
          Controls.Add(lblLetter);
      }
    }
    base.Render(writer);
}
private StringDictionary AlphaLinks(){
    StringDictionary abc = new StringDictionary();
    if (_dataSource != null){
        if (_dataSource is DataView) {
            DataView dv = (DataView)_dataSource;
            foreach(DataRow dr in dv.Table.Rows){
                string letter = dr[0].ToString().ToUpper();
                if (Char.IsDigit(letter[0]))
                    abc["#"] = "on";
                else
                    abc[letter] = "on";
            }
        }else if (_dataSource is IDataReader) {
            IDataReader reader = (IDataReader)_dataSource;
            while (reader.Read()) {
                string letter = reader[0].ToString().ToUpper();
                if (Char.IsDigit(letter[0]))
                    abc["#"] = "on";
                else
                    abc[letter] = "on";
            }
        }
    }
    abc["All"] = "on";
    return abc;
}

Future plans

More robustness.

History

  • Version 1.0, May 2005.
  • Version 1.1, May 2005 - Rewritten, now uses DataSource to build self.

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


Written By
Web Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionNew Build?? Pin
Frank Walsh4-Oct-05 9:09
Frank Walsh4-Oct-05 9:09 
GeneralEeek! Pin
James Curran5-May-05 6:28
James Curran5-May-05 6:28 
I was just about to start on a similar control when I saw this. Hmm... I think I'll do my own...

You have way too many "magic numbers". Admittedly, one might argue that it's OK to hard code a "26" since the number of letters isn't going to change (unless we move this to a different language), but "28" for "the number of letters plus a couple other things" is really bad.

However, what's extremely bad is catch an exception to handle normal processing. Exceptions are incredibly slow --- which is OK, since they are only to be used in exceptional situations.

Let's try rewriting a bit. Replace:
while (myReader.Read()){<br />
	for(int x=0; x<28; x++){<br />
		try{<br />
			if (myReader[0].ToString().ToUpper() == abc[x,0])<br />
				abc[x,1] = "on";<br />
		}catch(Exception es){}<br />
		if ((myReader[0].ToString() == "0") || (myReader[0].ToString() == "1")<br />
		 || (myReader[0].ToString() == "2") || (myReader[0].ToString() == "3")<br />
		 || (myReader[0].ToString() == "4") || (myReader[0].ToString() == "5")<br />
		 || (myReader[0].ToString() == "6") || (myReader[0].ToString() == "7")<br />
		 || (myReader[0].ToString() == "8") || (myReader[0].ToString() == "9"))<br />
			iNumCount++;<br />
	}<br />
}<br />
if (iNumCount > 0)<br />
	abc[1,1] = "on";<br />
abc[0,1] = "on";

with
<br />
StringDictionary abc = new StringDictionary()<br />
<br />
while (myReader.Read())<br />
{<br />
    string letter = myReader[0].ToString().ToUpper();<br />
    if (Char.IsDIgit(letter[0]))<br />
         abc["#"] = "on";<br />
    else<br />
         abc[letter] = "on";<br />
}<br />
abc["All"] = "on";<br />

(note the also replaces the entire prepopulating of the abc array)
Then replace
<br />
for(int x=2; x<28; x++){<br />
      if ((ABCs[x,1] == "on") && (this.SelectedLetter != ABCs[x,0])) {<br />

with
<br />
string alphabet = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";<br />
foreach(char C in alphabet) {<br />
	if (abc[C.ToString()] == "on" && (this.SelectedLetter != C) )<br />

(note that this allows different langauge to be used, merely by changing one line, which could be made a property)

However, the biggest question is Why are you dealing with the database at all? No similar control in .Net handles the db directly. Every one uses a DataSource property.




Truth,
James
GeneralRe: Eeek! Pin
micahbowerbank5-May-05 7:24
micahbowerbank5-May-05 7:24 
GeneralRe: Eeek! Pin
James Curran6-May-05 5:49
James Curran6-May-05 5:49 
GeneralRe: Eeek! Pin
Anonymous7-May-05 3:39
Anonymous7-May-05 3:39 
GeneralRe: Eeek! Pin
micahbowerbank9-May-05 8:56
micahbowerbank9-May-05 8:56 
GeneralRe: Eeek! Pin
James Curran10-May-05 5:24
James Curran10-May-05 5:24 
GeneralRe: Eeek! Pin
Wcohen6-Sep-05 17:22
Wcohen6-Sep-05 17:22 
GeneralRe: Eeek! Pin
lolocmwa25-May-05 21:40
lolocmwa25-May-05 21:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.