Asked  9 Months ago    Answers:  5   Viewed   209 times

I'm creating a table inside a repeater programmatically. My problem is that the cells in the item template part don't render properly. They are showing up as text nodes after the table's markup. Does anyone have any suggestions on how to get the table cells rendering properly?

using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class WebForm2 : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                var dogs = new List<Dog>
                {
                    new Dog { Name = "Rex", Breed = "Russell Terrier" },
                    new Dog { Name = "Fido", Breed = "Poodle" },
                    new Dog { Name = "Fetcher", Breed = "Golden Retriever" },
                };

                var repeater = new Repeater { ID = "Repeater1" };
                repeater.DataSource = dogs;
                repeater.DataBind();

                AddHeader(repeater);
                AddItems(repeater, dogs);

                PlaceHolder1.Controls.Add(repeater);
            }
        }

        private void AddHeader(Repeater repeater)
        {
            var repeaterItem = new RepeaterItem(0, ListItemType.Header);
            var table = new HtmlTable();
            var row = new HtmlTableRow();
            var cell1 = new HtmlTableCell("th") { InnerText = "Name" };
            var cell2 = new HtmlTableCell("th") { InnerText = "Breed" };
            row.Cells.Add(cell1);
            row.Cells.Add(cell2);
            table.Rows.Add(row);
            repeaterItem.Controls.Add(table);
            repeater.Controls.Add(repeaterItem);
        }

        private void AddItems(Repeater repeater, List<Dog> dogs)
        {
            for (var i = 0; i < repeater.Items.Count; i++)
            {
                var repeaterItem = new RepeaterItem(i + 1, ListItemType.Item);
                var row = new HtmlTableRow();
                var cell1 = new HtmlTableCell() { InnerText = dogs[i].Name };
                var cell2 = new HtmlTableCell() { InnerText = dogs[i].Breed };
                row.Cells.Add(cell1);
                row.Cells.Add(cell2);
                repeaterItem.Controls.Add(row);
                repeater.Controls.Add(repeaterItem);
            }
        }

        private sealed class Dog
        {
            public string Breed { get; set; }
            public string Name { get; set; }
        }
    }
}

UPDATE: Thanks to Rob's help, I was able to get the code working. Now I have a fully-functional Repeater being loaded entirely in the code-behind with data-binding. Nice!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using ExtensionMethods.WebControls;

namespace WebApplication1
{
    public partial class WebForm1 : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var dogs = new List<Dog>
            {
                new Dog { Name = "Rex", Breed = "Russell Terrier" },
                new Dog { Name = "Fido", Breed = "Poodle" },
                new Dog { Name = "Fetcher", Breed = "Golden Retriever" },
            };

            var repeater = new Repeater
            {
                ID             = "Repeater1",
                HeaderTemplate = new CustomTemplate(ListItemType.Header),
                ItemTemplate   = new CustomTemplate(ListItemType.Item),
                FooterTemplate = new CustomTemplate(ListItemType.Footer),
                DataSource     = dogs
            };

            repeater.DataBind();
            PlaceHolder1.Controls.Add(repeater);
        }

        // Custom template class to add controls to the repeater's header, item and footer sections.
        private sealed class CustomTemplate : ITemplate
        {
            private ListItemType ListItemType { get; set; }

            public CustomTemplate(ListItemType type)
            {
                ListItemType = type;
            }

            public void InstantiateIn(Control container)
            {
                if (ListItemType == ListItemType.Header)
                {
                    var table = new LiteralControl();
                    var head = new HtmlGenericControl("thead");
                    var row = new HtmlTableRow();
                    row.Cells.Add(new HtmlTableCell("th") { InnerText = "Breed" });
                    row.Cells.Add(new HtmlTableCell("th") { InnerText = "Name" });
                    head.Controls.Add(row);
                    table.Text = string.Format("<table>{0}<tbody>", head.RenderHtml());
                    container.Controls.Add(table);
                }
                else if (ListItemType == ListItemType.Item)
                {
                    var row = new HtmlTableRow();

                    var cell1 = new HtmlTableCell();
                    cell1.Controls.Add(new Literal { ID = "LiteralBreed" });
                    row.Cells.Add(cell1);

                    var cell2 = new HtmlTableCell();
                    cell2.Controls.Add(new Literal { ID = "LiteralName" });
                    row.Cells.Add(cell2);

                    container.Controls.Add(row);
                    container.DataBinding += new EventHandler(Container_DataBinding);
                }
                else if (ListItemType == ListItemType.Footer)
                {
                    var footer = new LiteralControl("</tbody></table>");
                    container.Controls.Add(footer);
                }
            }

            // Event handler to populate the dog's breed and name in the table when data-binding occurs.
            private void Container_DataBinding(object sender, EventArgs e)
            {
                var item = sender as RepeaterItem;
                if (item != null)
                {
                    var dog = ((Dog)item.DataItem);

                    var breed = item.FindDescendantsByType<Literal>().Single(x => x.ID == "LiteralBreed");
                    breed.Text = dog.Breed;

                    var name = item.FindDescendantsByType<Literal>().Single(x => x.ID == "LiteralName");
                    name.Text = dog.Name;
                }
            }
        }

        private sealed class Dog
        {
            public string Breed { get; set; }
            public string Name { get; set; }
        }
    }
}

 Answers

