Saturday 17 July 2010

Autocomplete Filter from the old Futures project working in Dynamic Data 4

I was sorry that the Autocomplete filter from the old Futures project was not added to Dynamic Data 4 CryingSo I thought I would do it, so here it is. I also thought I would make it work with the Entity Framework as well.

First of all if you don’t have a copy of the old futures project then go get it from here Dynamic Data Futures VS2008 SP1 RTM this has many useful samples that are worth adapting to DD4.

Copying The Necessary Files

First we need to copy some filed from the old Futures project to the new project in Visual Studio 2010, see Figure 1 for the files we need and Figure 2 for the where we need to copy them

Autocomplete files LinqExpressionHelper.cs

 Figure 1 - Required files from old Futures project

Files Added to Custom Filter project

Figure 2 - Files Added to Custom Filters project

The Files will now need updating to work with this project.

Change namespace in each file

For this I usually just do a global replace in entire project

Ctrl+H  “Find and Replace”

Figure 3 - Ctrl+H  “Find and Replace”

Remove redundant using

In the Autocomplete.ascx.cs file remove the redundant using statement for Microsoft.Web.DynamicData.

Fix up the AutocompleteFilter.asmx.cs service.

First we need to add some references:

Download and add a reference to Ajax Control Toolkit,

Next we need is to add the using for generic collections;

using System.Collections.Generic;

Then we need to change this;

 return queryable.Cast<object>().Select(row => CreateAutoCompleteItem(table, row)).ToArray();

for this;

var values = new List<String>();
foreach (var row in queryable)
{
    values.Add( CreateAutoCompleteItem(table, row));
}

return values.ToArray(); 

This also makes it compatible with the Entity Framework

Fix up the Autocomplete filter it’s self.

The very first thing is the filter needs to inherit from “System.Web.DynamicData.QueryableFilterUserControl”

public partial class Autocomplete_Filter : System.Web.DynamicData.QueryableFilterUserControl

Add the following Usings:

using System.Web.UI;
using System.Collections;

Then we need to add some properties;

private new MetaForeignKeyColumn Column
{
    get { return (MetaForeignKeyColumn)base.Column; }
}

public override Control FilterControl
{
    get { return AutocompleteTextBox; }
}

Next replace ALL  occurrences of InitialValue with DefaultValue

In the CleantButton_Click event add OnFilterChanged() call

public void ClearButton_Click(object sender, EventArgs e)
{
    // this would probably be better handled using client JavaScirpt
    AutocompleteValue.Value = String.Empty;
    AutocompleteTextBox.Text = String.Empty;
    OnFilterChanged();
}

Remove the SelectedValue property and add the following event handler and method.

protected void AutocompleteValue_ValueChanged(object sender, EventArgs e)
{
    OnFilterChanged();
}

public override IQueryable GetQueryable(IQueryable source)
{
    string selectedValue = String.IsNullOrEmpty(AutocompleteValue.Value) ? null : AutocompleteValue.Value
    if (String.IsNullOrEmpty(selectedValue))
        return source;

    IDictionary dict = new Hashtable();
    Column.ExtractForeignKey(dict, selectedValue);
    foreach (DictionaryEntry entry in dict)
    {
        string key = (string)entry.Key;
        if (DefaultValues != null)
            DefaultValues[key] = entry.Value;

        source = ApplyEqualityFilter(source, Column.GetFilterExpression(key), entry.Value);
    }
    return source;
}

Listing 1 – New Methods for Autocomplete filter.

Next we need to hook-up the HiddenField’s OnValueChanged event handler to point to AutocompleteValue_ValueChanged method we just added, so it looks like this.

<asp:HiddenField
    runat="server" 
    ID="AutocompleteValue" 
    OnValueChanged="AutocompleteValue_ValueChanged"/>

Add a link to the Autocomplete css

Open site.master and drag the AutocompleteStyle.css to the Head section

<link href="AutocompleteStyle.css" rel="stylesheet" type="text/css" />

Now we need to add some styling to the Autocomplete.ascx filter, I’m just adding

CssClass="DDControl"

to the TextBox and Button controls.

Add some Metadata

In Listing 1 we have added a FilterUIHint setting the Autocomplete filter as the the filter for the Orders Customer property.

[MetadataTypeAttribute(typeof(Order.OrderMetadata))]
public partial class Order
{
    internal sealed class OrderMetadata
    {
        [FilterUIHint("Autocomplete")]
        public Customer Customer { get; set; }
    }
}

Listing 3 -  sample metadata

You should now have a working sample run it up and go to the Orders table list page:

Autocomplete filter in action

Figure 4 - Autocomplete filter in action

Downloads

Happy Coding Happy Wizzard

12 comments:

Jamie Batiste said...

Thanks Steve - I've been beating myself up over this in the old version plus the conversion to VB.

Am currently trying to combine AJAX modal popup to populate a foreign key with a datagrid...

Stephen J. Naughton said...

You're welcome :) and best of luck with AJAX I really lothe working with JavaScript :D

Steve

Romny said...

and entity model, as would be an example.??

Stephen J. Naughton said...

Hi Romny, the attached sample is with Entity Framework.

Steve.

Anonymous said...

Sorry, but where is the attachment for Entity Framework?

Stephen J. Naughton said...

The attached attachment is EF I didn't both with an L2S sample as it will work with L2S anyway.

Steve :D

Jim Foulkrod said...

Steve
This is just what I needed. My users need to search a database of custom Chemical compounds that have really long, complicated names. It installed easily and does just what I need.

Stephen J. Naughton said...

Great glad it's usefull :)

Steve

Amanda said...

This control seems to break BuildFilterQuery when the DisplayColumn is a non-string type. Any ideas on how to modify the expression get it to work with other value types?

Amanda said...

This control seems to break BuildFilterQuery when the DisplayColumn is a non-string type. Any ideas on how to modify the expression get it to work with other value types?

Stephen J. Naughton said...

Yes that is correct it will only work with string fields

Steve

JP said...

To anyone getting strange results : remove DelimiterCharacters in AutoCompleteExtender