Showing posts with label Generics. Show all posts
Showing posts with label Generics. Show all posts

Friday, 23 January 2009

Getting Default Values from List page Filters for Insert – Dynamic Data

The Idea here is that when you are navigating through your pages you will select some filters on the way as here in Figure 1 where we have selected a Customer an Employee and a Shipper so what I wanted was not to throw away that information when I clicked insert and then get Figure 2.

Filtered Liast page

Figure 1 – Filtered List page

Values Defaulted on Insert

Figure 2 – Values Defaulted on Insert

Steps to Accomplish this:

  1. Modify ForeignKey_Edit.aspx.cs to check for query string parameters relating the column.
  2. Create a couple of extension methods to get the filters and then return a string of key, value query string.
  3. Hook up the Insert hyperlink to have these parameters if available to the insert URL.

Hope that makes sense.

Modify ForeignKey_Edit to check for query string parameters relating the column

This is relatively simple we just add an event handler to the DropDownList1’s PreRender event ForeignKey_Edit FieldTemplate code behind file.

protected void DropDownList1_PreRender(object sender, EventArgs e)
{
    // Adding a default value to a textbox
    // value aquired via query string
    string value = Request.QueryString[Column.Name];
    if (this.Mode == DataBoundControlMode.Insert && !string.IsNullOrEmpty(value))
    {
        ListItem item = DropDownList1.Items.FindByValue(value);
        if (item != null)
            DropDownList1.SelectedValue = value;
    }
}

Listing 1 – DropDownList’s PreRender event handler

Note: Don’t forget to wire up the event hander after pasting in the code.

What this does is check to see if there is a QueryString parameter that matches the column name and if this matches a value in the DropDownList’s Items collection it set’s this value as the DropDownList’s SelectedValue.

Creating Extension Methods that get the FilterUserControls and Return a String of Key, Value query string

There are two extension methods required:

  1. Gets a collection of the filters from the FilterRepeater that have a value.
  2. Take the filters and extract the key values pairs and return them as a QueryString to be appended to the Insert URL

Here’s the first one:

public static IEnumerable<FilterUserControlBase> GetFilterControls(this FilterRepeater filterRepeater)
{
    var filters = new List<FilterUserControlBase>();

    foreach (RepeaterItem item in filterRepeater.Items)
    {
        var filter = item.Controls.OfType<FilterUserControlBase>().FirstOrDefault();
        if (filter != null)
            filters.Add(filter);
    }

    return filters.AsEnumerable();
}

Listing 2 – GetFilterControls extension method.

This extension method shown in Listing 2 just loops through the FilterRepeater Items collection and using the OfType<T>() Linq extension method gets the FilterUserControl from it’s controls collection. Then adds this to the the list of found filters and finally returns the list.

public static String GetQueryStringParameters(this FilterRepeater filterRepeater)
{
    var filterControls = filterRepeater.GetFilterControls();
    if (filterControls.Count() > 0)
    {
        var queryParameters = new StringBuilder();
        queryParameters.Append("?");
        foreach (var filter in filterControls)
        {
            if (filter.SelectedValue != "")
                queryParameters.Append(filter.DataField + "=" + filter.SelectedValue + "&");
        }
        return queryParameters.ToString().Substring(0, queryParameters.Length - 1);
    }
    else
        return "";
}

Listing 3 – GetQueryStringParameters extensionmethod.

The second extension method shown in Listing 3 takes the output of the first and then loops through building the query parameters string for passing back to the caller.

Hook up the Insert hyperlink to the Returned Query Parameters

Now in the List page all you need to do is add the following code:

// setup the insert hyperlink
InsertHyperLink.NavigateUrl = table.GetActionPath(PageAction.Insert) 
    + FilterRepeater.GetQueryStringParameters();

Listing 4 – Putting the extension methods to use.

And this is why I like c# 3.0 extension methods so much HappyWizard

Tuesday, 20 January 2009

Writing Attributes and Extension Methods for Dynamic Data

This is just a short article on some useful tips I’ve found for writing Attributes for Dynamic Data.

I say Tips there really isn’t that much to this.