5

That's because in your logic you are creating a table with a header in the AddHeader method and adding it to the repeater, that will create:

<table>
<tbody><tr>
    <th>Name</th>
    <th>Breed</th>
</tr></tbody>
</table>

Then you add the list items to the repeater, yes to the repeater, not to the first table. You are adding table rows to the repeader after the table, and the browser will render this rows and cells as just text nodes because they don't have their parent tbody table elements.

The repeater writes HTML so you need to find a way to have the open and close table tags

<table>
    <tbody>
        <asp:Repeater ID="fooRepeater" runat="server" ></asp:Repeater>
    </tbody>       
</table>

So the repeater render will be something like: RexRussell Terrier For each item

I believe your logic is wrong if you want each item in the repeater as a table you need to change your code like this:

    private void AddItems(Repeater repeater, List<Dog> dogs)
    {
        var repeaterItem = new RepeaterItem(0, ListItemType.Header);
        var table = new HtmlTable();
        var row = new HtmlTableRow();
        var cell1 = new HtmlTableCell("th") { InnerText = "Name" };
        var cell2 = new HtmlTableCell("th") { InnerText = "Breed" };
        row.Cells.Add(cell1);
        row.Cells.Add(cell2);
        table.Rows.Add(row);

        for (var i = 0; i < repeater.Items.Count; i++)
        {
            repeaterItem = new RepeaterItem(i + 1, ListItemType.Item);
            row = new HtmlTableRow();
            cell1 = new HtmlTableCell() { InnerText = dogs[i].Name };
            cell2 = new HtmlTableCell() { InnerText = dogs[i].Breed };
            row.Cells.Add(cell1);
            row.Cells.Add(cell2);

            table.Rows.Add(row);
        }

        repeaterItem.Controls.Add(table);
        repeater.Controls.Add(repeaterItem);

    }

Everything will happen in the AddItems method and you no longer need the AddHeader. If you want each repeater item be the row of a table the logic must be different.

Saturday, August 28, 2021
 
4

You can use __doPostBack from the script, and use the RaisePostBackEvent method in the code behind to perform your server-side logic. If you're looking to do a redirect, this would probably be the best way.

EDIT

If you're looking to do some validation in JavaScript when a button is clicked, use OnClientClick to perform your JavaScript validation, and return true if the validation succeeds.

<asp:Button ID="Button1" runat="server" OnClientClick="return validateStuff();" OnClick="Button1_Click" />

Your JavaScript validation:

validateStuff = function(){
    var isValid = true;
    var txt = document.getElementById("<%=TextBox1.ClientID%>");
    if (txt.value.toLower() != "james"){
       isValid = false;
    }        
    return isValid;
}

If the validateStuff function returns true, a postback will occur and you can handle your save/update logic in the button click event:

protected void Button1_Click(object sender, EventArgs e)
{
    //save some stuff to the database

    string txtValue = TextBox1.Text.Trim();
}

In JavaScript:

redirectToAnotherPage = function(){
    __doPostBack("<%=SomeServerControl.ClientID%>", "someArgument");
}

In the code-behind:

protected override void RaisePostBackEvent(IPostBackEventHandler source, string eventArgument)
{
    //call the RaisePostBack event 
    base.RaisePostBackEvent(source, eventArgument);

    Response.Redirect("anotherpage.aspx");
}

If all you're looking to do is bring the user to another page, you can also do this:

redirectToAnotherPage = function(){
    window.location.href = "somepage.aspx";
}
Tuesday, August 24, 2021
 
Saurabh
 
2

There is a special syntax for using routes in markup: http://msdn.microsoft.com/en-us/library/dd329551.aspx#Y800

<asp:MenuItem NavigateUrl='<%$RouteUrl:about-route%>' Text="About"></asp:MenuItem>
Saturday, November 27, 2021
 
1

Here is a solution that worked for me. I used this stackoverflow answer (https://stackoverflow.com/a/2518441/2512022) to create the following function to test if a object has a specific handler bound to a specific event.

This function take a Object, Event Name, and handler function name as input parameters and will return true/false if the function is bound the event on the object passed in.

function testHandler(obj, sEvent, sHandlerName)
{
    var retVal = false;

    // Get all events bound to object
    var windowEvents = jQ._data(obj, "events");

    // Get all handlers for a specific event
    var handlers = windowEvents[sEvent];

    jQ(handlers).each(function() {
        // Using passed name to see if there is a match
        if(this.handler.name === sHandlerName)
        {
            retVal = true;
            return;
        }
    });

    return retVal;
}

Then call the function as follows.

// Test if there is a beforeclose() handler bound to the window objects
// "beforeunload" event

testHandler(window, "beforeunload", "beforeclose");

You could even test if there is on anonymous handler attached to an event. In the call below "this" references a button, and we are testing if there is an anonymous hanlder attached to the buttons click event

testHandler(this, "click", "anonymous");
Monday, December 6, 2021
 
4

If you need an instance object instead of a pointer, try:

trainer::trainer() : myPokemon(*this) {}

Be careful if Charizard tries to call any methods on tMyTrainer in its constructor, because your new trainer object has not yet been fully constructed at that time.

Monday, January 10, 2022
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :