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

25 comments:

Anonymous said...

I am new to dynamic data and programming. I am trying to implement this solution but I do not know where the two Extension Methods goes. Where do I paste? In the ForeignKey_Edit.aspx.cs?.

Thanks

Steve said...

Just place the extension methods in a public class of their own in the App_Code folder (I usually call it ExtensionMethods and then put all my extension methods in there.

Steve :D

Anonymous said...

I create a new class and paste the two extension methods, but I tried to run with no result. It say among other things that the Extension methods must be defined in a non-generic static class and the type or namespace name 'FilterUserControlBase' could not be found (are you missing a using directive or an assembly reference?).

I know this is a blog not a support site, but I thank for the initial responds and any help that you can provide
Thanks.
mahiraldo@hotmail.com

public class ExtensionMethods
{
public static IEnumerable FilterUserControlBase GetFilterControls(this FilterRepeater filterRepeater)
{
var filters = new ListFilterUserControlBase();

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

return filters.AsEnumerable();
}

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 "";
}
}

Steve said...

Sorry for not being clear you class also need to be static:
public static class ExtensionMethods
{

Sorry again
Steve :D

Anonymous said...

Hello Steve, I appreciate all your help that you give me. The solution works well thank to you.

i-developer said...

Hi,
I am logging all inserts and updates with user ID information. So i don't want to choose the user who created the insert or edited data. because i already who he/she is. So how can i insert user information when i insert data and user is foreign key.

i tried do it in detailsview1_iteminserting event but it's failed.

protected void DetailsView1_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
e.Values.Add("CreatedDate", DateTime.Now);
//e.Values.Add("aspnet_Users", Tools.GetCurrentUser());
}

I want your wonderful advices.

Steve said...

I would use the model in L2S <Table>Insert partial method on the data context or if you are useing EF look here http://msdn.microsoft.com/en-us/library/cc716714.aspx

Steve :D

Matt said...

Steve, I'm in a bind. I just want to simply have the foreign key selected filters auto-filled in when a user clicks 'Insert New Record' in any dynamic data instance. I need this in VB.net but can't find any instructional videos or step-by-steps. Is there a simple solution for this for a novice? It's the last part I need for my application, save for the proper ordering of the foreign key dropdownlist fields, which are not alphabetized based on the value..rather the primary key behind the scenes. Dynamic data was so close on everything else, not sure why they left out these elements. I'd appreciate anything you can offer. - Matthew Leach (matthewhleach@gmail.com)

Anonymous said...

How do you 'wire up the event handler' as you noted in Step 1? Shouldn't this be listed in the tutorial for a few of the slower folks (myself!)?

Steve said...

Change to Designe mode and click the dropdownlist and select the event icon (lightening bolt) not you can see the events instead of the properties. Find th ePreRender event and click the drop down list and choose the name of the method you pasted in.

Steve :D

Matt said...

Thanks Steve. The event handler link solved my issue. I appreciate the quick responses as I'm almost there. One last question when you are less busy: Is there a way to apply the same behavior to the 'Insert New Item' button outside of the Gridview? The querystring pass and default set on foreign key filter work fine when inserting off the link within the gridview, but I'm hoping I can link it to the general insert outside of the gridview at the bottom. I tried the code from your steps, but it doesn't seem to operate the hyperlink in the same way. -m

Steve said...

Sorry Matt, I don't understand your question, why don't you e-mail me direct, my e-mail is in the top right hand side of the page.

Steve :D

Anonymous said...

Hi. Sorry to bother you. I tried to add your tutorial to my dynamic data project and know I get the following compiler error and I don't know how to solve it:

CS0121: The call is ambigous between the following methods: 'ExtensionMethods.GetFilterControls(System.Web.DynamicData.FilterRepeater)' and 'ExtensionMethods.GetFilterControls(System.Web.DynamicData.FilterRepeater)'

Anonymous said...

Sorry, forget about the issue. I solved it myself. Was a project setting thing. Thanks anyway.

funky3l said...

Hello!
Thanks for such a grand nice example. However, I was wondering whether it would be possible to insert a new item on the basis of an existing one that would work similarly to the "Edit" button. Wouldn't it be a good idea for another post?

funky3l said...

Hello!
Thanks for such a grand nice example. However, I was wondering whether it would be possible to insert a new item on the basis of an existing one that would work similarly to the "Edit" button. Wouldn't it be a good idea for another post?

Steve said...

There is a project on codeplex N41 which adds clone behavoir to DD already.

Steve :D

wRAR said...

Unfortunately, it doesn't work with QueryableFilterRepeater/QueryableFilterUserControl. QueryableFilterRepeater doesn't have an easy way to iterate over filters (but it is not fatal), and DynamicFilter/QueryableFilterUserControl don't have a way to get the selected valuem only IQueryable.

Steve said...

Hi wRaR, is that in DDv2 with VS2010?

wRAR said...

No, DD Preview 4 in VS2008.

Steve said...

Hi wRAR they are now superceded with VS2010 and .Net 4.0, I shall look at doing a version for DDv2 and VS2010 soon.

Steve :D

Anonymous said...

Where do you put the hyperlink in List? In the PageLoad? I tried that and get...

'System.Web.DynamicData.QueryableFilterRepeater' does not contain a definition for 'GetQueryStringParameters' and the best extension method overload 'ExtensionMethods.GetQueryStringParameters(System.Web.DynamicData.FilterRepeater)' has some invalid arguments

Steve said...

Hi there, this is an old post for DD in .Net 3.5 not .Net 4 sorry

Anonymous said...

Thanks again for the great article. Is there any way to make this work with the 4 framework or do you have an updated article using 4? Thanks again for the article and the quick response.

Steve said...

Hi again, yes you can get the values using this example see http://csharpbits.notaclue.net/2010/12/filter-history-for-dynamic-data-4.html

Steve