views:

161

answers:

2

The elegant Action Syntax in the MVCContrib Grid gives us the Empty() method. However, the default behavior of MvcContrib.UI.Grid.GridRenderer<T>.RenderHeader() is to hide the table column headers when the grid is empty. Is there a way to show headers when data is not present that does not require a major refactoring?

Now I have heard of hiding the headers by default and hard-coding something but this is not cool to me.

By the way, this is what is happening under the hood (in MvcContrib.UI.Grid.GridRenderer<T>):

protected virtual bool RenderHeader()
{
    //No items - do not render a header.
    if(! ShouldRenderHeader()) return false;

    RenderHeadStart();

    foreach(var column in VisibleColumns())
    {
        //Allow for custom header overrides.
        if(column.CustomHeaderRenderer != null)
        {
            column.CustomHeaderRenderer(new RenderingContext(Writer, Context, _engines));
        }
        else
        {
            RenderHeaderCellStart(column);
            RenderHeaderText(column);
            RenderHeaderCellEnd();
        }
    }

    RenderHeadEnd();

    return true;
}

protected virtual bool ShouldRenderHeader()
{
    return !IsDataSourceEmpty();
}

protected bool IsDataSourceEmpty()
{
    return DataSource == null || !DataSource.Any();
}
A: 

Can't you just comment out the check to see if it should render the header. Am I missing something or do you want it to always display the header?

If so then comment out that line.

//if(! ShouldRenderHeader()) return false;

I haven't looks at all the code but from your code snippet it seems like that should work.

Jeff T
I don't want to disable default functionality in MVCContrib... we need to look for formal extensibility points...
rasx
I see now... I already have a 'formal extensibility point' working; it is sub-classing `GridRenderer<T>`---all I have to do (it seems) is override `RenderHeader()`...
rasx
+2  A: 

In your custom Grid Renderer (subclass GridRenderer<T>) use overrides like these:

/// <summary>
/// Renders the <c>table</c> header.
/// </summary>
/// <returns>
/// Returns the negative of the results
/// of <see cref="GridRenderer<T>.IsDataSourceEmpty"/>.
/// </returns>
/// <remarks>
/// The return value of <see cref="GridRenderer<T>.IsDataSourceEmpty"/>
/// in this override has no effect on whether the Grid header is rendered.
/// 
/// However, this return value is used
/// by <see cref="GridRenderer<T>.Render"/>
/// to run <see cref="GridRenderer<T>.RenderItems"/>
/// or <see cref="GridRenderer<T>.RenderEmpty"/>.
/// </remarks>
protected override bool RenderHeader()
{
    RenderHeadStart();

    foreach(var column in VisibleColumns())
    {
        //Allow for custom header overrides.
        if(column.CustomHeaderRenderer != null)
        {
            column.CustomHeaderRenderer(new RenderingContext(Writer, Context, _engines));
        }
        else
        {
            RenderHeaderCellStart(column);
            RenderHeaderText(column);
            RenderHeaderCellEnd();
        }
    }

    RenderHeadEnd();

    return !base.IsDataSourceEmpty();
}

protected override void RenderEmpty()
{
    RenderBodyStart();
    WriteNoRecordsAvailable(base.Writer, this._numberOfTableColumns);
    RenderBodyEnd();
}

Note that WriteNoRecordsAvailable() is my custom method so it can be ignored.

Finally:

/// <summary>
/// This private member is duplicated
/// in order to override <see cref="GridRenderer<T>.RenderHeader"/>.
/// </summary>
readonly ViewEngineCollection _engines;

/// <summary>
/// Initializes a new instance of the <see cref="CrmHtmlTableGridRenderer&lt;T&gt;"/> class.
/// </summary>
/// <param name="engines">The engines.</param>
public CrmHtmlTableGridRenderer(ViewEngineCollection engines)
    : base(engines)
{
    _engines = engines;
}
rasx