Wednesday 3 September 2008

Dynamic Data Futures – Part 1 Adding Advanced Filters ***UPDATED***

  1. Part 1 - Getting Dynamic Data Futures filters working in a File Based Website.
  2. Part 2 - Create the AnyColumn filter from the Dynamic Data Futures Integer filter.
  3. Part 3 – Creating the AnyColumnAutocomplete filter.

Getting Dynamic Data Futures filters working in File Based Website

1. Adding Dynamic Data Futures to your Website

From the File menu of you file based website select Add –> Existing Project… (see Figure 1) and browse to the folder where you unzipped the Dynamic Data Futures to, and select the DynamicDataFutures.csproj file this will add the Futures project and none of the samples.

Adding an Existing Project to the file based website

Figure 1 – Adding an Existing Project to the file based website

2. Adding a Reference to Dynamic Data Futures and AjaxToolkit

Right mouse click the website root and click Add Reference…

Adding a reference to the website

Figure 2  - Adding a reference to the website

When the dialogue box pops up choose the Projects Tab and select the DynamicDataFutures project and click OK.

Now you will need to do the same for the AjaxToolkit, only this time you need to click the Browse tab and navigate to the folder where you have downloaded and extracted the AjaxToolkit to, select the DLL in the sample website’s bin folder and click OK.

Selecting the AjaxToolkit DLL

Figure 3 – Selecting the AjaxToolkit DLL

3. Adding the new Filter User Controls to the website

Right mouse click the DynamicData folder in your Dynamic Data Website and select New Folder, name the folder Filters.

Adding the Filters Folder

Figure 4 – Adding the Filters Folder

New right mouse click the newly created folder and select Add Existing Items…

Add Existing Items

Figure 5 - Add Existing Items

Browse to the folder containing DynamicDataFutures project and then navigate to the DynamicData\Filters folder in the samples website

Selecting the Filter files (excluding the designer files)

Figure 6 – Selecting the Filter files (excluding the designer files)

Now select all except the .designer.cs files and click Add.

Now we will need to copy the following files:

Copy the following to the App_Code folder.

  • AutocompleteFilter.asmx.cs
  • CascadeAttribute.cs

Copy the following to the root of the website.

  • AutocompleteFilter.asmx
  • AutocompleteStyle.css
  • AjaxToolkitFixes.css

4. Converting Web Application files to work in a file based Website

We are going to use some advanced search and replace (not just because I like showing off) to demonstrate these features in Visual Studio 2008:

  • Search and replace using simple regular expression.
  • Replace by file extension.
  • Replace in files in a particular folder.

Things that need to be changes:

  • Namespaces needs to be removed from the Inherits property of the control tag in the ascx files.
  • CodeBehind changes to CodeFile
  • Namespace surrounding the user control class in the ascx.cs files.

To Find and Replace in only the DynamicData\Filters folder:

Find and Replace if Files in a specific folder

Figure 7 – Find and Replace if Files in a specific folder

Using Figure 6 use the following steps with each of the Search Patterns.

  1. Enter the text to search for.
  2. If you need to do it in all the sub-folders.
  3. Click to set the folder to find file in (see Figure 7).
  4. Note the Match case option is not checked (when searching for CodeBehind you may miss codebehind or Codebehind or codeBehind with it checked).
  5. Check when using Regular Expressions or Wild Cards.
  6. The files extension or pattern to match.
  7. Click to start the Find and Replace.

Setting the Search Folders

Figure 8 – Setting the Search Folders

  1. Click the up folder button until you see some folders below then navigate to you website and the DynamicData folder.
  2. Click the add button to add the folder to the list of folders to search in (we are only interested in the Filters folder here).
  3. The folder is added to the Selected folders list.

Search Patterns:

start without the Regular expression checkbox unchecked.

  1. Find Inherits="DynamicDataFuturesSample. and Replace with Inherits="
  2. Find CodeBehind and Replace with CodeFile

