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;

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
.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.

        <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.


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.

Steve said...

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

Steve :d