Keep it MVC. Use templated controls without injecting Eval() in your aspx.

I am quite stubborn in keeping .aspx clean, try to keep only asp and html tag in it.

Until recently I need to use ListView and bind my data to it, almost 90% of the example available are using <%# Eval(“[PropertyName]”) %>.

But I really don’t want to stuff my .aspx with these things, I don’t know if they are VBScript or ASP code, anyway, I want to do that in C# code.

I image that is possible to customize my binding just like I did in Java. After searching and reading articles for a few hours, I finally got it.

I want to share my experience here hoping to save someone a few hours. I will try to give sample code download if I can.

First step, drag a ListView control to your page. There are three things a ListView must have.

1.You must have a <LayoutTemplate> in your ListView.

2.You must have a <PlaceHolder> in your <LayoutTemplate>.

3.Set ItemPlaceholderId to your PlaceHolder Id.

I am using table to display my data. You will result in something that looks like this:

<asp:ListView ID="ltv_users" runat="server" ItemPlaceholderID="plh_userItems"
        onitemcommand="ltv_users_ItemCommand"
        ondatabinding="ltv_users_DataBinding" onitemdeleting="ltv_users_ItemDeleting">
        <LayoutTemplate>
            <table class="ListViewTableStyle" border="1">
                <thead class="ListViewHeaderStyle">
                    <tr>
                        <td>
                        </td>
                        <td>
                            Column Header 1
                        </td>
                        <td>
                            Column Header 2
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <asp:PlaceHolder ID="plh_userItems" runat="server"></asp:PlaceHolder>
                </tbody>
            </table>
        </LayoutTemplate>
    </asp:ListView>

Second Step is to define your own customize Template to do data binding. Create a class which implement ITemplate interface under System.Web.UI namespace. People usually pass an enumerator to the constructor to indicate what type of template to create. The result looks like this.

public class UserTemplate : ITemplate
    {
        protected ListViewTemplateType m_templateType;
        public UserTemplate(ListViewTemplateType type)
        {
            m_templateType = type;
        }
    }

ListViewTemplateType is just an enumerator one to one maps to template available inside ListView tag. Then we implement two methods, InstantiateIn(Control container) which response for creating html tags and data binding method. Here is an example for generating different tags for different template.

public void InstantiateIn(Control container)
        {
            //for itemtemplate and alternativeitemtemplate
            LinkButton l_btnDetail = new LinkButton() { Text = m_DetailBtnText, ID = "btnDetail", CommandName = "Detail", CssClass = "ListViewButton" };
            LinkButton l_btnRole = new LinkButton() { Text = m_RoleBtnText, ID = "btnRole", CommandName = "Role", CssClass = "ListViewButton" };
            LinkButton l_btnDelete = new LinkButton() { Text = m_DeleteBtnText, ID = "btnDelete", CommandName = "Delete", CssClass = "ListViewButton" };
            Label l_lblAccount = new Label() { ID = "lblAccount" };
            Label l_lblUserName = new Label() { ID = "lblUserName" };
            switch (m_templateType)
            {
                //ListViewItemType.
                case ListViewTemplateType.ItemTemplate:
                    container.Controls.Add(new LiteralControl("<tr class=\"ListViewItemStyle\"><td>"));
                    container.Controls.Add(l_btnDetail);
                    container.Controls.Add(l_btnRole);
                    container.Controls.Add(l_btnDelete);
                    container.Controls.Add(new LiteralControl("</td><td>"));
                    container.Controls.Add(l_lblAccount);
                    container.Controls.Add(new LiteralControl("</td><td>"));
                    container.Controls.Add(l_lblUserName);
                    container.Controls.Add(new LiteralControl("</td></tr>"));
                    container.DataBinding += new EventHandler(ItemTemplate_DataBinding);
                    break;
                case ListViewTemplateType.AlternatingItemTemplate:
                    container.Controls.Add(new LiteralControl("<tr class=\"ListViewAlternativeItemStyle\"><td>"));
                    container.Controls.Add(l_btnDetail);
                    container.Controls.Add(l_btnRole);
                    container.Controls.Add(l_btnDelete);
                    container.Controls.Add(new LiteralControl("</td><td>"));
                    container.Controls.Add(l_lblAccount);
                    container.Controls.Add(new LiteralControl("</td><td>"));
                    container.Controls.Add(l_lblUserName);
                    container.Controls.Add(new LiteralControl("</td></tr>"));
                    container.DataBinding += new EventHandler(ItemTemplate_DataBinding);
                    break;
            }
        }

We need to define controls id so that we can later bind data to them by their id in ItemTemplate_DataBinding().

public void ItemTemplate_DataBinding(object sender, EventArgs e)
        {
            ListViewDataItem listViewDataItem = (ListViewDataItem)sender;
            string l_account = (string)DataBinder.Eval(listViewDataItem.DataItem, "Account");
            string l_userName = (string)DataBinder.Eval(listViewDataItem.DataItem, "FirstName") + (string)DataBinder.Eval(listViewDataItem.DataItem, "LastName");
            Guid l_userId = (Guid)DataBinder.Eval(listViewDataItem.DataItem, "Id");
            switch (m_templateType)
            {
                case ListViewTemplateType.ItemTemplate:
                case ListViewTemplateType.AlternatingItemTemplate:
                    ((LinkButton)listViewDataItem.FindControl("btnDetail")).CommandArgument = l_userId.ToString();
                    ((LinkButton)listViewDataItem.FindControl("btnRole")).CommandArgument = l_userId.ToString();
                    //((LinkButton)listViewDataItem.FindControl("btnDelete")).CommandArgument = l_userId.ToString();
                    LinkButton btnDelete = (LinkButton)listViewDataItem.FindControl("btnDelete");
                    btnDelete.CommandArgument = l_userId.ToString();
                    btnDelete.OnClientClick = m_ConfirmScript;
                    ((Label)listViewDataItem.FindControl("lblAccount")).Text = l_account;
                    ((Label)listViewDataItem.FindControl("lblUserName")).Text = l_userName;
                    break;
            }
        }

I am using a fall through here because ItemTemplate and AlternatingItemTemplate are binding data in the same way. You can bind textbox for ItemEditTemplate. I am going to show how to use this template class we make just now. How to work under asp page life cycle and use your own data source, and something about default ListView event handling. Read It Now!

One thought on “Keep it MVC. Use templated controls without injecting Eval() in your aspx.

  1. Pingback: ListView with dynamic template in action « 麥克斯做個不宅的工程師

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s