Check the Regular expression checkbox for this.

  1. Find namespace DynamicDataFuturesSample\n\{\n Replace with "" nothing.
  2. Find namespace DynamicDataFuturesSample \{\n Replace with "" nothing (Note the space instead of the \n).
  3. Find \n\} and replace with nothing.
  4. Note: Note there is only ever one } preceded by a linefeed except if you have two classes in the same file, also if you repeat the search after doing a CTRL+K and CTRL-D to reformat the code, then you will again remove the last brace in the file.
  5. The hit CTRL+K and CTRL-D to reformat the code in each file before saving it.

And now manually edit the following three files removing namespace and changing NOT CodeBehind to CodeFile in AutocompleteFilter.asmx.

  1. AutocompleteFilter.asmx.cs
  2. AutocompleteFilter.asmx
  3. CascadeAttribute.cs

5. Making the Necessary Changes to allow Advanced Filter to Work

To make Dynamic Data Futures work with the website we will need to make the following changes to the List and ListDetails pages:

  • Add a Tag Mapping in the web.config.
  • Register the Dynamic Data Futures assembly and tag in the web.config.
  • Change each PageTemplates FilterRepeater a little.
  • Edit the Site.master to add a link to the AutocompleteStyle.css file ***UPDATED***
Note: The Tag mapping is a great idea and I didn’t know it was there until DynamicDataFutures added the ImprovedDynamicValidator.

So add the Tag Mapping to the pages collection in configuration->system.web->pages see Listing 1.

<configuration>
...
<system.web>
...
<
pages>
<controls>
...
</
controls>
<tagMapping>
...
</tagMapping>

Listing 1 – Where to add the Tag Mapping

Listing 2 shows the Tag Mapping to be added, as you can see the classes including full namespace are show in tagType and mappedTagType.

<add tagType="System.Web.DynamicData.FilterRepeater" 
     mappedTagType="Microsoft.Web.DynamicData.AdvancedFilterRepeater" />

Listing 2 – The Tag Mapping

This sorts out the FilterRepeater being replaced by the AdvancedFilterRepeater.

<add tagPrefix="asp" 
     namespace="Microsoft.Web.DynamicData" 
     assembly="Microsoft.Web.DynamicData"/>

Listing 3 – Register the Dynamic Data Futures assembly and tag

Listing 3 add a registration for the Dynamic Data Futures assembly and tag in the web.config.

<add namespace="AjaxControlToolkit" 
     assembly="AjaxControlToolkit" 
     tagPrefix="ajaxToolkit"/>

Listing 4 – Add Ajax Toolkit to the website

Note: You need to add the AjaxToolkit and Dynamic Data Futures assemblies and tags to the controls collection, the AjaxToolkit is need as some of the other Filters require it.

Next in the List.aspx and ListDetails.aspx PageTemplates you need to add the DelegatingFilter and remove the DynamicFilter and also remove the AssociatedControlID="DynamicFilter$DropDownList1" from the Label control above the DynamicFilter making the whole FilterRepeater (aliased AdvancedFilterRepeater via Tag Mapping) look like Listing 5.

<asp:FilterRepeater ID="FilterRepeater" runat="server">
    <ItemTemplate>
        <asp:Label runat="server" Text='<%# Eval("DisplayName") %>' />
        <asp:DelegatingFilter 
            runat="server" 
            ID="DynamicFilter" 
            OnSelectionChanged="OnFilterSelectedIndexChanged" />
    </ItemTemplate>
    <FooterTemplate>
        <br />
        <br />
    </FooterTemplate>
</asp:FilterRepeater>

Listing 5 – The finished FilterRepeater.

Note: It would have been nice to map the DynamicFilter to DelegatingFilter also but the parameters are not the same between controls, I suppose you could always rename them in the DynamicDataFutures source and then map it. But then when a new version DynamicDataFutures is released you would need to remember to rename the properties again.
The DynamicFilter has OnSelectedIndexChanged and the DelegatingFilter has OnSelectionChanged, if they were the same you could also use the tag mapping.