Let me show you an attribute I just created for a post on the Dynamic Data Forum:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class DisableEditingAttribute : Attribute
{
    public Boolean Disable { get; set; }

    public static DisableEditingAttribute Default = new DisableEditingAttribute();

    public DisableEditingAttribute() : this(false) { }

    public DisableEditingAttribute(Boolean disable)
    {
        Disable = disable;
    }
}

Listing 1 – Disable Editing Attribute

And here’s it being used in the List page:

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

    //GridView1.Sort("ColumnName, ColumnName", SortDirection.Descending);

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

    // Disable various options if the table is readonly
    var editingDisabled = table.Attributes.OfType<DisableEditingAttribute>().DefaultIfEmpty(new DisableEditingAttribute()).FirstOrDefault();
    if (table.IsReadOnly || editingDisabled.Disable)
    {
        GridView1.Columns[0].Visible = false;
        InsertHyperLink.Visible = false;
    }
}

Listing 2 – DisableEditingAttribute in use BOLD ITALIC

The first ting to note is a Linq thing; the DefautIfEmpty extension method. This is used to specify a default value if the returned value is null (From the OfType FirstOrDefault combination) this means I don’t have to test for null like:

// Disable various options if the table is readonly
var editingDisabled = table.Attributes.OfType<DisableEditingAttribute>().FirstOrDefault();
if (table.IsReadOnly || (editingDisabled != null && editingDisabled.Disable))
{
    GridView1.Columns[0].Visible = false;
    InsertHyperLink.Visible = false;
}

Listing 3 – Having to test for null

Another way of doing this would be to use a Default static method to provide the default value.

// Disable various options if the table is readonly
var editingDisabled = table.Attributes.OfType<DisableEditingAttribute>().
    DefaultIfEmpty(DisableEditingAttribute.Default).FirstOrDefault();
if (table.IsReadOnly || editingDisabled.Disable)
{
    GridView1.Columns[0].Visible = false;
    InsertHyperLink.Visible = false;
}

Listing 4 – using the Default static method

Either method works but my preference is to have a default constructor Attribute() and I’ll explain why. But first let me show you an Extension method I found in the Dynamic Data Futures project extension methods:

public static T GetAttribute<T>(this MetaTable table) where T : Attribute
{
    return table.Attributes.OfType<T>().FirstOrDefault();
}

Listing 5 – the GetAttribute Generic extension method.

And it’s use:

// Disable various options if the table is readonly
var editingDisabled = table.GetAttribute<DisableEditingAttribute>();
if (table.IsReadOnly || (editingDisabled != null && editingDisabled.Disable))
{
    GridView1.Columns[0].Visible = false;
    InsertHyperLink.Visible = false;
}

Listing 6 – the GetAttribute extension method in use

This is better more readable code but the test for null makes it a bit messy. So here are my interpretations of the GetAttribute extension method:

public static T GetAttributeOrDefault<T>(this MetaTable table) where T : Attribute, new()
{
    return table.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault();
}

public static T GetAttributeOrDefault<T>(this MetaColumn column) where T : Attribute, new()
{
    return column.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault();
}

Listing 7 – My GetAttributeOrDefault extension methods

All I’ve done here is use the DefaultIfEmpty Linq extension method and added an extra constraint to the generic class the make the extension method only work with attributes that have an explicit default Constructor.

And just for completeness here are all the generic extension methods together:

public static T GetAttributeOrDefault<T>(this MetaTable table) where T : Attribute, new()
{
    return table.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault();
}

public static T GetAttribute<T>(this MetaTable table) where T : Attribute
{
    return table.Attributes.OfType<T>().FirstOrDefault();
}

public static T GetAttributeOrDefault<T>(this MetaColumn column) where T : Attribute, new()
{
    return column.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault();
}

public static T GetAttribute<T>(this MetaColumn column) where T : Attribute
{
    return column.Attributes.OfType<T>().FirstOrDefault();
}

Listing 8 – All Generic Attributes together

The one in BOLD ITALIC is the original from Dynamic Data Futures project.

 

I think C# 3.0 is real neat HappyWizard