Devlico.Us
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @devlicious

Christopher Bennage

Our WPF book is now available!

September 2006 - Posts

  • Data-Binding to Methods in ASP.NET

    I've run into a couple of situations where I need more than simple databinding in ASP.NET.  Sometimes I need some to bind a thing conditionally.

    Ok, so let's say you have a collection of addresses that you want to bind to a DataList. The markup might look something like this:

    <asp:DataList ID="DataList1" runat="server">

        <ItemTemplate>

            <asp:Panel ID="AddressPanel" runat="server" CssClass="address">

                <asp:Label ID="Address" runat="server" Text='<%# Eval("address") %>' /><br />

                <asp:Label ID="City" runat="server" Text='<%# Eval("city") %>' /><br />

                <asp:Label ID="PostalCode" runat="server" Text='<%# Eval("postalcode") %>' />

            </asp:Panel>

        </ItemTemplate>

    </asp:DataList>

    Now, let’s say that you would really like to highlight all addresses where the zip code starts with "902". Let's take the AddressPanel in the ItemTemplate and bind its CssClass property like this:

    <asp:Panel ID="AddressPanel" runat="server" CssClass='<%# Eval("postalcode") %>'> ...

    That gets us a little closer. It we wanted to brute force it we could create a css class for every possible zip code variation. (Yeah, okay.)

    Instead, let’s create a protected method on the containing page:

    protected string GetCssForPostalCode(object dataItem)

    {

        DataRowView row = dataItem as DataRowView;

     

        if (row["postalcode"].ToString().StartsWith("902")) return "highlight-address";

        return "normal-address";

    }

    We can use this method to decide what data should be bound.  So how do we connect this back to our ItemTemplate in the DataList? The first thing to understand is that Eval() is a shortcut function for calling DataBinder.Eval(). To perform the data-binding without Eval() looks like this: <%#DataBinder.Eval(Container.DataItem, "postalcode")%> I’m not sure what the proper nomenclature is for this, but the # enables the use of DataBinder as well as Container.

    So here’s the trick, instead of calling DataBinder.Eval() you can call your own method. In this case GetCssForPostalCode(). So the end result will look like this:

    <asp:DataList ID="DataList1" runat="server">

        <ItemTemplate>

            <asp:Panel ID="AddressPanel" runat="server" CssClass='<%#GetCssForPostalCode(Container.DataItem)%>'>

                <asp:Label ID="Address" runat="server" Text='<%# Eval("address") %>' /><br />

                <asp:Label ID="City" runat="server" Text='<%# Eval("city") %>' /><br />

                <asp:Label ID="PostalCode" runat="server" Text='<%# Eval("postalcode") %>' />

            </asp:Panel>

        </ItemTemplate>

    </asp:DataList>

     

    Also see Rob Eisenberg's series of posts on .NET 3.0 to learn how WPF addresses this problem (though not for the Web).

  • Reflecting Virtual Properties

    I experienced an interesting gotcha with reflection today. I had a base class with a virtual property:

    class BaseClass
        {
            private string _someProperty = "Hello!";

            public virtual string SomeProperty
            {
                get { return _someProperty; }
                set { _someProperty = value; }
            }
        }

    In a subclass I overrode the property, but only implemented the setter:

    class SubClass : BaseClass
        {
            public override string SomeProperty
            {
                set { base.SomeProperty = value + " and stuff"; }
            }
        }
     

    You can get/set the property of an instance of SubClass normally.  However, if you try to get the property's value with reflection, it's not quite straightforward.  Something like this, won't work:

        SubClass sub = new SubClass();
        Type t = sub.GetType();
        PropertyInfo prop = t.GetProperty("SomeProperty");
        string s = prop.GetValue(sub, null).ToString();

    The call to GetValue() fails because the getter doesn't exist on the SubClass.  It sounds obvious in retrospect, but it sure threw me for a loop today.  See the attachment for a working example.

  • The Castle Project/MonoRail

    If you do any Web development whatsoever then you have most likely heard of Ruby on Rails. Ruby is a dynamic programming language and Rails is a framework for Web development. It's analogous to saying C# on ASP.NET. Well, the Rails framework is impressive to me in its own right. Even after just hearing some friends discuss it, my mind immediately began to try to apply the ideas to .NET. Luckily, I stumbled across the Castle Project. Castle is a rich, open source project that offers a great many things. One of those things is MonoRail, a port of Rails to the .NET framework.

    Rails and MonoRail are both built around the Model-View-Controller pattern. (As opposed to the Page Controller pattern that ASP.NET claims to built around.)

    My initial forays into MonoRail have been promising and I really hope the project's community continues to grow.  

    I will warn you, if you begin to play with MonoRail you will begin to hate the Page lifecycle in ASP.NET.

  • My History With 3rd Party Controls

    The following is a series of posts I made on my old blog regarding control suites. I think it should be an interesting read for anyone evaluating a 3rd party control suite.  Be sure to read both posts.

    March 31st, 2006
    The Honeymoon Is Over: My Farewell to 3rd Party Controls

    Over the last couple of years I have used web controls suite from Infragistics and Telerik. I was a very enthusiastic user, and I think that I could have been a product evangelistic for Telerik about 9 months ago. Telerik seems to have an especially agressive development cycle and they deliver new products every couple of months.

    So what happened?
    Well, the whiz-bang wore off and I began to realize the following deficits:

    • Inadequate Documentation. 3rd party never seem to be documented well. Sure, there's lot of documentation for both Infragistrics and Telerik, but that doesn't mean it's good documentation. I can't come down on them too hard. My wife is a tech writer and I understand the difficulties of writing good documentation. However, I can never seem to find what I need. Which leads to the next problem...
    • Inconsistent API's. I personally try to follow Microsoft's guidlines and examples. I want a .NET developer reviewing my code to feel "at home", like my code is a natural part of the framework itself. Now, I understand that 3rd parties may have excellent reasons for establishing their own feel. However, both API's are inconsistent even within themselves. Don't expect methods that do the same thing on different controls to have the same name. I feel like I have to become an expert with each and every control.
    • Bulk. Too many features. Does that sound backwards? I spend a lot of my time figuring out how to minimize what the control does. Take Telerik's rich text editor; it rivals Word. Additionally, the acutal HTML rendered for many of these controls is expansive. I've ended up writing a number of simple controls,with simple output just because using a 3rd party control seemed excessive.

    I will say a positive thing about 3rd party controls. If you have a relativity simple application to development, and you want very rich client functionality, these suites will benefit you. However, if you are writing commericial applications for a wide audience, and if performance is an issue, then I would recommend being a bit more wary.

    April 9th, 2006
    Telerik Responds

    I was surprised and somewhat humbled last week to receive an email from the CEO of Telerik, Vassil Terziev. He had come across my blog post where I criticize 3rd party control suites and wanted to respond.
    To summarize, he was very cordial and acknowledged each of my complaints as valid. He explained that Telerik has recently changed a few things about their development cycle in order to improve upon the weaknesses I listed. He also pointed out a few things Telerik has already accomplished to those ends (such as a 70% reduction in output from their tabstrip product).
    His email was personal, friendly, and transparent about his products. I was very impressed and the fact that Telerik has that kind of leadership encourages me to give their products another chance.
    Luckily, my employer's subscription to their control suite still has many months left. Expect me to post my reflections upon the updated Telerik products when they arrive.

    September 20th, 2006 

    I never did get around to really evaluating the improvements that Vassil listed.  We did continue to use there controls and I have continued to be impressed  with their attention to customer input.  I have had some performance issues with the rich text editor, though mostly in an environment with multiple instances of the editor on a single page. 

  • Custom Fields for GridView Tips

    This is a followup to my post on creating a DropDownField for the GridView control. Just a couple of tips for anyone else who might be developing custom columns for the GridView.  If you don't care about customizing the GridView, don't bother reading this.

    Tip #1 - Respect the Page Lifecycle

    The distinction between the two methods I mentioned previously,  InitializeDataCell and OnDataBindField, was vague to me at first.  It didn't seem to matter which method I used for creating controls to insert into the GridView. Now, I'm a little wiser.  You want to instantiate your controls in InitializeDataCell so that their change events will fire, if you want and instantiate them in OnDataBindField it will be to late.  Additionally, you will not be able to access the bound data until the DataBinding event, thus the need for the second method.

    Tip #2 - Beware of Adding Members to DataControlFieldCell

    There is only one instance of field defined in a GridView regardless of the number of rows. When I first attempted to create a custom field, I inherited from DataControlFieldCell and added a private member of type TextBox called EditControl.  I set EditControl in InitializeDataCell to a new TextBox, and set the .Text property in OnDataBindField.  My first test only had one row of data in the GridView and everything seemed to work.  My second test had many rows of data, and it no longer worked.  I discovered that my EditControl field was being shared across every row, because there is only one instance of the each field.

    The solution was to  do something like this:

            protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
            {

                cell.DataBinding += OnDataBindField;

                if ((rowState & DataControlRowState.Edit) != DataControlRowState.Normal)
                {
                    cell.Controls.Add(new TextBox());
                }
            }
    and
    protected override void OnDataBindField(object sender, EventArgs e)
    {
    DataControlFieldCell cell = (DataControlFieldCell) sender;

    string myBoundData = GetValue(cell.NamingContainer).ToString();

    if ((rowState & DataControlRowState.Edit) != DataControlRowState.Normal)
    {
    (cell.Controls[0] as TextBox).Text = myBoundData;
    }
    else
    {
    cell.Text = myBoundData;
    }
    }

  • DropDownField for GridView

    One of the requirements on my current project involves the user defining what a grid of data should look like. We allow a user to create a "definition", which we persist in the database and then we construct a GridView at runtime based on the "definition". This mean that we don't know what fields (or even types of fields) the GridView has at design time. Additionally, we needed to support drop down lists in the GridView.

    I searched for a good while hoping to find out how to programmatically add a drop down list to a GridView. All of the examples I found used a TemplateField and were based on the assumption that you knew you wanted a drop down list at design time. So I decided to build my own custom drop down list field. Reflector allowed me to dissect the various fields that shipped with the framework (BoundField, CheckBoxField, etc.) All of these classes derive from DataControlField. I won't go into too much more detail for the moment, but the major members that I had to implement for DataControlField were:

    • InitializeDataCell
    • OnDataBindField

    InitializeDataCell determines the state of the current row in the GridView (is it edit or readonly). Then it instantiates the appropriate controls. In my case, the default DataControlFieldCell for read-only and a (you guessed it) DropDownList for edit. Additionally, it wires up the DataBinding event for the control it just added.

    OnDataBindField is responsible for putting the right value in the control. In my case, we check to see whether or not we have a drop down list and if we do, then we apply some logic to populate the items in that list. An interesting point here is that you want to instantiate new ListItems for every row. If you only have one set of ListItems you will end up with odd behavior, because multiple DropDownLists will be referencing the same exact ListItems.

More Posts

Our Sponsors

Red-Gate!