Add the following line to the Site.master head tag

<head runat="server">
    <title>Dynamic Data Site</title>
    <link href="~/Site.css" rel="stylesheet" type="text/css" />
    <link href="AutocompleteStyle.css" rel="stylesheet" type="text/css" />
<link href="AjaxToolkitFixes.css" rel="stylesheet" type="text/css" />
</head>

Listing 6  - adding a link to the Site.master head

UPDATED: Forget to add a link to the AjaxToolkitFixes.css and AutocompleteStyle.css in the Site.master file.

6. Now to Test the AdvancedFilterRepeater and new Filters

To test this out we need to add a Metadata file to our website, see Listing 6.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using Microsoft.Web.DynamicData;

[MetadataType(typeof(Order_Detail_MD))]
public partial class Order_Detail
{
    public class Order_Detail_MD
    {
        // Use the Cascade.ascx filter control. 
        //
        // Specify that the list of items in the products filter should be
        // filtered by the Product.Category foreign key column.
        [Filter(FilterControl = "Cascade")]
        [Cascade("Category")]
        public object Product { get; set; }

        // Don't show the Order filter
        [Filter(Enabled = false)]
        public object Order { get; set; }
    }
}

Listing 7 – Order_Details Metadata

Run the website and go to Order_Details table and you should have the Cascade filter there and also the Orders filter should be missing also, see Figure 9.

Cascade filter in operation

Figure 9 – Cascade filter in operation

The next step is to add our own filter the AnyColumn filter which of course will filter any column.

32 comments:

Rommel C. Manalo said...

I follow every steps that you write there but it seems to have a problem.. I always get this error.

The filter control 'DynamicFilter' does not support this operation because it is associated with an unsupported column 'Name'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The filter control 'DynamicFilter' does not support this operation because it is associated with an unsupported column 'Name'.

