Sunday, 31 May 2009

Sorting Filters in Dynamic Data (DD v1.0)

This is just a small sample of how to sort your filters in Dynamic Data using the ColumnOrderAttribute from the Dynamic Data Futures project. I was surprised at how easy it was and that I’d not thought of it before.

using System;
using System.Linq;
using System.Web.DynamicData;

namespace DynamicData.CascadeExtensions
{
    /// <summary>
    /// Allows to specify the ordering of columns. 
/// Columns are will be sorted in increasing order based
/// on the Order value. Columns without this attribute
/// have a default Order of 0. Negative values are
/// allowed and can be used to place a column before all other columns. /// </summary> [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
Inherited = true,
AllowMultiple = false)] public class ColumnOrderAttribute : Attribute, IComparable { public static ColumnOrderAttribute Default = new ColumnOrderAttribute(0); public ColumnOrderAttribute(int order) { Order = order; } /// <summary> /// The ordering of a column. Can be negative. /// </summary> public int Order { get; private set; } public int ListOrder { get; set; } public int CompareTo(object obj) { return Order - ((ColumnOrderAttribute)obj).Order; } } public static partial class HelperExtansionMethods { public static ColumnOrderAttribute GetColumnOrdering(this MetaColumn column) { return column.Attributes.OfType<ColumnOrderAttribute>()
.DefaultIfEmpty(ColumnOrderAttribute.Default).First(); } } }

Listing 1 - Column Order attribute

So Listing 1 is just a direct rip off of the ColumnOrderAttribute in the Futures project. and then the code to order the filters based on the ColumnOrderAttribute.

protected void Page_Load(object sender, EventArgs e)
{
    table = GridDataSource.GetTable();
    Title = table.DisplayName;

    InsertHyperLink.NavigateUrl = table.GetActionPath(PageAction.Insert);

    // Disable various options if the table is readonly
    if (table.IsReadOnly)
    {
        GridView1.Columns[0].Visible = false;
        InsertHyperLink.Visible = false;
    }

    // set the filter order
    var filters = from c in table.Columns
                  where c is MetaForeignKeyColumn
                  orderby c.GetColumnOrdering()
                  select c;
    FilterRepeater.DataSource = filters;
    FilterRepeater.DataBind();
}

Listing 2 – modified Page_Load event handler

Here in Listing 2 you can see the code highlighted in bold italic is setting the filter sort order simples.

Note: the only caveat is that the filters are generated twice smile_sad

That caveat in mind I decided to do this instead:

public class SortedFilterRepeater : FilterRepeater
{
    protected override IEnumerable<MetaColumn> GetFilteredColumns()
    {
        // sort the filters by their filter order as specified in FilterAttribute.
        // Table.Columns.Where(c => IsFilterableColumn(c))
// .OrderBy(column => FilterOrdering(column));
var filteredColumns = from c in Table.Columns where IsFilterableColumn(c) orderby FilterOrdering(c) select c; return filteredColumns; } protected bool IsFilterableColumn(MetaColumn column) { // don't filter custom properties by default if (column.IsCustomProperty) return false; // always filter FK columns and bools if (column is MetaForeignKeyColumn) return true; if (column.ColumnType == typeof(bool)) return true; return false; } private ColumnOrderAttribute FilterOrdering(MetaColumn column) { return column.Attributes
.OfType<ColumnOrderAttribute>()
.DefaultIfEmpty(ColumnOrderAttribute.Default)
.First(); } }

Listing 3 – SortedFilterRepeater

Updated: Listing 3 is just a ripp-off on the AdvancedFilterRepeater in the Dynamic Data Futures sample.

I implemented this using by adding a mapping to the web.config as in Listing 4.

<pages>
    <tagMapping>
        <add tagType="System.Web.DynamicData.FilterRepeater"
mappedTagType="DynamicData.CascadeExtensions.SortedFilterRepeater" /> </tagMapping> </pages>

Listing 4 – Adding mapping to web.config

The advantage of the above is:

  1. It only generates the filters once
  2. This will work with my CascadingFilters

So I think this addendum wraps this up as we have sorting of filters in Dynamic Data Preview 4.

2 comments:

Ashwani Roy said...

Is it possible to apply ordering to the columns which appear in details view. Lets say my Table has col1 and col2.. , I can show then in col1..col2.. order by changing the XML of EDXM . but if one of this column is referenced by another entity and appears in Navigation Property I am not able to move it up or down.

Stephen J. Naughton said...

Yes, no problem have a look at this sample here that uses IAutoFieldGenerator to sort and move a column.

Steve :d