Creating a row above the header or just extending the header

18 views
Skip to first unread message

james4651

unread,
Jul 2, 2009, 11:06:50 AM7/2/09
to mvccontrib-discuss
Hi,

I'm new to this group. I have created a grid using the mvc contrib
grib but having some trouble with adding on to the header of a certain
column. I tried using the .Header for a certain column but it just
places it in the first column. I'm trying to place some arrows above
a column to manipulate that column row order. I have an ajax call for
the current header of that column I need to keep. I started making a
grid renderer but having some trouble figuring out how to add the row/
header/cell. I was able to create a javascript to create it but it
just disappears on any of the ajax calls. So any help or if someone
has an example would be helpful.

Thanks

Jeremy Skinner

unread,
Jul 2, 2009, 11:42:24 AM7/2/09
to mvccontri...@googlegroups.com
As I already mentioned in your post on the issue tracker (http://mvccontrib.codeplex.com/WorkItem/View.aspx?WorkItemId=4648) the reason that Header isn't rendering in the right column was because because you're not including the <th></th> tags.

I must admit that I'm still not following exactly what you're trying to do. If all you want is to include some arrows in certain column headers, then calling .Header will work fine (see my example below). If, however, you're trying to introduce an entirely new row *above* the header row then you will need a custom GridRenderer for this (example below)

Using the Header method to customise a particular column heading:

    <%= Html.Grid(Customers).Columns(column => {
            column.For(x => x.Id);
             column.For(x => x.Name).Header("<th>Customer Name <img src='/arrow.gif' /></th>");
     }) %>

This injects the image next to the heading but only for the Name column.

If you want to inject an additional row above the header row, then you can use a custom GridRenderer:

public class AdditionalHeaderRowGridRenderer<T> : HtmlTableGridRenderer<T> where T : class
    {
        protected override void RenderHeadStart() {
            base.RenderHeadStart();

            //RenderHeadStart creates a <thead><tr>, so now we inject our additional row

            foreach (var column in GridModel.Columns) {
                RenderText("<th><img src='/arrow.gif' /></th>");
            }

            //Now we finish the additional row, and allow the header to continue rendering
            RenderText("</tr><tr>");
        }
    }

...which can then be used in your view:

<%= Html.Grid(Customers).Columns(column => {
            column.For(x => x.Id);
             column.For(x => x.Name);
     }).RenderUsing(new AdditionalHeaderRowGridRenderer<Customer>()) %>


Hopefully that makes sense

Jeremy


Patrick Evans

unread,
Jul 3, 2009, 5:18:21 PM7/3/09
to mvccontri...@googlegroups.com

Hi,

 

Sorry it took me so long to reply.  Too much to do.

 

I used what you did but instead of for each column just created a <th></th><th… out to the column.  Now to figure out how to remove the css for the column headers created before that in that extra row.   I wouldn’t imagine there is an example for this since adding an additional row for the header is unusual. 

 

Thanks you so much for your help.  I didn’t understand that you had to put the <th> </th> around what you wanted to display in a certain column header.   

 

________________

James Evans

Patrick Evans

unread,
Jul 6, 2009, 11:53:11 AM7/6/09
to mvccontri...@googlegroups.com

Hi,

 

Is there a way to call a partial when using the renderer to create a row above the header?  For example, this is what I have so far:

 

RenderText("<th id=inv></th><th id=inv></th><th id=inv></th><th id=inv></th><th id=arrows><img id=\"imgMoveToTop\" alt=\"Move to top\" src=\"../../Images/ico_arrow_up_dbl.png\" /><img id=\"imgMoveUp\" alt=\"Move up\" src=\"../../Images/ico_arrow_up_sngl.png\" /><img id=\"imgMoveDown\" alt=\"Move down\" src=\"../../Images/ico_arrow_down_sngl.png\" /><img id=\"imgMoveToBottom\" alt=\"Move to bottom\" src=\"../../Images/ico_arrow_down_dbl.png\" /></th>");

     

 

But was wondering if there was a way to call a partial?  I know it is unlikely but figured it couldn’t hurt to ask…I hope.  I looked through the other render methods and couldn’t find anything that looked like it would call a partial.

 

Thanks.

________________

 

Patrick Evans

Jeremy Skinner

unread,
Jul 6, 2009, 12:50:07 PM7/6/09
to mvccontri...@googlegroups.com
Yes, you could just call in to the ViewEngines collection directly to do this:

var view = ViewEngines.Engines.TryLocatePartial(Context, "view name here");

view.Render(Context, Writer);


(Context and Writer are properties on GridRenderer)

Jeremy

2009/7/6 Patrick Evans <patric...@adjilitygroup.com>

Patrick Evans

unread,
Jul 6, 2009, 1:12:06 PM7/6/09
to mvccontri...@googlegroups.com

Hi,

 

Can I change the model because the partial doesn’t take the model that was passed for the grid? 

 

Thanks again for all the help.  I really appreciate it.

 

________________

Patrick Evans

 

From: mvccontri...@googlegroups.com [mailto:mvccontri...@googlegroups.com] On Behalf Of Jeremy Skinner
Sent: Monday, July 06, 2009 11:50 AM
To: mvccontri...@googlegroups.com
Subject: [mvccontrib-discuss] Re: Creating a row above the header or just extending the header

 

Yes, you could just call in to the ViewEngines collection directly to do this:

Jeremy Skinner

unread,
Jul 6, 2009, 1:41:23 PM7/6/09
to mvccontri...@googlegroups.com
Yes, just use a new ViewContext (with a new ViewDataDictionary) and pass that to the partial instead.

Patrick Evans

unread,
Jul 6, 2009, 5:24:08 PM7/6/09
to mvccontri...@googlegroups.com

Hi,

 

I have created a new ViewContext and can call the partial fine but how do you put that web form into the current view? 

 

Thanks

Patrick Evans

unread,
Jul 6, 2009, 5:32:03 PM7/6/09
to mvccontri...@googlegroups.com

Hi,

 

Sorry was using the wrong context, it works except the partial isn’t listed in the column extended header.  hehe

 

Thanks

Jeremy Skinner

unread,
Jul 7, 2009, 3:05:48 AM7/7/09
to mvccontri...@googlegroups.com
I don't follow. Partial views render directly to the response stream, so it will render at whatever point you call view.Render()

Patrick Evans

unread,
Jul 7, 2009, 9:16:08 AM7/7/09
to mvccontri...@googlegroups.com

Hi,

 

Here is what I have.  I would of thought it would put the partial in the header too.

RenderText("<th id=inv></th><th id=inv></th><th id=inv></th><th id=inv></th><th id=arrows");

 

ViewDataDictionary vdd = new ViewDataDictionary(new OrderViewModel());

TempDataDictionary tdd = new TempDataDictionary();

               

ViewContext v = new ViewContext(Context, Context.View, vdd, tdd);

var view = ViewEngines.Engines.TryLocatePartial(v, "ReorderButtons");

               

view.Render(v, m_Writer);

RenderText("</th>");

 

 

 

________________

Patrick Evans

 

 

 

From: mvccontri...@googlegroups.com [mailto:mvccontri...@googlegroups.com] On Behalf Of Jeremy Skinner
Sent: Tuesday, July 07, 2009 2:06 AM
To: mvccontri...@googlegroups.com
Subject: [mvccontrib-discuss] Re: Creating a row above the header or just extending the header

 

I don't follow. Partial views render directly to the response stream, so it will render at whatever point you call view.Render()

Jeremy

Jeremy Skinner

unread,
Jul 7, 2009, 11:34:08 AM7/7/09
to mvccontri...@googlegroups.com
If you could post all of your code for your custom GridRenderer I'll take a look at it.

Jeremy

2009/7/7 Patrick Evans <patric...@adjilitygroup.com>

Patrick Evans

unread,
Jul 7, 2009, 12:50:16 PM7/7/09
to mvccontri...@googlegroups.com

Hi,

 

The call is at the bottom for rendering the arrow header.

 

namespace eDoc.Portal.Web.Helpers

{

    [MinimumColumnGridRenderer]

    public class GovernGridRenderer<T> : HtmlTableGridRenderer<T> where T : class

    {

 

        public GovernGridRenderer()

            : base()

        {

 

        }

 

        public GovernGridRenderer(ViewEngineCollection engines)

            : base(engines)

        {

            this.m_Engines = engines;

        }

 

        protected ViewEngineCollection m_Engines;

 

        protected TextWriter m_Writer;

 

        protected ViewContext m_Context;

 

        protected override bool RenderHeader()

        {

            IMinimumColumn<T> model = this.GridModel as IMinimumColumn<T>;

           

            if (model != null

                && this.VisibleColumns().Count() < model.MinimumColumns)

            {

                return false;

            }

            this.RenderArrowHeader();

            return base.RenderHeader();

        }

 

 

        protected override void RenderRowStart(GridRowViewData<T> rowData)

        {

            IDictionary<string, object> attributes = GridModel.Sections.Row.Attributes(rowData);

            if (!attributes.ContainsKey("class"))

            {

                attributes.Add("class", string.Empty);

            }

            attributes["class"] = string.Format("{0} {1}", attributes["class"].ToString(), (rowData.IsAlternate ? "gridrow_alternate" : "gridrow"));

            string str = BuildAttributes(attributes);

            RenderText(string.Format("<tr {0}>", str));

        }

 

        protected string BuildAttributes(IDictionary<string, object> attributes)

        {

            if ((attributes == null) || (attributes.Count == 0))

            {

                return string.Empty;

            }

            return string.Join(" ", attributes.Select<KeyValuePair<string, object>, string>(delegate(KeyValuePair<string, object> pair)

            {

                return string.Format("{0}=\"{1}\"", pair.Key, pair.Value);

            }).ToArray<string>());

        }

 

 

 

        protected void RenderArrowHeader()

        {

            base.RenderHeadStart();

            if (this.VisibleColumns().Count() > 6)

            {

                // other table

                //foreach (var column in GridModel.Columns)

                //{

                    RenderText("<Row><Cell id=\"inv\"><Data></Data></Cell><Data></Data><Cell id=\"inv\"><Data></Data></Cell><Data></Data><Cell id=\"inv\"><Data></Data></Cell><Cell id=\"inv\"><Data></Data></Cell><Cell id=\"inv\"><Data></Data></Cell><Cell id=\"inv\"><Data></Data></Cell><Cell id=\"inv\"><Data></Data></Cell><Cell id=\"inv\"><Data><img id=\"imgMoveToTop\" alt=\"Move to top\" src=\"../../Images/ico_arrow_up_dbl.png\" /><img id=\"imgMoveUp\" alt=\"Move up\" src=\"../../Images/ico_arrow_up_sngl.png\" /><img id=\"imgMoveDown\" alt=\"Move down\" src=\"../../Images/ico_arrow_down_sngl.png\" /><img id=\"imgMoveToBottom\" alt=\"Move to bottom\" src=\"../../Images/ico_arrow_down_dbl.png\" /></Data></Cell></Row>");

                //}

            }

            else if (this.VisibleColumns().Count() > 4)

            {

                // table

                //foreach (var column in GridModel.Columns)

                //{

                RenderText("<th id=inv></th><th id=inv></th><th id=inv></th><th id=inv></th><th id=arrows>”);

                ViewDataDictionary vdd = new ViewDataDictionary(new OrderViewModel());

                TempDataDictionary tdd = new TempDataDictionary();

               

                ViewContext v = new ViewContext(Context, Context.View, vdd, tdd);

                var view = ViewEngines.Engines.TryLocatePartial(v, "ReorderButtons");

               

                view.Render(v, m_Writer);

                RenderText("</th>");

                   

                //}

            }

            base.RenderHeadEnd();

        }

 

 

    }

 

}

 

________________

Patrick Evans

 

From: mvccontri...@googlegroups.com [mailto:mvccontri...@googlegroups.com] On Behalf Of Jeremy Skinner
Sent: Tuesday, July 07, 2009 10:34 AM
To: mvccontri...@googlegroups.com
Subject: [mvccontrib-discuss] Re: Creating a row above the header or just extending the header

 

If you could post all of your code for your custom GridRenderer I'll take a look at it.

 

Jeremy

Jeremy Skinner

unread,
Jul 7, 2009, 1:36:04 PM7/7/09
to mvccontri...@googlegroups.com
It's a bit difficult to diagnose the exact problem that you're seeing without seeing the surrounding markup and partial views. Here is a simple example of a renderer that outputs a partial view above each column heading:

 public class AdditionalHeaderRowGridRenderer<T> : HtmlTableGridRenderer<T> where T : class {

protected override void RenderHeadStart() {

base.RenderHeadStart();


foreach (var column in GridModel.Columns) {

var partial = ViewEngines.Engines.TryLocatePartial(Context, "foo");

var newViewContext = new ViewContext(base.Context, partial, new ViewDataDictionary(), base.Context.Controller.TempData);

partial.Render(newViewContext, base.Writer);

}


RenderText("</tr><tr>");

}

}



the foo.ascx partial looks like this:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<th>Foo</th>

(You could move the <th /> tags into the renderer if you don't want to specify them in the partial)

Jeremy


2009/7/7 Patrick Evans <patric...@adjilitygroup.com>

Hi,

Patrick Evans

unread,
Jul 7, 2009, 2:40:58 PM7/7/09
to mvccontri...@googlegroups.com

Hi,

 

The only thing I see different is that you are creating the new context after the partial call.  I thought I had to create the context before calling the partial to pass the new model. 

 

Also is there a base.Writer for the HtmlGridRenderer?

 

Thanks again.  J

Jeremy Skinner

unread,
Jul 7, 2009, 2:44:27 PM7/7/09
to mvccontri...@googlegroups.com
Yes, there is a base.Writer, but only in the latest source code (I added it last week). The new context is only needed for rendering the view, finding the view can use the old one (although it won't make a difference). 

If things are still not being rendered in the correct place then it sounds like a problem with the HTML. I'd suggest making sure that the markup is valid and the elements are being rendered in the correct place, because as far as the GridRenderer is concerned everything appears to be set up correctly.

Patrick Evans

unread,
Jul 7, 2009, 2:50:04 PM7/7/09
to mvccontri...@googlegroups.com

Hi,

 

Ok, thanks for all the help and hope I wasn’t too much of a pain in the butt.  I will repost when I find the error.

 

________________

Patrick Evans

 

 

From: mvccontri...@googlegroups.com [mailto:mvccontri...@googlegroups.com] On Behalf Of Jeremy Skinner
Sent: Tuesday, July 07, 2009 1:44 PM
To: mvccontri...@googlegroups.com
Subject: [mvccontrib-discuss] Re: Creating a row above the header or just extending the header

 

Yes, there is a base.Writer, but only in the latest source code (I added it last week). The new context is only needed for rendering the view, finding the view can use the old one (although it won't make a difference). 

Reply all
Reply to author
Forward
0 new messages