Line 34: if (!Page.IsPostBack)
Line 35: {
Line 36: PopulateListControl(DropDownList1);
Line 37:
Line 38: // Set the initial value if there is one


[InvalidOperationException: The filter control 'DynamicFilter' does not support this operation because it is associated with an unsupported column 'Name'.]
System.Web.DynamicData.DefaultPropertyFilterDelegate.PopulateListControl(ListControl listControl) +141
System.Web.DynamicData.FilterUserControlBase.PopulateListControl(ListControl listControl) +25
DynamicData.FilterUserControl.Page_Init(Object sender, EventArgs e) in C:\SIS\OtherUI\MVC\SIS_MVC\SIS_MVC\DynamicData\Content\FilterUserControl.ascx.cs:36
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
System.Web.UI.Control.OnInit(EventArgs e) +99
System.Web.UI.UserControl.OnInit(EventArgs e) +77
System.Web.UI.Control.InitRecursive(Control namingContainer) +333
System.Web.UI.Control.InitRecursive(Control namingContainer) +210
System.Web.UI.Control.AddedControl(Control control, Int32 index) +198
System.Web.UI.ControlCollection.Add(Control child) +80
System.Web.UI.WebControls.Repeater.CreateItem(Int32 itemIndex, ListItemType itemType, Boolean dataBind, Object dataItem) +106
System.Web.UI.WebControls.Repeater.CreateControlHierarchy(Boolean useDataSource) +443
System.Web.UI.WebControls.Repeater.OnDataBinding(EventArgs e) +51
System.Web.UI.WebControls.Repeater.DataBind() +75
System.Web.DynamicData.FilterRepeater.DataBind() +22
System.Web.DynamicData.FilterRepeater.Page_InitComplete(Object sender, EventArgs e) +37
System.EventHandler.Invoke(Object sender, EventArgs e) +0
System.Web.UI.Page.OnInitComplete(EventArgs e) +8694646
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +467

Anonymous said...

I'm getting an error of the form Error 15 Could not load type 'TableList'. C:\WebSites\FordVehicleTracker\TableList.aspx

Is there an additional instruction missing from your previous posting?

Stephen J. Naughton said...

Hi regarding you error "Error 15 Could not load type 'TableList'. C:\WebSites\FordVehicleTracker\TableList.aspx" without seeing your code I cant be sure whats missing.
But as far as this article is conserned I whent throught the steps again just thee other day following the article to the letter and everything worked OK for me (Note that I wrote the article on Wednesday, 3 September 2008 almost three weeks ago). You can always e-mail at steve@notaclue.net and I'll see what I can do :D
Steve

Pablo Peralta said...

Thanks, useful post.
Please also note that for filtering, the ASMX uses the DisplayName property from the table.
Do not why, but I had to change it to make it the same as the column that I wanted to filter by.
For instance:

[MetadataType(typeof(Users_Md))]
public partial class Users
{
[DisplayColumn("UserId")]
public class Users_Md
{
....
}

satish said...

HI Steve,
Thanks for the post.

Is there any way to search when we click on submit button instead of autopost back for textbox, dropdown , radio button ?

i want to search ,when search button is clicked after selecting all search criteria's

Thanks in Advance,
Satish

Stephen J. Naughton said...

Hi Satish, the only option at the mement is "Dynamic Data Filtering" on codeplex by Josh Heyes but it only work with Linq to SQL not EF as yet, but he does have plans to add support for EF soon. I'm supposed to be doing some articles on it but not had the time as I'm not doing soome freelance work.

Steve :D

satish said...

Thanks Steve,
For reply.
I tried to use it , but however i got the below exception when i tried to run "Dynamic Data Filtering" on codeplex by Josh Heyes

Now i am struck , unable to use either entity or link 2 sql.

pls help me ..

Server Error in '/' Application.
Could not load file or assembly 'Microsoft.VisualStudio.Web.Blinq' or one of its dependencies. Strong name signature could not be verified. The assembly may have been tampered with, or it was delay signed but not fully signed with the correct private key. (Exception from HRESULT: 0x80131045)

Thanks,
Satish

exception is:

Stephen J. Naughton said...

Hi Satish, was that error on the source code project or when you tried to use the dll in your code?

e-mail mae direct rather than keep posting to steve@notaclue.net

Steve :D

Daniel said...

Hi

Is all this necessary?

Cant you just provide link to DDFutures prepared/enabled project?

Thanks
Daniel

Stephen J. Naughton said...

Hi Daniel, I suppose that depends on whether you wan't to know how or not?
Steve :D

Daniel said...

:) well its good to see how it works in detail, anyway prepared project can be downloaded at end of Part 3.

Stephen J. Naughton said...

Hi Dizzy, I glad you are finding the post useful.

Steve :D

Anonymous said...

I know you can implement .NET Membership roles and restrict access to the Tables and Actions on those tables per user role. Is there a way to persist the user information along with the action, for example if i INSERT a record, i would like to track the username associated with that INSERT. Much appreciated.

Stephen J. Naughton said...

See these articles:
http://csharpbits.notaclue.net/2008/05/dynamicdata-automatic-column-update.html
And
http://csharpbits.notaclue.net/2008/06/dynamicdata-limit-data-displayed-by.html

Hope this helps
Steve :D

Anonymous said...

Im trying to do a filter on a foreign key ,Im using Linq currently to connect to a SQL datastore.
The Ajax Drop down works great with the local attributes , but with foreign keys , It doesnt return anything and since it cannot return anything ,I cannot do a Search on it, Could you please help me out with the issue ,
Thanks

Stephen J. Naughton said...

Hi Jack, I'm not sure what you mean do you want to e-mail me direct.

Steve

Anonymous said...

Hello,
I'm looking for a DateTime filter than I can use to filter my data using a date range (i.e. from 2009/01/01 to 2009/05/01).
How can I do it creating a new filter repeater?

Thank you

Stephen J. Naughton said...

Hi there, you can't do this with the futures project you will need to look at Preview 4
which has a range sample filter for int but this could be adapted.

Steve :D

Fabio G. said...

Hello,
thank you for the reply, today I tried to add the advanced filter repeater to my project without success (I always had some component defined two times in the GAC), I was exactly doing what you suggested following your guide.
Now I'm trying again, if I'll have some problem more I'll write it here...bye

Stephen J. Naughton said...

Try in a new project with just a simple setup based on one of the sample project templates supplied with Preview 4.

Steve :D

Fabio G. said...

Ok, I'm started from a new Sample project (LinqToSql) and all worked fine.
The only problem is that the project provided by DDPreview was a ASPNET Web Application Project, while I wanted to use a Web site. So I copied all dynamic data folder and DLL from the Template project to my website, and all was OK.
Now I have Foreign key filters automatically added into Filter Repeater on the List page.

But now I would like to add the more complex filters, like Autocompletion or Range to my project, but I don't know how.
In fact if I simply copy the FieldTemplate to my FieldTemplate folder, and try to use it loading by UIHint attribute, it give me an error.
If I try to use a sintax like this over the column name:
[Filter(FilterControl = "Range")]
it doesn't work (the wordkey Filter is not recognized).

So how can I now use the other filters provided by the DDPreview4?

Stephen J. Naughton said...

Hi Fabio, if does not look like you are using the preview as the preview uses [FilterUIHint("Range")] not filter it looks to me like you have mix of DD Futures and Preview.

Steve :D

Pedro6 said...

Why is your sample file based ASP.NET. Can it not be done with a Namespace and an ASP.NET project?

Anonymous said...

Hi Steve
Could you tell me, how to change the folder of filter controls?
I have move dynamicdata project to a subproject. Page- and FieldTemplate are working fine, but FilterUserControl tries to look for filter elements on root page?! Any ideas?

Thanks Sebastian

Stephen J. Naughton said...

Hi Sebastian, you will need to look in the DelegatinFilter.cs file for this code:
public string FilterFolderVirtualPath
{
get
{
return "~/DynamicData/Filters/";
}
}
and change it, it should get the base folder from:

MetaModel.Default.DynamicDataFolderVirtualPath

Hope this helps

Eric Matsuno said...

I followed all of the steps using the ListDetails.aspx template. Any attempt at a post back from the dropdown lists gets me an an error that I'm not connected to the internet. In fact, there is no post back to the server. the error happens only on the client.

When I follow the steps for List.aspx, everything works fine.... What's different about listDetail.aspx that is causing this

Stephen J. Naughton said...

Hi Eric, could you try setting EnablePartialRendering="true" to false in the ScriptManger on the Site.Master this may be masking the error.

Regards
Steve

Eric said...

Thanks Steve, I've tried that. Funny thing, is that it does not post back at all. I put breakpoints all over the project (server side) and nothing gets hit with either EnablePartialRendering="true" nor EnablePartialRendering="false"

Stephen J. Naughton said...

Not sure what is going on there, it's a very old sample :( I will try to get some time to look at it, but there is not much motivation now VS2010 RC is here.

Steve

Eric said...

Right. Can't migrate up to 2010 here in my organisation. Just got up to 2008! If by chance you have a moment. The experiment should take someone of your knowledge about 2 minutes: Alter the ListDetail.aspx to coincide with your code changes and reroute the request to the listdetail.aspx page.


I'm otherwise at wits end.

Thanks!

Ashi S Rags said...

I get the error Cannot create AutocompleteFilterService. Error in file AutocompleteFilter.asmx.

Stephen J. Naughton said...

Sorry it just sound like an issue with your file, are you trying to run this sample with DD4 by any chance?

Steve