Question

Edit for clarity: I know the code has 2 columns, one for title and one for date, I am trying to change the code so it displays 3 events per row.

I am new to development and I am trying to take an ASP control used in a Sitefinity 6.1 website that currently takes data from our SQL database and outputs it into a single column and instead produce an output in 3 columns.

The .ascx looks like this

<div style="margin:10px">
    <asp:MultiView ID="mvEvents" runat="server" ActiveViewIndex="0">
        <asp:View ID="viewDefault" runat="server">
            <asp:Table ID="tblEvents" runat="server" CellPadding="5">
            </asp:Table>
        </asp:View>
        <asp:View ID="viewList" runat="server">
            <asp:Table ID="tblEventsList" runat="server" CellPadding="5">
            </asp:Table>
        </asp:View>
    </asp:MultiView>
</div>

The PageLoad and BuildEvents portions of the .ascx.cs code look like this

protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            CalendarDataContext db = new CalendarDataContext();

            var evt = db.CalendarEvents(NumberToDisplay, Department);

            foreach (CalendarEventsResult Evt in evt)
            {
                if (Department == "List")
                {
                    BuildEventsList(Evt.event_name, Evt.event_start_date, Evt.event_idn, Evt.information_id);
                }
                else
                {
                    BuildEvents(Evt.event_name, Evt.event_start_date, Evt.event_idn, Evt.information_id);
                }
            }
            return;
        }
        catch(Exception ex)
        {
        }
    }

    protected void BuildEvents(string EvtTitle, DateTime EvtStart, int EvtIdn, int EvtInfoIdn)
    {
        //EvtInfoIdn shows Event Description without location.  EvtInfoIdn - 1 shows location information. changing the href to eventInfoId
        int EvtInfoId = EvtInfoIdn - 1;


        TableRow tr = new TableRow();
        tr.VerticalAlign = VerticalAlign.Top;
        tr.HorizontalAlign = HorizontalAlign.Center;
        TableCell tcTitle = new TableCell();
        TableCell tcStart = new TableCell();
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(ShortMonth(EvtStart.Month));
        sb.AppendLine(EvtStart.Day.ToString());

        tr.VerticalAlign = VerticalAlign.Bottom;
        tr.Height = Unit.Pixel(80);

        Literal litDate = new Literal();
        litDate.Text = "<div class='EventDate'>" + sb.ToString() + "</div>";
        tcStart.Controls.Add(litDate);

        Literal litTitle = new Literal();
        litTitle.Text = @"<div class='EventTitle'><a style='text-decoration:none;' href='http://events.website.edu/EventList.aspx?view=EventDetails&eventidn=" + EvtIdn.ToString().Trim() + "&information_id=" + EvtInfoId + "&type=&rss=rss'>";
        litTitle.Text = litTitle.Text + EvtTitle + "</a></div>";
        tcTitle.Controls.Add(litTitle);

        tr.Cells.Add(tcStart);
        tr.Cells.Add(tcTitle);

        tblEvents.Rows.Add(tr);
    }

I have tried adding a ColumnSpan = "3" attribute to the ascx file and also tried adding the ColumnSpan to tcStart and tcTitle in the cs file as well in addition to trying to redesign the ascx in design mode and nothing I have though of has worked. I realize this is likely an easy fix, but I am new to C# programming. I appreciate any help provided.

Was it helpful?

Solution

Try the following -- n.b. I haven't been able to test fully as I haven't mocked up your bespoke classes, e.g. CalendarDataContext.

The basic premise is that the CalandarEvents collection is processed in batches of 3 (or whatever number you choose) and that the BuildEvents method now is broken down into smaller parts, each with their own responsibility, which should help with maintenance going forward.

    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            CalendarDataContext db = new CalendarDataContext();
            var evt = db.CalendarEvents(NumberToDisplay, Department);

            if (Department == "List")
            {
                foreach (CalendarEventsResult cer in evt)
                {
                    BuildEventsList(cer.event_name, cer.event_start_date, cer.event_idn, cer.information_id);
                }
            }
            else
            {
                // Depending what type evt is may depend on how to convert to the List.
                // This assumes that it supports IEnumerable (like DataTable) 
                List<CalendarEventsResult> events = evt.AsEnumerable().ToList();

                // Rather than hard-coding, read this from config or database 
                // to allow easier changing to a different number of events per row?
                int numberOfEventsPerRow = 3;

                // loop increments in steps of 3 (numberOfEventsPerRow)
                for (int rowNumber = 0; rowNumber < events.Count; rowNumber += numberOfEventsPerRow)
                {
                    // use Linq to pick out the subset of Events to process
                    List<CalendarEventsResult> queryEvents = events
                        .Skip(numberOfEventsPerRow * rowNumber)
                        .Take(numberOfEventsPerRow).ToList<CalendarEventsResult>();

                    // Build a row using that subset
                    TableRow tr = buildRow(queryEvents, numberOfEventsPerRow);
                    // Add it to the table
                    tblEvents.Rows.Add(tr);
                }
            }
        }
        catch (Exception ex)
        {
            // this just suppresses any exceptions. Better to fix issues at source.
        }
    }

    private TableRow buildRow(List<CalendarEventsResult> events, int eventsPerRow)
    {
        TableRow tr = new TableRow();

        // Can these be added to CSS?
        tr.HorizontalAlign = HorizontalAlign.Center;
        tr.VerticalAlign = VerticalAlign.Bottom;
        tr.Height = Unit.Pixel(80);

        TableCell tc;

        // for our event subset, build a pair of cells for each Event,
        // adding them to a row
        foreach (var evt in events)
        {
            tc = BuildEventDate(evt);
            tr.Cells.Add(tc);
            tc = BuildEventTitle(evt);
            tr.Cells.Add(tc);
        }

        // If we're dealing with a partial row, i.e. only 1 or 2 Events,
        // pad the row with empty cells.
        if (events.Count < eventsPerRow)
        {
            tc = BuildEmptyCell(eventsPerRow - events.Count);
            tr.Cells.Add(tc);
        }

        return tr;
    }

    private TableCell BuildEventDate(CalendarEventsResult evt)
    {
        TableCell tc = new TableCell();

        Literal litDate = new Literal();
        //String.Format should suffice c.f. StringBuilder
        litDate.Text = String.Format("<div class='EventDate'>{0}{1}</div>", ShortMonth(evt.Month), evt.Day.ToString());
        tc.Controls.Add(litDate);

        return tc;
    }

    private TableCell BuildEventTitle(CalendarEventsResult evt)
    {
        TableCell tc = new TableCell();
        int evtInfoId = evt.information_id - 1;

        Literal litTitle = new Literal();
        // n.b. hard-coded URL doesn't look good for ease of maintenance (move to config or CalendarEventsResult?)
        litTitle.Text = String.Format(@"<div class='EventTitle'><a style='text-decoration:none;' href='http://events.website.edu/EventList.aspx?view=EventDetails&eventidn={0}&information_id={1}&type=&rss=rss'>{2}</a></div>", 
            evt.event_idn.ToString().Trim(), evtInfoId, evt.event_name);
        tc.Controls.Add(litTitle);

        return tc;
    }

    private TableCell BuildEmptyCell(int numberOfEvents)
    {
        // Define as const rather than having unexplained "2" hard-coded.
        const int spanPerEvent = 2;

        TableCell tc = new TableCell();
        tc.ColumnSpan = spanPerEvent * numberOfEvents;
        tc.Text = "";
        return tc;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top