Archives

Archives / 2005 / April
  • I think I got the first and original IBM ThinkPad

    When I got my first job at IBM back in -88 we got small brown notepads with the word 'THINK' printed on the cover. We're talking good old pen and paper stuff here. I would guess that was the original IBM ThinkPad :) I no longer work for IBM, but when I was cleaning out a few old boxes back home I found that "think pad" again.

    I took that old notepad with me to work today and showed it to some of my younger work mates, but they just looked strangely at me. I wonder why...

    I must try to upload an image of it I guess.

    Lol, according to what's printed inside the cover, I can "order refills from the nearest IBM office or write to IBM Corporation, Armonk, New York..." Maybe I should try that, I'm running out of sheets :p

  • Sending events from user controls to the parent containers

    Right, this is how I prefer to do things, instead of the other solution I wrote about earlier. The scenario is as follows (again):

    Imagine having a web form, which has a label control on it and this web form also loads a user control during run-time. The user control has a single button on it and when pressed, the button should set the text value of the label to the current date and time.

    This sample lets the user control raise an event, which the parent page catches. The event contains information about what text the label should be set to.

    First you define the event argument class so you have a way to send data to the “listener”. This sample is really simple, and contains just a single text property, which will contain a string:

     

    public class MyEventArgs : EventArgs

    {

               private readonly string text;

     

               public MyEventArgs(string text)

               {

                          this.text = text;

               }

     

               public string Text

               {

                          get { return text; }

               }

    }

     

    Then you go into your user control class and set up the event handler and code to trigger/raise the event with the correct argument values. One could argue if it's really necessary to have the OnEvent() method, but I prefer that, it feels cleaner. I also define the delegate for the event handler in the same class file, you may want to have this in some other place:

     

    public delegate void MyEventHandler(object sender, MyEventArgs e);

     

    public class WebUserControl1 : System.Web.UI.UserControl

    {

               protected System.Web.UI.WebControls.Button Button1;

               public event MyEventHandler MyEvent;

     

               private void Button1_Click(object sender, System.EventArgs e)

               {

                          OnEvent(new MyEventArgs("Time is " + DateTime.Now));

               }

     

               protected virtual void OnEvent(MyEventArgs e)

               {

                          if (MyEvent != null)

                                     MyEvent(this,e);

               }

    }

     

    Now, the rest of the code goes into the web form class, where you have to add the event listener after you’ve loaded the control. The Page_Load() event loads the control and sets up the event handler for MyEvent, called ctrl_MyEvent(). When the event fires, you just extract the text property from the event arguments and set the label text to that value.

     

    It’s a bit harder if you need to load different kinds of controls dynamically, but in that case I would define the events in a superclass that all user controls inherit from:

     

    public class WebForm1 : System.Web.UI.Page

    {

               protected System.Web.UI.WebControls.Panel Panel1;

               protected System.Web.UI.WebControls.Label Label1;

               protected WebUserControl1 ctrl = null;

     

               private void Page_Load(object sender, System.EventArgs e)

               {

                          ctrl = (WebUserControl1)LoadControl("WebUserControl1.ascx");

                          Panel1.Controls.Add(ctrl);

                          ctrl.MyEvent +=new MyEventHandler(ctrl_MyEvent);

               }

     

               private void ctrl_MyEvent(object sender, MyEventArgs e)

               {

                          Label1.Text = e.Text;

               }

    }

     

  • How ugly is this solution?

    I guess this can be called an anti-pattern, but it sort of works if you have a really small solution and no other coders than yourself :)

     Imagine having a web form, which has a label control on it and this web form also loads a user control during run-time. The user control has a single button on it and when pressed, the button should set the text value of the label to the current date and time.

    Now, there are some good ways and some bad ways to send data from a child control to a parent control, and I usually use events for this. Another way of doing this would be to access a property in the parent directly from the child control, but personally I think this is a really ugly way of doing things. How ugly do you think this is?

    In the web form, add a public property to be able to set the label text:

     

    protected System.Web.UI.WebControls.Panel Panel1;

    protected System.Web.UI.WebControls.Label Label1;

     

    private string mylabel = null;

     

    public string Mylabel

    {

               get { return mylabel; }

               set

               {

                   mylabel = value;

                   this.Label1.Text = mylabel;

               }

    }

     

    In the user control, the Page property of the control (which always points at the parent page, not the parent control) into the correct WebForm class, then set the public label property we define above directly.

     

    private void Button1_Click(object sender, System.EventArgs e)

    {

               if(this.Page is WebForm1)

               {

                          WebForm1 form = (WebForm1)this.Page;

                          form.Mylabel = "Time is " + DateTime.Now;

               }

    }

     

    This code seems to work pretty well, but I bet some of you get a nasty feeling in your gut when seeing code like this, and I agree completely. First of all, in an event driven enviroment, a control should never mess with properties in its parent/container. Secondly, the control assumes that the parent is always of a certain type (WebForm1) with a public property called Mylabel. I'm sure there are other good reasons for not coding like this. Comment please :)

     

  • Set focus on a clicked control in ASP.NET (part 2)

    I got a message from some friends that the code sample I had in my previous post didn't work when the control was located within a repeater or a datalist/datagrid, so I sat down and changed the code somewhat. The problem with controls in a repeater is that the container control eats up the event so the OnBubbleEvent() never fires.

    Now, the trick is to do exactly the same thing, but in the OnItemCommand event fired by the repeater/datalist/datagrid instead.

    So, the ASP-Page could look something like this:

    <%@ Page language="c#" Codebehind="WebForm2.aspx.cs" AutoEventWireup="false" Inherits="ControlTest.WebForm2" %>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >

    <HTML>

               <HEAD>

                          <title>WebForm2</title>

                          <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">

                          <meta name="CODE_LANGUAGE" Content="C#">

                          <meta name="vs_defaultClientScript" content="JavaScript">

                          <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">

               </HEAD>

               <body MS_POSITIONING="FlowLayout">

                          <form id="Form1" method="post" runat="server">

                                     <P>

                                                <table>

                                                          <asp:Repeater id="Repeater1" runat="server" OnItemCommand="Repeater1_ItemCommand">

                                                                     <ItemTemplate>

                                                                                <tr>

                                                                                           <td>

                                                                                                      <ASP:Button ID="someID" CommandName="someCommand" CommandArgument='<%# DataBinder.Eval(Container.DataItem, "id") %>'

                                                                                                      Text='<%# DataBinder.Eval(Container.DataItem, "id") %>' runat="server" />

                                                                                           </td>

                                                                                </tr>

                                                                     </ItemTemplate>

                                                          </asp:Repeater>

                                                </table>

                                     </P>

                          </form>

               </body>

    </HTML>

     

    And the code behind for this simple sample:

    using System;
    using System.Collections;
    using System.Diagnostics;
    using System.Text;
    using System.Web.UI.WebControls;

    namespace ControlTest

    {

               public class somedata

               {

                          public somedata(string id, string value)

                          {

                                     this.id = id;

                                     this.value = value;

                          }

     

                          private string id;

                          private string value;

     

                          public string Id

                          {

                                     get { return id; }

                                     set { id = value; }

                          }

     

                          public string Value

                          {

                                     get { return value; }

                                     set { this.value = value; }

                          }

               }

               /// <summary>

               /// Summary description for WebForm2.

               /// </summary>

               public class WebForm2 : System.Web.UI.Page

               {

                          protected System.Web.UI.WebControls.Repeater Repeater1;

                          private ArrayList ht = new ArrayList();

     

                          private void Page_Load(object sender, System.EventArgs e)

                          {

                                     FillArrayList();

     

                                     if(!IsPostBack)

                                                BindData();

                          }

     

                          private void BindData()

                          {

                                     Repeater1.DataSource = this.ht;

                                     Repeater1.DataBind();

                          }

     

                          private void FillArrayList()

                          {

                                     for(int i = 0; i<10; i++)

                                                this.ht.Add(new somedata("id"+i,"value"+i));

                          }

     

     

                          protected void Repeater1_ItemCommand(object sender, RepeaterCommandEventArgs e)

                          {

                                     if(e.CommandSource is WebControl)

                                                SetControlFocus(e.CommandSource);

                          }

     

                          private void SetControlFocus(object sender)

                          {

                                     WebControl webControl = (WebControl)sender;

                                     Debug.WriteLine("Clicked " + webControl.ClientID);

                                     StringBuilder sb = GetFocusScriptBlock(webControl);

                                     RegisterClientScriptBlock("FocusScript", sb.ToString());

                          }

     

                          private static StringBuilder GetFocusScriptBlock(WebControl webControl)

                          {

                                     StringBuilder sb = new StringBuilder(1000);

                                     sb.Append("<script language = \"javascript\">");

                                     sb.Append("function ControlFocus() {");

                                     sb.Append("document.getElementById('" + webControl.ClientID + "').focus();");

                                     sb.Append("}");

                                     sb.Append(String.Concat(Environment.NewLine, Environment.NewLine, "window.onload = ControlFocus;"));

                                     sb.Append("</script>");

                                     return sb;

                          }

     

                          #region Web Form Designer generated code

                          override protected void OnInit(EventArgs e)

                          {

                                     //

                                     // CODEGEN: This call is required by the ASP.NET Web Form Designer.

                                     //

                                     InitializeComponent();

                                     base.OnInit(e);

                          }

                         

                          /// <summary>

                          /// Required method for Designer support - do not modify

                          /// the contents of this method with the code editor.

                          /// </summary>

                          private void InitializeComponent()

                          {   

                                     this.Load += new System.EventHandler(this.Page_Load);

     

                          }

                          #endregion

               }

    }

     

     

     

  • [Off Topic] Finally got my black belt

    I passed my black belt graduation in aikido (aikikai) today! Yay! I've been so nervous the last month you cannot imagine... been dreaming about attacks and throws and swords... Anyway, the graduation went really well - I'm sitting here with a HUGE SMILE on my face!