<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;Dk4MSH84cCp7ImA9WhFSEU4.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979</id><updated>2013-06-13T15:49:49.138+01:00</updated><category term="List.aspx" /><category term="white-space: nowrap" /><category term="Custom Filter" /><category term="ListActionPath" /><category term="Y/N Field" /><category term="Database Based Permissions" /><category term="Default Sort Column" /><category term="ItemTemplate" /><category term="Regular Expressions" /><category term="Linq join" /><category term="Model" /><category term="DetailsView" /><category term="France" /><category term="DomainDataSource" /><category term="Web Application Project" /><category term="Searching" /><category term="Roles" /><category term="Conversion" /><category term="Job" /><category term="Live Writer" /><category term="LayoutTemplate" /><category term="DynamicField" /><category term="FileImage_Edit" /><category term="css" /><category term="FromView" /><category term="Conditional" /><category term="IQueryable" /><category term="Session variables" /><category term="Grouping" /><category term="SP1 Release" /><category term="JuiceUI" /><category term="Extension Methods" /><category term="Linq to SQL" /><category term="ReadOnlyAttribute" /><category term="ITemplate" /><category term="PDF to Image" /><category term="Required Field" /><category term="History" /><category term="DynamicData" /><category term="Preview 4" /><category term="Events" /><category term="File Upload" /><category term="Preview" /><category term="DynamicControl" /><category term="Dynamic Data Futures" /><category term="Hierarchical" /><category term="GridView Pager Size" /><category term="DataContext" /><category term="DynamicHyperLink" /><category term="LightSwitch" /><category term="Watermark" /><category term="TypeDescriptor" /><category term="jQuery" /><category term="I'm Back" /><category term="Rollover" /><category term="Compound Properties" /><category term="Row Highlighting" /><category term="ITemplate class" /><category term="Tabs" /><category term="GridView" /><category term="ObjectContext" /><category term="MVP" /><category term="CustomTypeDescriptor" /><category term="AJAX HTML Editor" /><category term="UIHint" /><category term="Vacation" /><category term="Blogger" /><category term="Templates" /><category term="InsertItemTemplate" /><category term="CTP4" /><category term="Hide Column" /><category term="Telerik" /><category term="NuGet" /><category term="Agile Principals" /><category term="FieldTemplate" /><category term="Custom Field Templates" /><category term="Expression Trees" /><category term="Tooling" /><category term="User Filter" /><category term="ASP.Net" /><category term="Looking for a Job" /><category term="Entity Framework" /><category term="Default Values" /><category term="Cascading FieldTemplates" /><category term="PDF To Text" /><category term="DynamicDataFutures" /><category term="OnSavingChanges" /><category term="Sorting" /><category term="Camp-Hôtel Pachacaïd" /><category term="Button" /><category term="Cascading Controls" /><category term="Business Logic/Validation" /><category term="MataTable" /><category term="Auditing" /><category term="Pascal to Human" /><category term="DynamicDataExtensions" /><category term="Permissions" /><category term="Syntax Highlighter" /><category term="ABCpdf .Net 7" /><category term="CTP" /><category term="I18N" /><category term="ForeignKey_Edit" /><category term="Security" /><category term="IAutoFieldGenerator" /><category term="Visual Studio 2010" /><category term="Build-5/23a" /><category term="SQL Server Views" /><category term="RegisterControl" /><category term="Digsby" /><category term="ToArray" /><category term="VB Code" /><category term="Dynamic Data Filtering" /><category term="Advertisement" /><category term="Custom Page Template" /><category term="FilterUserControl" /><category term="Command Column" /><category term="Limit FilterRepeater" /><category term="Image Handler" /><category term="Links" /><category term="Routing Constraint" /><category term="Routing" /><category term="TypeDescriptionProvider" /><category term="Autocomplete" /><category term="ListView" /><category term="Read-Only" /><category term="Code First" /><category term="OnDataBind" /><category term="GetColumnValue" /><category term=".Net 4.0" /><category term="Metadata" /><category term="Linq to Entities" /><category term="Validation Groups" /><category term="FilterTemplates" /><category term="DisplayColumnAttribute" /><category term="Holiday" /><category term="DomainService" /><category term="ASP.Net 4.0" /><category term="Cascading Filters" /><category term="Filtering" /><category term="Web User Controls" /><category term="Visual Studio 2012" /><category term="CustomValidator" /><category term="EditItemTemplate" /><category term="Wijmo Open" /><category term="Custom Meta Classes" /><category term="Generics" /><category term="File Based Website" /><category term="Custom Pages" /><category term="OpenAccess ORM" /><category term="Add Preview to Web Site" /><category term="Render" /><category term="Multi Column Search" /><category term="Inferred Keys" /><category term="ForeignKey Columns" /><category term="Attributes" /><category term="Visual Studio 2008 SP1 beta" /><category term="AJAX History" /><category term="Children" /><category term="Linq" /><category term="LESS" /><category term="External Class Library" /><category term="Validation" /><category term="Patterns and Practices in C#" /><category term="Multiple Models" /><category term="Filters" /><category term="Partial Methods" /><category term="Hyperlink" /><category term="Dynamic Data" /><category term="Custom Attribute" /><category term="GetActionPath" /><category term="Attribute Based Permission" /><category term="MetaColumn" /><category term="Password" /><category term="Entity Templates" /><category term="OrderBy" /><category term="Silverlight" /><category term="AJAX Control Toolkit" /><category term="Books" /><title>C# Bits</title><subtitle type="html">ASP.Net, Dynamic Data and c# stuff: Focused on what new and cool, code tutorials and useful tricks and tips on getting the most out of ASP.Net. All in C#</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://csharpbits.notaclue.net/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>153</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/notaclue/IYRx" /><feedburner:info uri="notaclue/iyrx" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CkMDRHg6eyp7ImA9WhNbE0s.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-6214335039470172967</id><published>2013-01-16T18:15:00.001Z</published><updated>2013-01-16T18:21:15.613Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-16T18:21:15.613Z</app:edited><title>Adding Multi Column Sort to Dynamic Data List Page</title><content type="html">&lt;p&gt;Well this is the first post of 2013 and has been brewing for a while, what we want is to be able to set the initial sort of the GridView on the List page or ListDetails page. &lt;strong&gt;Listing 1&lt;/strong&gt; shows what we want to achieve.&lt;/p&gt; &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="OrderDate sorted Descending and ShipName sorted Ascending" border="0" alt="OrderDate sorted Descending and ShipName sorted Ascending" src="http://lh6.ggpht.com/-qyIWrnRSqQc/UPbuPzJA-TI/AAAAAAAAClM/RJF-Y6uZAZU/Sorted%25255B7%25255D.png?imgmax=800" width="608" height="478"&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Figure 1 – OrderDate sorted Descending and ShipName sorted Ascending&lt;/strong&gt;&lt;/p&gt; &lt;h3&gt;The Multi Column Sort Attribute&lt;/h3&gt; &lt;p&gt;&lt;strong&gt;Figure 2&lt;/strong&gt; shows the first version of the attribute, I was using magic strings. But in &lt;strong&gt;Figure 3&lt;/strong&gt; we have an enum from System.Web.UI.WebControls to help us out (I’m a bad speller and I tend to type too quickly) so I think that is better.&lt;/p&gt; &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Early Version Of Metadata" border="0" alt="Early Version Of Metadata" src="http://lh4.ggpht.com/-hrSzrIASpFk/UPbuQ5FawsI/AAAAAAAAClQ/oudAmKKseyY/EarlyVersionOfMetadata%25255B5%25255D.png?imgmax=800" width="482" height="97"&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Figure 2 – Early Version Of Metadata&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Example Metadata" border="0" alt="Example Metadata" src="http://lh4.ggpht.com/-UIYV1eXen9w/UPbuRjqjT8I/AAAAAAAAClc/hifHbOaSMrk/ExampleMetadata%25255B6%25255D.png?imgmax=800" width="699" height="100"&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Figure 3 – Example Metadata&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Listing 1&lt;/strong&gt; shows the MultiColumnSortAttribute I am using the params construct to get a list of values from the attribute and I am using the BuildColumnParametersDictionary method to convert the object array to a dictionary with a string key the column name and a value of the SortDirection.&lt;/p&gt;&lt;pre class="brush: csharp; ruler: true;"&gt;[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]&lt;br&gt;public class MultiColumnSortAttribute : Attribute&lt;br&gt;{&lt;br&gt;    private IDictionary&amp;lt;String, SortDirection&amp;gt; _columns;&lt;br&gt;&lt;br&gt;    public IDictionary&amp;lt;String, SortDirection&amp;gt; Columns&lt;br&gt;    {&lt;br&gt;        get { return this._columns; }&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    public MultiColumnSortAttribute(params object[] columnParameters)&lt;br&gt;    {&lt;br&gt;        _columns = BuildColumnParametersDictionary(columnParameters);&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    private IDictionary&amp;lt;String, SortDirection&amp;gt; BuildColumnParametersDictionary(object[] objArray)&lt;br&gt;    {&lt;br&gt;        var dictionary = new Dictionary&amp;lt;String, SortDirection&amp;gt;();&lt;br&gt;        if ((objArray != null) &amp;amp;&amp;amp; (objArray.Length != 0))&lt;br&gt;        {&lt;br&gt;            if ((objArray.Length % 2) != 0)&lt;br&gt;                throw new InvalidOperationException(&lt;br&gt;                    String.Format("Need even number of control parameters.", &lt;br&gt;                    new object[0]));&lt;br&gt;&lt;br&gt;            for (int i = 0; i &amp;lt; objArray.Length; i += 2)&lt;br&gt;            {&lt;br&gt;                if (objArray[i] is String &amp;amp;&amp;amp; objArray[i + 1] is SortDirection)&lt;br&gt;                {&lt;br&gt;                    if (objArray[i] == null)&lt;br&gt;                        throw new InvalidOperationException(&lt;br&gt;                            String.Format("Column name [{0}] is null.", i));&lt;br&gt;&lt;br&gt;                    // get column name from array&lt;br&gt;                    String columnName = objArray[i] as String;&lt;br&gt;                    if (columnName == null)&lt;br&gt;                        throw new InvalidOperationException(&lt;br&gt;                            String.Format("Column name '{0}' is not a String.", &lt;br&gt;                            objArray[i].ToString()));&lt;br&gt;&lt;br&gt;                    // check for duplicate column names&lt;br&gt;                    if (dictionary.ContainsKey(columnName))&lt;br&gt;                        throw new InvalidOperationException(&lt;br&gt;                            String.Format("Column name '{0}' occurs more than once.", &lt;br&gt;                            columnName));&lt;br&gt;&lt;br&gt;                    // get sort direction from array&lt;br&gt;                    if (objArray[i + 1] == null)&lt;br&gt;                        throw new InvalidOperationException(&lt;br&gt;                            String.Format("Sort direction '{0}' is not a of type SortDirection.", &lt;br&gt;                            objArray[i].ToString()));&lt;br&gt;&lt;br&gt;                    SortDirection sortDirection = (SortDirection)objArray[i + 1];&lt;br&gt;                    dictionary[columnName] = sortDirection;&lt;br&gt;                }&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;        return dictionary;&lt;br&gt;    }&lt;br&gt;}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 1 - MultiColumnSortAttribute&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;An Extension Method to Add Multi Column Sort to the Page&lt;/h3&gt;
&lt;p&gt;This extension method in &lt;strong&gt;Listing 2&lt;/strong&gt; is a little more complicated than it would need to be to handle just the Multi Column Sort, it also handles the DisplayColumn attribute to, this way we cover all bases.&amp;nbsp; &lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;The GetAttribute&amp;lt;T&amp;gt;() extension method is covered here &lt;a href="http://csharpbits.notaclue.net/2009/01/writing-attribute-and-extension-methods.html" target="_blank"&gt;Writing Attributes and Extension Methods for Dynamic Data&lt;/a&gt;&lt;/div&gt;&lt;pre class="brush: csharp; ruler: true;"&gt;/// &amp;lt;summary&amp;gt;&lt;br&gt;/// Sets the initial sort order.&lt;br&gt;/// &amp;lt;/summary&amp;gt;&lt;br&gt;/// &amp;lt;param name="queryExtender"&amp;gt;The query extender.&amp;lt;/param&amp;gt;&lt;br&gt;/// &amp;lt;param name="table"&amp;gt;The table.&amp;lt;/param&amp;gt;&lt;br&gt;public static void SetInitialSortOrder(this QueryExtender queryExtender, MetaTable table)&lt;br&gt;{&lt;br&gt;    var multiColumnSort = table.GetAttribute&amp;lt;MultiColumnSortAttribute&amp;gt;();&lt;br&gt;    if (multiColumnSort != null)&lt;br&gt;    {&lt;br&gt;        var firstEntry = multiColumnSort.Columns.Keys.First();&lt;br&gt;        var order = new OrderByExpression()&lt;br&gt;        {&lt;br&gt;            DataField = firstEntry,&lt;br&gt;            Direction = multiColumnSort.Columns[firstEntry],&lt;br&gt;        };&lt;br&gt;&lt;br&gt;        foreach (var item in multiColumnSort.Columns)&lt;br&gt;        {&lt;br&gt;            if (item.Key != firstEntry)&lt;br&gt;            {&lt;br&gt;                order.ThenByExpressions.Add(new ThenBy()&lt;br&gt;                {&lt;br&gt;                    DataField = item.Key,&lt;br&gt;                    Direction = item.Value&lt;br&gt;                });&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;        queryExtender.Expressions.Add(order);&lt;br&gt;    }&lt;br&gt;    else if (table.SortColumn != null)&lt;br&gt;    {&lt;br&gt;        var order = new OrderByExpression()&lt;br&gt;        {&lt;br&gt;            DataField = table.SortColumn.Name,&lt;br&gt;            Direction = table.SortDescending ? SortDirection.Descending : SortDirection.Ascending,&lt;br&gt;        };&lt;br&gt;        queryExtender.Expressions.Add(order);&lt;br&gt;    }&lt;br&gt;}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 2 – SetInitialSortOrder Extension Method&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Using in the List Page Template&lt;/h3&gt;
&lt;p&gt;All we need to do in the List and ListDetails page templates is to add one line to the Page_Init method.&lt;/p&gt;&lt;pre class="brush: csharp; ruler: true;"&gt;protected void Page_Init(object sender, EventArgs e)&lt;br&gt;{&lt;br&gt;    table = DynamicDataRouteHandler.GetRequestMetaTable(Context);&lt;br&gt;    GridView1.SetMetaTable(table, table.GetColumnValuesFromRoute(Context));&lt;br&gt;    GridDataSource.EntityTypeFilter = table.EntityType.Name;&lt;br&gt;&lt;br&gt;    // set initial sort order&lt;br&gt;    GridQueryExtender.SetInitialSortOrder(table);&lt;br&gt;}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 3 – adding the extension method to the Page Template&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Download&lt;/h3&gt;&lt;iframe height="120" src="https://skydrive.live.com/embed?cid=96845E7B0FAC1EED&amp;amp;resid=96845E7B0FAC1EED%21893&amp;amp;authkey=AMVv_Ebo2DeYzzs" frameborder="0" width="98" scrolling="no"&gt;&lt;/iframe&gt;
&lt;p&gt;You may need to look through the list of files on my sky drive to find the one you want, it’s called &lt;strong&gt;MultiColumnSort.zip&lt;/strong&gt;&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/6f3q0DRga6Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/6214335039470172967/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=6214335039470172967&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6214335039470172967?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6214335039470172967?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/6f3q0DRga6Y/adding-multi-column-sort-to-dynamic.html" title="Adding Multi Column Sort to Dynamic Data List Page" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/-qyIWrnRSqQc/UPbuPzJA-TI/AAAAAAAAClM/RJF-Y6uZAZU/s72-c/Sorted%25255B7%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2013/01/adding-multi-column-sort-to-dynamic.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQCQX8_eip7ImA9WhNUGEs.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-7678066147791049354</id><published>2012-12-20T15:42:00.001Z</published><updated>2013-01-11T00:32:40.142Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-11T00:32:40.142Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Button" /><category scheme="http://www.blogger.com/atom/ns#" term="NuGet" /><category scheme="http://www.blogger.com/atom/ns#" term="DynamicData" /><category scheme="http://www.blogger.com/atom/ns#" term="Hyperlink" /><category scheme="http://www.blogger.com/atom/ns#" term="LESS" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><category scheme="http://www.blogger.com/atom/ns#" term="css" /><title>Turning you ASP.Net Hyperlinks into images buttons using CSS and jQuery</title><content type="html">&lt;p&gt;First of all I’m no big &lt;a href="http://jquery.com/" target="_blank"&gt;jQuery&lt;/a&gt; or CSS geek I know a little and I search the net &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/-AgWDxBCT8v0/UNMx0k7dmnI/AAAAAAAACi4/NERhqUvRn1c/wlEmoticon-smile2.png?imgmax=800"&gt;&lt;/p&gt; &lt;p&gt;I was building a site for a client who wanted Image buttons not text links and you should know me if you have read past posts I believe Dynamic Data is about changing as little as possible in the pages I like to do it all if possible using the Metadata, so I thought is there a way of doing this using pure CSS, there is sort of but you are still left with the text of the hyperlink, that is where jQuery came in, and then I thought I need to add a CSS class to each button and again jQuery came to my aid. so here we go.&lt;/p&gt; &lt;p&gt; &lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;I am using the latest &lt;a href="http://visualstudiogallery.msdn.microsoft.com/07d54d12-7133-4e15-becb-6f451ea3bea6" target="_blank"&gt;Web Essentials&lt;/a&gt; by &lt;a title="Mads Kristensen" href="http://madskristensen.net/" target="_blank"&gt;Mads Kristensen&lt;/a&gt; and using LESS for my style sheets, you are really missing out if you have VS2012 and are not using this experimental add-in for VS2012. &lt;/div&gt; &lt;p&gt; &lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;If you don't have VS2012 the you can use &lt;a href="http://www.mindscapehq.com" target="_blank"&gt;Mindscape’s&lt;/a&gt; &lt;a href="http://visualstudiogallery.msdn.microsoft.com/2b96d16a-c986-4501-8f97-8008f9db141a?SRC=VSIDE" target="_blank"&gt;Web Workbench&lt;/a&gt; which offers &lt;a href="http://sass-lang.com/" target="_blank"&gt;SASS&lt;/a&gt;, &lt;a href="http://lesscss.org/" target="_blank"&gt;LESS&lt;/a&gt; and &lt;a href="http://coffeescript.org/" target="_blank"&gt;CoffeeScript&lt;/a&gt;&lt;/div&gt; &lt;p&gt;So the first job is to somehow automatically add the CSS class to each of the buttons that we want to swap to image button. &lt;/p&gt;&lt;pre class="brush: js; ruler: true;"&gt;function NAC_ReplaceHyperLinkWithImageButton() {&lt;br&gt;    // array of button commands/names to affect&lt;br&gt;    var toMatch = ["Details", "Edit", "Delete", "Update", "Cancel", "Insert", "Select", "New"];&lt;br&gt;    // commands/names to replace&lt;br&gt;    var toReplace = { "New": "Insert" };&lt;br&gt;    $(document).ready(function () {&lt;br&gt;        $("TABLE.DDDetailsTable a, TABLE.DDGridView a")&lt;br&gt;            .each(function () {&lt;br&gt;                // get the inner text&lt;br&gt;                var innerText = $(this).text();&lt;br&gt;                if ($.inArray(innerText, toMatch) &amp;gt; -1) {&lt;br&gt;&lt;br&gt;                    // do replacement of commands to Replace&lt;br&gt;                    var found = toReplace[innerText];&lt;br&gt;                    // check there is a match in the lookup table&lt;br&gt;                    if (typeof found !== "undefined")&lt;br&gt;                        innerText = found;&lt;br&gt;&lt;br&gt;                    // get the embedded text&lt;br&gt;                    $(this).addClass(innerText);&lt;br&gt;&lt;br&gt;                    // add a tooltip&lt;br&gt;                    $(this).attr('Title', innerText);&lt;br&gt;&lt;br&gt;                    // remove the hyperlinks text&lt;br&gt;                    $(this).text('');&lt;br&gt;                }&lt;br&gt;            });&lt;br&gt;    });&lt;br&gt;}&lt;br&gt;// run script&lt;br&gt;NAC_ReplaceHyperLinkWithImageButton();&lt;br&gt;// bind script to AJAX bits&lt;br&gt;Sys.Application.add_load(NAC_ReplaceHyperLinkWithImageButton);
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 1 – jQuery for the swap out&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So first of all we have an array this contains ALL the button names (the display text) that we want to affect, next we hook into the jQuery Read event then we are selecting command buttons List, Details, Edit and ListDetails pages using these two selectors:&lt;/p&gt;&lt;pre&gt;"TABLE.DDDetailsTable a, TABLE.DDGridView a"
&lt;/pre&gt;
&lt;p&gt;after that I am using the jQuery &lt;a href="http://api.jquery.com/jQuery.inArray/" target="_blank"&gt;inArray&lt;/a&gt; function to check if the buttons text is one we want to affect. Then having gotten the innerText form the hyperlink we add the CSS class, then finally we remove the text so only the icon will show.&lt;/p&gt;
&lt;p&gt;jQuery is so cool mixed with CSS.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-rn0owmUL-jc/UNMx1xwr1zI/AAAAAAAACjA/R90fnAtzzBY/s1600-h/ReplaceHyperlinkWithIcons%25255B6%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="ReplaceHyperlinkWithIcons" border="0" alt="ReplaceHyperlinkWithIcons" src="http://lh4.ggpht.com/-AP0irAOhaNk/UNMx219xQKI/AAAAAAAACjI/t0a943p-ZhM/ReplaceHyperlinkWithIcons_thumb%25255B4%25255D.png?imgmax=800" width="577" height="360"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 1- hyperlinks replace with buttons&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now people say LESS is more and in this case it is.&lt;/p&gt;&lt;pre class="brush: css; ruler: true;"&gt;table.DDGridView a.Cancel,
table.DDDetailsTable a.Cancel
{
    width: 20px;
    height: 20px;
    display: inline-block;
    background-repeat: no-repeat;
    background-position: center center;
    background-image: url('../images/Cancel.png');
}

    table.DDGridView a.Cancel:hover,
    table.DDDetailsTable a.Cancel:hover
    {
        background-image: url('../images/Cancel-h.png');
    }

        table.DDGridView a.Cancel:hover:active,
        table.DDDetailsTable a.Cancel:hover:active
        {
            background-image: url('../images/Cancel-a.png');
        }

    table.DDGridView a.Cancel.aspNetDisabled,
    table.DDDetailsTable a.Cancel.aspNetDisabled,
    table.DDGridView a.Cancel.aspNetDisabled:hover,
    table.DDDetailsTable a.Cancel.aspNetDisabled:hover,
    table.DDGridView a.Cancel.aspNetDisabled:active,
    table.DDDetailsTable a.Cancel.aspNetDisabled:active
    {
        background-image: url('../images/Cancel-d.png');
    }
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 2 – the CSS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;above in &lt;strong&gt;Listing 2&lt;/strong&gt; is the CSS for the Edit button as you can see we cover hyperlinks with a CSS class of “Edit” and we have three states normal hover and active that is when we click. Now for the LESS&lt;/p&gt;&lt;pre class="brush: css; ruler: true;"&gt;/* ==== button mixin ==== */&lt;br&gt;.Button (@Name)&lt;br&gt;{&lt;br&gt;    a.@{Name}&lt;br&gt;    {&lt;br&gt;        width: 20px;&lt;br&gt;        height: 20px;&lt;br&gt;        display: inline-block;&lt;br&gt;        background-repeat: no-repeat;&lt;br&gt;        background-position: center center;&lt;br&gt;&lt;br&gt;        background-image: url('../images/@{Name}.png');&lt;br&gt;&lt;br&gt;        &amp;amp;:hover&lt;br&gt;        {&lt;br&gt;            background-image: url('../images/@{Name}-h.png');&lt;br&gt;&lt;br&gt;            &amp;amp;:active&lt;br&gt;            {&lt;br&gt;                background-image: url('../images/@{Name}-a.png');&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;        // link fix &lt;br&gt;        &amp;amp;.aspNetDisabled,&lt;br&gt;        &amp;amp;.aspNetDisabled:hover,&lt;br&gt;        &amp;amp;.aspNetDisabled:active&lt;br&gt;        {&lt;br&gt;            background-image: url('../images/@{Name}-d.png');&lt;br&gt;        }&lt;br&gt;        // link fix &lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;table.DDGridView,&lt;br&gt;table.DDDetailsTable&lt;br&gt;{&lt;br&gt;    .Button(Cancel);&lt;br&gt;    .Button(Delete);&lt;br&gt;    .Button(Details);&lt;br&gt;    .Button(Edit);&lt;br&gt;    .Button(Update);&lt;br&gt;    .Button(New);&lt;br&gt;    .Button(Select);&lt;br&gt;    .Button(Insert);&lt;br&gt;}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 3 – LESS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;Listing 3&lt;/strong&gt; we have a MIXIN called Button and we pass in the name of the button we want, no repeating the same code and if you need to add an extra button it’s easy.&lt;/p&gt;
&lt;p&gt;The only thing left is for me to add this to &lt;a href="http://nuget.org" target="_blank"&gt;NuGet&lt;/a&gt; as a simple to apply package and you are away.&lt;/p&gt;
&lt;p&gt;
&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #f0d0f0; margin: 4px; padding-left: 4px; padding-right: 4px; color: #800080; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Updated: &lt;/strong&gt;Package now available from &lt;a href="https://nuget.org" target="_blank"&gt;NuGet&lt;/a&gt; here &lt;a href="https://nuget.org/packages/ReplaceHyperlinkWithImageButton" target="_blank"&gt;Replace ASP.Net Hyperlink With Image Button&lt;/a&gt; You will need to add a reference in you master page to the CSS and the JavaScript files which will be added to the Style and Scripts folder respectively. &lt;/div&gt;
&lt;h3&gt;Adding the NuGet package to an existing Dynamic Data site&lt;/h3&gt;
&lt;p&gt;Right Click the “References” node of the Web Application Project&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-CJl0qLmdnE4/UNNWUNlW2VI/AAAAAAAACjY/AFIZn4pSCo0/s1600-h/Adding%252520NuGet%252520Package%25255B5%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Adding NuGet Package" border="0" alt="Adding NuGet Package" src="http://lh3.ggpht.com/-6rvFpBaAvGA/UNNWVQziPII/AAAAAAAACjg/K6HKSAZ21sY/Adding%252520NuGet%252520Package_thumb%25255B3%25255D.png?imgmax=800" width="336" height="224"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 1 – Adding NuGet Package to Project&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-A57iwLvlvpw/UNNWWn4fzAI/AAAAAAAACjo/GpOHaI2kkjY/s1600-h/NuGetPackageReplaceHyperlinkWithImageButton%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Find the &amp;ldquo;Replace Hyperlink With Image Button&amp;rdquo; NuGet Package" border="0" alt="Find the &amp;ldquo;Replace Hyperlink With Image Button&amp;rdquo; NuGet Package" src="http://lh3.ggpht.com/-7D5XRADvQaM/UNNWYV5ql2I/AAAAAAAACjw/zPVH4aSYQ10/NuGetPackageReplaceHyperlinkWithImageButton_thumb%25255B2%25255D.png?imgmax=800" width="929" height="310"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 2 – Find the “Replace Hyperlink With Image Button” NuGet Package&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh3.ggpht.com/-u29-pzr3ATs/UNNWZFsHt3I/AAAAAAAACj4/7y7cABqoMlM/s1600-h/AddingScriptToHead%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="AddingScriptToHead" border="0" alt="AddingScriptToHead" src="http://lh3.ggpht.com/-6aWrby8PCXg/UNNWacq-_aI/AAAAAAAACkA/PGUF0Y1G0hY/AddingScriptToHead_thumb%25255B2%25255D.png?imgmax=800" width="617" height="191"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 3 – Add the Style sheet and jQuery references to the head of the Master page&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;the highlighted sections, you will need to add a ~/ and ../ to the start od the CSS and Script links.&lt;/div&gt;
&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-fsndu1RaAw4/UNNWbc3xnoI/AAAAAAAACkI/2tEXwf4eUm8/s1600-h/AddScriptToEndOfMasterPage%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="AddScriptToEndOfMasterPage" border="0" alt="AddScriptToEndOfMasterPage" src="http://lh3.ggpht.com/-7vGrzmo1Bho/UNNWcV0KvII/AAAAAAAACkQ/iCBnzoxvs2Y/AddScriptToEndOfMasterPage_thumb%25255B2%25255D.png?imgmax=800" width="607" height="89"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 4 – Add a script tag just before the end of the BODY tag&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: you &lt;/strong&gt;can add your scripts and Style sheets your own way with bundling and minifying this is just an example. &lt;/div&gt;
&lt;p&gt;Happy coding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;V1.0.4&lt;/strong&gt; now on NuGet you disabled icons if a link’s Enabled property is set to “false”;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-WZB7kwxpZcc/UN2QoKDkAiI/AAAAAAAACkk/I0j5QdJ4NDI/s1600-h/ReplaceHyperlinkWithIconsDisabledIcons%25255B9%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="ReplaceHyperlinkWithDisabledIcons" border="0" alt="Replace Hyperlink With Disabled Icons" src="http://lh5.ggpht.com/-cGRSbuPvxfM/UN2Qo8cUpkI/AAAAAAAACko/to6QqQOVGxY/ReplaceHyperlinkWithIconsDisabledIcons_thumb%25255B5%25255D.png?imgmax=800" width="135" height="133"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hopefully no more changes now.&lt;/p&gt;
&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: red; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Warning another change: &lt;/strong&gt; v1.0.8 now has better icons and supports disabled buttons including removing the onclick event of the Delete button.&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/uUt4CLI8rAg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/7678066147791049354/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=7678066147791049354&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/7678066147791049354?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/7678066147791049354?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/uUt4CLI8rAg/turning-you-aspnet-hyperlinks-into.html" title="Turning you ASP.Net Hyperlinks into images buttons using CSS and jQuery" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-AgWDxBCT8v0/UNMx0k7dmnI/AAAAAAAACi4/NERhqUvRn1c/s72-c/wlEmoticon-smile2.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2012/12/turning-you-aspnet-hyperlinks-into.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IGRHo_fip7ImA9WhNVEEw.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-1644208332986111323</id><published>2012-12-14T12:01:00.001Z</published><updated>2012-12-20T14:58:45.446Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-20T14:58:45.446Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tooling" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio 2012" /><category scheme="http://www.blogger.com/atom/ns#" term="Web Application Project" /><title>ASP.NET and Web Tools 2012.2 (Release Candidate)</title><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Scott Hanselman announced &lt;a title="ASP.NET and Web Tools 2012.2 (Release Candidate)" href="http://www.hanselman.com/blog/ASPNETAndWebTools20122ReleaseCandidate.aspx" target="_blank"&gt;ASP.NET and Web Tools 2012.2 (Release Candidate)&lt;/a&gt; today and it’s great for the first time it’s easy to deploy a DD Web Application Project (WAP) site precompiled and un-editable it’s just a check box now. &lt;/p&gt; &lt;p&gt;So install the new tools (get them from here &lt;a href="http://www.microsoft.com/en-us/download/details.aspx?id=36053"&gt;Download Page&lt;/a&gt; and &lt;a href="http://go.microsoft.com/fwlink/?LinkID=275132"&gt;Release notes&lt;/a&gt;)  &lt;div style="border-top: gray 1px dotted; border-right: gray 1px dotted; border-bottom: gray 1px dotted; color: #666666; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; margin: 4px; border-left: gray 1px dotted; padding-right: 4px; background-color: #ffffcc"&gt;&lt;strong&gt;Note: &lt;/strong&gt;If you already have publish settings then VS2012 will import them but they need to be in the root of your site.&lt;/div&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-w6SmDFpqTL0/UMsU9zkDoNI/AAAAAAAACh4/GDGGHmkGn-M/s1600-h/New%252520Publish%252520Wizard%25255B4%25255D.png"&gt;&lt;img title="New Publish Wizard" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="New Publish Wizard" src="http://lh5.ggpht.com/-4qP6ZjYTTak/UMsU_RIosCI/AAAAAAAACiA/_0Occ3Zk66I/New%252520Publish%252520Wizard_thumb%25255B2%25255D.png?imgmax=800" width="610" height="480"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Figure 1 - New Publish Wizard&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Navigate to the Settings Tab and check the “Precompile during publishing” checkbox and then click “Configure”&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-gOsaFYZ9wr0/UMsVAdZE0gI/AAAAAAAACiE/lHPykY9ybLA/s1600-h/Disabled%252520Editable%252520markup.%25255B5%25255D.png" target="_blank"&gt;&lt;img title="Disabled Editable markup." style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="Disabled Editable markup." src="http://lh6.ggpht.com/-v2Nf9Q6eHOQ/UMsVB6CDBSI/AAAAAAAACiQ/yYVa7XQGf_s/Disabled%252520Editable%252520markup._thumb%25255B3%25255D.png?imgmax=800" width="411" height="480"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Figure 2 - Disabled Editable markup.&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;un-check the “Allow precompiled site to be updatable” checkbox and your pages will no look like this &lt;strong&gt;Figure 3&lt;/strong&gt; if someone tries to edit them &lt;img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none" alt="Smile" src="http://lh4.ggpht.com/-E6sQw1dE79s/UMsVC2fNcnI/AAAAAAAACiY/sRS-5CSS7ts/wlEmoticon-smile%25255B2%25255D.png?imgmax=800"&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-JOZqzYxNkw0/UMsVEPfSDzI/AAAAAAAACig/iq-GfNhhQsw/s1600-h/Precompiled%252520aspx%252520page%252520no%252520uneditable%25255B5%25255D.png" target="_blank"&gt;&lt;img title="Precompiled aspx page no uneditable" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="Precompiled aspx page no uneditable" src="http://lh3.ggpht.com/-KfNeEEj4R6I/UMsVFD3PDYI/AAAAAAAACik/31xqW0WfC0Q/Precompiled%252520aspx%252520page%252520no%252520uneditable_thumb%25255B3%25255D.png?imgmax=800" width="640" height="140"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Figure 3 - Precompiled aspx page no un-editable&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;And finally in VS2012 you can set the build configuration in each Publish profile, this works without having to change the build configuration in you project.&lt;/p&gt; &lt;p&gt; &lt;div style="border-top: gray 1px dotted; border-right: gray 1px dotted; border-bottom: gray 1px dotted; color: red; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; margin: 4px; border-left: gray 1px dotted; padding-right: 4px; background-color: #ffffcc"&gt;&lt;strong&gt;Warning: &lt;/strong&gt;This sadly does not work for Dynamic Data yet it testes OK you already deployed to a site as it uses the place holders, I’m looking into it hopefully there will be a simple fix.&lt;/div&gt;&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/xOiVE3xOMDA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/1644208332986111323/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=1644208332986111323&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/1644208332986111323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/1644208332986111323?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/xOiVE3xOMDA/aspnet-and-web-tools-20122-release.html" title="ASP.NET and Web Tools 2012.2 (Release Candidate)" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-4qP6ZjYTTak/UMsU_RIosCI/AAAAAAAACiA/_0Occ3Zk66I/s72-c/New%252520Publish%252520Wizard_thumb%25255B2%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2012/12/aspnet-and-web-tools-20122-release.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QFRnw5fSp7ImA9WhJbFUU.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-8596326951462610071</id><published>2012-08-30T12:04:00.001+01:00</published><updated>2012-09-25T16:01:57.225+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-25T16:01:57.225+01:00</app:edited><title>O2 has major fail</title><content type="html">&lt;strike&gt;O2 have just blocked external access to smtp.o2.co.uk this means you cannot send e-mail from your mobile if you are no connected to an O2 network and if you are abroad you will only be able to send email via your data account. &lt;br /&gt;
&lt;br /&gt;
For me this is a major fail I havrelayeded on this from O2 for as long as I have been with them. I will be moving from O2 and finding a solution to sending e-mail that no ISP or Mobile provider will be able to block.&lt;br /&gt;
&lt;br /&gt;
RIP O2&lt;br /&gt;
&lt;br /&gt;
Steve&lt;br /&gt;
&lt;br /&gt;
&lt;/strike&gt;&lt;br /&gt;
&lt;br /&gt;
Well news is O2 don't seem to know what the issue is I just got told by first level support that it was not accessable from outside O2's network? but it is again I suspect I was being given a line...&lt;br /&gt;
&lt;br /&gt;
Steve&lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/naNre_ZGB84" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/8596326951462610071/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=8596326951462610071&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/8596326951462610071?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/8596326951462610071?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/naNre_ZGB84/o2-has-major-fail.html" title="O2 has major fail" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2012/08/o2-has-major-fail.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08NQHc5fSp7ImA9WhVbEE4.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-2916191347055087853</id><published>2012-05-26T12:43:00.001+01:00</published><updated>2012-05-26T14:44:51.925+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-26T14:44:51.925+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic Data" /><category scheme="http://www.blogger.com/atom/ns#" term="Wijmo Open" /><category scheme="http://www.blogger.com/atom/ns#" term="JuiceUI" /><category scheme="http://www.blogger.com/atom/ns#" term="Tabs" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>Creating a Tabbed Entity Template using Wijmo Open for Juice UI</title><content type="html">&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" border="0" src="http://juiceui.com/images/wijmo-logo.png"&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.componentone.com/SuperProducts/WijmoOpenJuiceUI/"&gt;Wijmo Open for Juice UI&lt;/a&gt; is quite cool and offers an alternative to using &lt;a href="http://www.asp.net/ajaxlibrary/AjaxControlToolkitSampleSite/"&gt;Ajax Control Toolkit&lt;/a&gt; which is still cool but &lt;a href="http://www.componentone.com/SuperProducts/WijmoOpenJuiceUI/"&gt;Wijmo Open for Juice UI&lt;/a&gt; supports IE6+, Firefox 3+, Safari 3+, and Chrome browsers which should mean everything works.&lt;/p&gt; &lt;p&gt;I started customising Entity Templates here &lt;a href="http://csharpbits.notaclue.net/2010/10/custom-entity-templates-dynamic-data-4.html"&gt;Custom Entity Templates – Dynamic Data 4&lt;/a&gt; I decided to take this a little further and create a Tabbed UI for editing really long forms, I have done this with the &lt;a href="http://www.asp.net/ajaxlibrary/AjaxControlToolkitSampleSite/"&gt;Ajax Control Toolkit&lt;/a&gt; but thought I like to have a &lt;a href="http://jqueryui.com/home"&gt;jQuery UI&lt;/a&gt; version which brings theming to the table.&lt;/p&gt; &lt;h4&gt;Creating the Entity Template&lt;/h4&gt; &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-tgLhWaXzbt0/T8DCkbfxQoI/AAAAAAAAByc/I6FuO6mY65g/s1600-h/WijmoTabs2.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WijmoTabs" border="0" alt="Wijmo tabs in action" src="http://lh6.ggpht.com/-Him8aTVhJ7U/T8DBy1qK7uI/AAAAAAAAByk/vdzXj9iKyyU/WijmoTabs_thumb1.png?imgmax=800" width="640" height="146"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Figure 1 – Wijmo tabs in action&lt;/strong&gt;&lt;/p&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;asp:Panel ID="Panel1" runat="server"&amp;gt;
    &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="#tabs-1"&amp;gt;Nunc tincidunt&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="#tabs-2"&amp;gt;Proin dolor&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="#tabs-3"&amp;gt;Aenean lacinia&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
    &amp;lt;div id="tabs-1"&amp;gt;
        &amp;lt;p&amp;gt;
            Proin elit arcu, rutrum commodo, vehicula tempus...&lt;br&gt;        &amp;lt;/p&amp;gt;&lt;br&gt;     &amp;lt;/div&amp;gt;
    &amp;lt;div id="tabs-2"&amp;gt;
        &amp;lt;p&amp;gt;
            Morbi tincidunt, dui sit amet facilisis feugiat...&lt;br&gt;        &amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div id="tabs-3"&amp;gt;
        &amp;lt;p&amp;gt;
            Mauris eleifend est et turpis. Duis id erat...&lt;br&gt;        &amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/asp:Panel&amp;gt;
&amp;lt;wijmo:WijTabs ID="Tabs1" runat="server" TargetControlID="Panel1"&amp;gt;
&amp;lt;/wijmo:WijTabs&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 1 – mark-up to create the Wijmo tabs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As you can see there are two blocks the UL and the DIVs the UO is used to create the tabs and each DIV matched an LI element and is shown when the tab is selected. &lt;/p&gt;
&lt;p&gt;This is not quite as easy to render in an Entity Template as was the AJAX tabs because we need to render two sets of elements two the page, first the UL then the DIVs and we also need the IDs of the DIVs for link in the LIs. so we have to first create the DIVs so we can get each ones client ID then create the UL and add the hyperlinks.&lt;/p&gt;&lt;pre class="brush: csharp;"&gt;protected override void OnLoad(EventArgs e)
{
    var groupAttribute = Table.GetAttribute&amp;lt;GroupNamesAttribute&amp;gt;();
    if (groupAttribute == null)
        throw new InvalidOperationException("A GroupsAttribute is required for AJAX tab group to work.");

    var row = new HtmlTableRow();
    var td = new HtmlTableCell();
    row.Controls.Add(td);
    this.Controls.Add(row);
    // create tab container to hold each children column
    var panel = new Panel();
    panel.ID = "tabContainer_" + Table.Name;

    // add a tab panel for each children table
    var unorderedList = new HtmlGenericControl("ul");

    // SortedList of tabs
    var tabs = new SortedList&amp;lt;String, HtmlGenericControl&amp;gt;();

    // add DIV for each group
    foreach (var gi in groupAttribute.Groups)
    {
        var groupName = gi.Value;

        var tabDiv = new HtmlGenericControl("div");
        tabDiv.ClientIDMode = ClientIDMode.Static;
        tabDiv.ID = String.Format("{0}-{1}", Table.Name, groupName).Replace(" ", "-");

        // get columns for this group
        var columns = from c in Table.GetScaffoldColumns(Mode, ContainerType)
                      where c.GetAttributeOrDefault&amp;lt;GroupAttribute&amp;gt;().Index == gi.Key
                      orderby c.GetAttributeOrDefault&amp;lt;DisplayAttribute&amp;gt;().GetOrder()
                      select c;

        // add table for this tabs fields
        var htmlTable = new HtmlTable();
        htmlTable.Attributes.Add("class", "DDDetailsTable");
        htmlTable.CellPadding = 6;
        htmlTable.Attributes.Add("Name", groupName);

        // add fields
        foreach (MetaColumn column in columns)
        {
            // new row
            var htmlRow = new HtmlTableRow();
            htmlTable.Controls.Add(htmlRow);

            // add header cell
            var tdHeader = new HtmlTableCell();
            tdHeader.Attributes.Add("class", "DDLightHeader");
            tdHeader.InnerText = column.DisplayName;
            // add cell to row
            htmlRow.Controls.Add(tdHeader);

            // add data cell
            var tdData = new HtmlTableCell();
            // get field template
            var dynamicControl = new DynamicControl() 
                { 
                    Mode = Mode,
                    DataField = column.Name, 
                    ValidationGroup = this.ValidationGroup 
                };
            // add field template to cell
            tdData.Controls.Add(dynamicControl);
            // add cell to row
            htmlRow.Controls.Add(tdData);
        }

        // add the DynamicControl to the tab panel
        tabDiv.Controls.Add(htmlTable);

        // add the tab to list
        tabs.Add(groupName, tabDiv);
    }

    foreach (var gi in groupAttribute.Groups)
    {
        var groupName = gi.Value;

        // new 'LI'
        var tabLi = new HtmlGenericControl("li");

        // new hyperlink
        var hyperlink = new Literal();
        hyperlink.Text = String.Format("&amp;lt;a href=\"#{0}\" &amp;gt;{1}&amp;lt;/a&amp;gt;", tabs[groupName].ClientID, groupName);

        // add hyperlink to 'LI'
        tabLi.Controls.Add(hyperlink);

        // add LIs items to UL
        unorderedList.Controls.Add(tabLi);
    }

    // add UL to panel
    panel.Controls.Add(unorderedList);

    // add DIVs to panel
    foreach (var gi in groupAttribute.Groups)
    {
        var groupName = gi.Value;
        panel.Controls.Add(tabs[groupName]);
    }

    // add the panel to the page
    td.Controls.Add(panel);

    // associate the panel with the Wijmo tabs
    var wijmoTabs1 = new WijTabs()
        {
            ID = "wijmoTabs1",
            TargetControlID = panel.ID
        };

    // add Wijmo tabs to the page
    td.Controls.Add(wijmoTabs1);
}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 2 – the main code for the Entity Template&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-n8_UYSGgaAI/T8DBz_CWOmI/AAAAAAAABx8/_uFEVtTIvPk/s1600-h/26-05-2012-12-13-504.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="26-05-2012 12-13-50" border="0" alt="26-05-2012 12-13-50" src="http://lh3.ggpht.com/-a_n_ezFGU2o/T8DB05PXqDI/AAAAAAAAByE/G8CvvsIeciU/26-05-2012-12-13-50_thumb2.png?imgmax=800" width="533" height="512"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 2 – the finished Wijmo Tabs EntityTemplate&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To setup you will need to have the Attributes and the Advanced Field Template Factory these are in the sample project. I will be putting on NuGet along with my other bits and pieces hopefully soon.&lt;/p&gt;&lt;pre class="brush: csharp;"&gt;public static void RegisterRoutes(RouteCollection routes)
{
    // add new entity template factory that works with single files also
    DefaultModel.EntityTemplateFactory 
        = new AdvancedEntityTemplateFactory();

    DefaultModel.RegisterContext(typeof(Models.NorthwindEntities), 
        new ContextConfiguration() { ScaffoldAllTables = true });

    routes.Add(new DynamicDataRoute("{table}/{action}.aspx")
    {
        Constraints = new RouteValueDictionary(new 
        { 
            action = "List|Details|Edit|Insert" 
        }),
        Model = DefaultModel
    });
}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 3 – setting up the project Global.asax.cs&lt;/strong&gt;&lt;/p&gt;&lt;pre class="brush: csharp;"&gt;[MetadataTypeAttribute(typeof(Employee.EmployeeMetadata))]
[EntityUIHint("WijmoTabs")]
[GroupNames("Personal","Company","Address")]
public partial class Employee
{
    internal sealed class EmployeeMetadata
    {
        public int EmployeeID { get; set; }

        [Group(0)]
        [Display(Order = 0)]
        public string Title { get; set; }
        [Group(0)]
        [Display(Order = 1)]
        public string TitleOfCourtesy { get; set; }
        [Group(0)]
        [Display(Order = 2)]
        public string FirstName { get; set; }
        [Group(0)]
        [Display(Order = 3)]
        public string LastName { get; set; }
        [Group(0)]
        [Display(Order = 4)]
        public Nullable&amp;lt;DateTime&amp;gt; BirthDate { get; set; }
        [Group(0)]
        [Display(Order = 5)]
        public string Extension { get; set; }
        [Group(0)]
        [Display(Order = 6)]
        public byte[] Photo { get; set; }
        [Group(0)]
        [Display(Order = 7)]
        public string HomePhone { get; set; }

        [Group(1)]
        [Display(Order = 8)]
        public Nullable&amp;lt;DateTime&amp;gt; HireDate { get; set; }
        [Group(1)]
        [Display(Order = 9)]
        public Employee Manager { get; set; }
        [Group(1)]
        [Display(Order = 10)]
        public Nullable&amp;lt;int&amp;gt; ReportsTo { get; set; }
        [Group(1)]
        [Display(Order = 10)]
        public EntityCollection&amp;lt;Employee&amp;gt; Staff { get; set; }
        [Group(1)]
        [Display(Order = 11)]
        public EntityCollection&amp;lt;Order&amp;gt; Orders { get; set; }
        [Group(1)]
        [Display(Order = 12)]
        public EntityCollection&amp;lt;Territory&amp;gt; Territories { get; set; }
        [Group(1)]
        [Display(Order = 13)]
        public string Notes { get; set; }

        [Group(2)]
        [Display(Order = 14)]
        public string Address { get; set; }
        [Group(2)]
        [Display(Order = 15)]
        public string City { get; set; }
        [Group(2)]
        [Display(Order = 16)]
        public string PostalCode { get; set; }
        [Group(2)]
        [Display(Order = 17)]
        public string Region { get; set; }
        [Group(2)]
        [Display(Order = 18)]
        public string Country { get; set; }

        [Display(AutoGenerateField = false)]
        public string PhotoPath { get; set; }
    }
}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Listing 4 – Sample Metadata&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You will also need &lt;a href="http://nuget.org/" target="_blank"&gt;NuGet&lt;/a&gt; and add the &lt;a href="http://nuget.org/packages/WijmoOpenJuiceUI"&gt;Wijmo Open for Juice UI&lt;/a&gt; to your project.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-kGifilXQZSw/T8DDn2YVx9I/AAAAAAAAByo/RxyMj60tyuM/s1600-h/26-05-2012%25252012-00-11%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="26-05-2012 12-00-11" border="0" alt="Get Wijmo Open for Juice UI from NuGet" src="http://lh3.ggpht.com/-pZY9h_j14E4/T8DDoyePFrI/AAAAAAAABys/vicmBqB95Ro/26-05-2012%25252012-00-11_thumb%25255B2%25255D.png?imgmax=800" width="437" height="98"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Later I will add all the features that you get with jQuery UI such as tab sorting and alignment see the &lt;a href="http://demo.componentone.com/aspnet/JuiceExplorer/"&gt;online Juice Explorer&lt;/a&gt; for all the features.&lt;/p&gt;
&lt;p&gt;Just for good measure I have added the Wijmo Accordion to the project&lt;/p&gt;
&lt;p&gt;&lt;a href="http://lh4.ggpht.com/-pJww5KsLxNo/T8DeTXnelOI/AAAAAAAABy8/q5I5AvFowa8/s1600-h/26-05-2012%25252014-37-22%25255B6%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="26-05-2012 14-37-22" border="0" alt="Wijmo Accordian Entity Termplate" src="http://lh3.ggpht.com/-vmHkmr4QDr8/T8DeUQ7VbjI/AAAAAAAABzE/MWkjJwPn-g4/26-05-2012%25252014-37-22_thumb%25255B4%25255D.png?imgmax=800" width="546" height="461"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 3 – Wijmo Accordion Entity Template &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can of course get even more by getting Studio for &lt;a href="http://www.componentone.com/SuperProducts/StudioASPNET/"&gt;Studio for ASP.NET Wijmo&lt;/a&gt; from &lt;a href="http://www.componentone.com" target="_blank"&gt;ComponentOne&lt;/a&gt; this is the best thing for ASP.Net I have seem come out for a while &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-openmouthedsmile" alt="Open-mouthed smile" src="http://lh6.ggpht.com/-qj7N9e-uSSw/T8DB1tWbK-I/AAAAAAAAByI/U0jHlamdGO4/wlEmoticon-openmouthedsmile%25255B2%25255D.png?imgmax=800"&gt; as everyone else seems to be concentrating on either pure client or MVC &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-sadsmile" alt="Sad smile" src="http://lh4.ggpht.com/-yrTZsvRGkFU/T8DB2VDmYGI/AAAAAAAAByQ/B5FWQnQK6kQ/wlEmoticon-sadsmile%25255B2%25255D.png?imgmax=800"&gt;&lt;/p&gt;
&lt;p&gt;Download from my sky drive&lt;a title="WijmoTabs" href="https://skydrive.live.com/redir?resid=96845E7B0FAC1EED!681" target="_blank"&gt; WijmoTabs.zip&lt;/a&gt;&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/PEyOJ6IMetc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/2916191347055087853/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=2916191347055087853&amp;isPopup=true" title="15 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/2916191347055087853?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/2916191347055087853?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/PEyOJ6IMetc/creating-tabbed-entity-template-using.html" title="Creating a Tabbed Entity Template using Wijmo Open for Juice UI" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/-Him8aTVhJ7U/T8DBy1qK7uI/AAAAAAAAByk/vdzXj9iKyyU/s72-c/WijmoTabs_thumb1.png?imgmax=800" height="72" width="72" /><thr:total>15</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2012/05/creating-tabbed-entity-template-using.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UDRHw8eip7ImA9WhRaGU8.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-6614375484351663497</id><published>2012-02-22T15:34:00.001Z</published><updated>2012-02-22T16:47:55.272Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-22T16:47:55.272Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Inferred Keys" /><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server Views" /><category scheme="http://www.blogger.com/atom/ns#" term="LightSwitch" /><title>Using SQL Server View in Visual Studio LightSwitch 2011</title><content type="html">&lt;p&gt;There are two issue resulting from SQL Server Views in VS LightSwitch 2011 inferred keys;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Columns appearing as key that you do not want&amp;#160; to be inferred as keys. &lt;/li&gt;    &lt;li&gt;Forcing columns to be keys that are not inferred as keys. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;You will see the results of these issues with SQL Server Views in different ways for me there were two forms:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Strange Paging on child grids, you may see less row than are set on the pager i.e. page size was set to 10 but on pages you see 5, 6, 7 rows or more.&lt;/li&gt;    &lt;li&gt;Single item per page.&lt;/li&gt;    &lt;li&gt;Single item returned when there should be many.&lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;Removing Inferred Columns&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-RJHqiAX6weY/T0UK33azoLI/AAAAAAAABk4/H_l63OhN_ug/s1600-h/View%25255B7%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="View from Northwind" border="0" alt="View from Northwind" src="http://lh3.ggpht.com/-Ywxbne_Uxhg/T0UK50XiLVI/AAAAAAAABk8/cw10oABBk5E/View_thumb%25255B5%25255D.png?imgmax=800" width="240" height="117" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 1 – View from Northwind&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;As you can see in &lt;strong&gt;Figure 1&lt;/strong&gt; view from the Northwind database as imported in to LightSwitch you can see there are two columns that may cause you problems.&lt;/p&gt;  &lt;p&gt;To take these out of the inferred key on this view we can apply a CAST see below:&lt;/p&gt;  &lt;pre class="brush: sql;"&gt;CAST(dbo.Products.Discontinued AS BIT)&lt;br /&gt;CAST(dbo.Categories.CategoryName AS NVARCHAR(15))&lt;/pre&gt;

&lt;h4&gt;&lt;a href="http://lh6.ggpht.com/-LMmyqYjsMec/T0UK6UfXnUI/AAAAAAAABlI/YRJstSbw-eM/s1600-h/Adding%252520Cast%25255B11%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Adding CAST to Column" border="0" alt="Adding CAST to Column" src="http://lh6.ggpht.com/-kMcpeYtwFiE/T0UK8RnXuMI/AAAAAAAABlQ/43ArSEkCB9E/Adding%252520Cast_thumb%25255B7%25255D.png?imgmax=800" width="240" height="184" /&gt;&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Figure 2 – Adding CAST to Column&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So when we “Update Datasource” we get what we see in &lt;strong&gt;Figure 3&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-gmD7kZ7YfiY/T0UK9zcgYdI/AAAAAAAABlY/o1GGl-xfwCQ/s1600-h/View%252520After%25255B4%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="View after “Update Datasource”" border="0" alt="View after “Update Datasource”" src="http://lh6.ggpht.com/-CEMUiqog3NE/T0UK_xXB3jI/AAAAAAAABlg/vRp10dZGn8c/View%252520After_thumb%25255B2%25255D.png?imgmax=800" width="240" height="115" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 3 – View after “Update Datasource”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now we have remove the two offending columns from the inferred keys.&lt;/p&gt;

&lt;h4&gt;Forcing Columns to be Inferred&lt;/h4&gt;

&lt;p&gt;Here we need to do the opposite and the function we use for that is &lt;a href="http://msdn.microsoft.com/en-us/library/ms184325.aspx" target="_blank"&gt;ISNULL (Transact-SQL)&lt;/a&gt; for this sample we will add the Supplier and Customer ID’s to the inferred keys, here the replacement value I am using is 0 because the two columns are INT but if a column was NVARCHAR(50) then the cast would be ISNULL(TextColumn, N‘’)&lt;/p&gt;

&lt;pre class="brush: sql;"&gt;ISNULL(dbo.Products.SupplierID, 0)&lt;br /&gt;ISNULL(dbo.Products.CategoryID, 0)&lt;/pre&gt;

&lt;p&gt;In &lt;strong&gt;Figure 4&lt;/strong&gt; we can see the result;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/-LLpuOi-ef6Q/T0ULB0Nv2vI/AAAAAAAABlo/seUfoapJQaY/s1600-h/View%252520After%252520Include%252520Columns%25255B4%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="After Including the Supplier and Customer IDs in the Inferred Keys" border="0" alt="After Including the Supplier and Customer IDs in the Inferred Keys" src="http://lh6.ggpht.com/-lBs8klKbmqg/T0ULFGMwONI/AAAAAAAABlw/7GO79Ev14N4/View%252520After%252520Include%252520Columns_thumb%25255B2%25255D.png?imgmax=800" width="240" height="115" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 4 – After Including the Supplier and Customer IDs in the Inferred Keys&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;This way you can for the keys you want to used in your view, there will be a small hit in the queries for using either of these techniques in your queries but hopefully not too much of a hit.&lt;/p&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;These view may or may not have issues, but I have had various problems in LightSwitch relating both issues and used one the two techniques to override the default behaviour.&lt;/div&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;Also I did not come up with these methods they are scattered around the LightSwitch Forums but for my own use and easy reference I have added them here. &lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/EkrgcjYKAmg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/6614375484351663497/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=6614375484351663497&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6614375484351663497?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6614375484351663497?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/EkrgcjYKAmg/using-sql-server-view-in-visual-studio.html" title="Using SQL Server View in Visual Studio LightSwitch 2011" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-Ywxbne_Uxhg/T0UK50XiLVI/AAAAAAAABk8/cw10oABBk5E/s72-c/View_thumb%25255B5%25255D.png?imgmax=800" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2012/02/using-sql-server-view-in-visual-studio.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0IDQHwyfyp7ImA9WhRaF0s.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-9219585852780119463</id><published>2012-02-20T18:06:00.001Z</published><updated>2012-02-20T18:12:51.297Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-20T18:12:51.297Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenAccess ORM" /><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic Data" /><category scheme="http://www.blogger.com/atom/ns#" term="Telerik" /><title>Love Telerik Open Access ORM</title><content type="html">&lt;p&gt;Just watched the Q1 2012 “What’s New in Data Tools – OpenAccess ORM” and they now have a a Dynamic Data Wizard see screen show of the slide.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.telerik.com/products/orm.aspx" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="DD Wizard in Telerik OpenAccess ORM" border="0" alt="DD Wizard in Telerik OpenAccess ORM" src="http://lh5.ggpht.com/-9zVN3dawavk/T0KMP9mHO2I/AAAAAAAABko/pBcVZRXQxmU/DD%252520Wizard%252520in%252520Telerik%252520OpenAccess%252520ORM.png?imgmax=800" width="462" height="425" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Find it here &lt;a href="http://www.telerik.com/products/orm.aspx" target="_blank"&gt;Telrik OpenAccess ORM&lt;/a&gt;, Note this works with Most Databases and all Free databases &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-openmouthedsmile" alt="Open-mouthed smile" src="http://lh4.ggpht.com/-phxhwjq2Vwk/T0KMvLVl1VI/AAAAAAAABkw/oWK9dDNN7SA/wlEmoticon-openmouthedsmile%25255B2%25255D.png?imgmax=800" /&gt;&lt;/p&gt;  &lt;p&gt;This is cool!&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/5f3liczVn-A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/9219585852780119463/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=9219585852780119463&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/9219585852780119463?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/9219585852780119463?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/5f3liczVn-A/love-telerik-open-access-orm.html" title="Love Telerik Open Access ORM" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-9zVN3dawavk/T0KMP9mHO2I/AAAAAAAABko/pBcVZRXQxmU/s72-c/DD%252520Wizard%252520in%252520Telerik%252520OpenAccess%252520ORM.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2012/02/love-telerik-open-access-orm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4MSXs-eSp7ImA9WhRaEU4.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-2153229492236835380</id><published>2012-02-13T12:46:00.001Z</published><updated>2012-02-13T12:59:48.551Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-13T12:59:48.551Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Auditing" /><category scheme="http://www.blogger.com/atom/ns#" term="DynamicData" /><category scheme="http://www.blogger.com/atom/ns#" term="Entity Framework" /><title>Basic Auditing for Dynamic Data with Entity Framework 4.x</title><content type="html">&lt;p&gt;This is my first article of 2012 and I thought I had published an article on this previously but apparently not &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-cryingface" alt="Crying face" src="http://lh5.ggpht.com/-ZXM88T3p974/TzkGD9DYpDI/AAAAAAAABjs/tFoYf9ybq3U/wlEmoticon-cryingface%25255B2%25255D.png?imgmax=800" /&gt; so I will now rectify that oversight.&lt;/p&gt;  &lt;p&gt;The first this we need out audit fields, these are added to every entity we need to audit, next we need an Interface to allow us to fine entities with Audit fields.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-bdXH715QEx8/TzkGEoIBQiI/AAAAAAAABj0/sH7GdnX6F9U/s1600-h/AuditFields%25255B11%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="AuditFields" border="0" alt="AuditFields" src="http://lh3.ggpht.com/-EI3HdIqUd-g/TzkGFezcdfI/AAAAAAAABj8/hmHYZKRYHfs/AuditFields_thumb%25255B5%25255D.png?imgmax=800" width="180" height="265" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 1 – Audit Fields&lt;/strong&gt;&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;public interface IAuditable&lt;br /&gt;{&lt;br /&gt;    String CreatedByUserID { get; set; }&lt;br /&gt;    String CreatedDateTime { get; set; }&lt;br /&gt;    String UpdatedByUserID { get; set; }&lt;br /&gt;    String UpdatedDateTime { get; set; }&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 1 – IAuditable interface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We then need to add this to each entity that will be audited, this is just applied to you metadata classes on the Partial Class &lt;strong&gt;NOT&lt;/strong&gt; the buddy class.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;[MetadataType(typeof(AppAlterMetadata))]&lt;br /&gt;public partial class AppAlter : IAuditable&lt;br /&gt;{&lt;br /&gt;    internal class AppAlterMetadata&lt;br /&gt;    {&lt;br /&gt;        public Object ID { get; set; }&lt;br /&gt;&lt;br /&gt;        // other field deleted for brevety&lt;br /&gt;&lt;br /&gt;        // auditing fields&lt;br /&gt;        public Object CreatedByUserID { get; set; }&lt;br /&gt;        public Object CreatedDateTime { get; set; }&lt;br /&gt;        public Object UpdatedByUserID { get; set; }&lt;br /&gt;        public Object UpdatedDateTime { get; set; }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 2 – the interface applied to each entity that requires auditing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now for the code that does the auditing automatically,&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;public partial class MyEntities&lt;br /&gt;{&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Called when [context created].&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    partial void OnContextCreated()&lt;br /&gt;    {&lt;br /&gt;        // Register the handler for the SavingChanges event. &lt;br /&gt;        this.SavingChanges += new EventHandler(context_SavingChanges);&lt;br /&gt;    }&lt;/pre&gt;

&lt;pre class="brush: csharp;"&gt;&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Handles the SavingChanges event of the context control.&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    /// &amp;lt;param name=&amp;quot;sender&amp;quot;&amp;gt;The source of the event.&amp;lt;/param&amp;gt;&lt;br /&gt;    /// &amp;lt;param name=&amp;quot;e&amp;quot;&amp;gt;The &amp;lt;see cref=&amp;quot;System.EventArgs&amp;quot;/&amp;gt; instance containing the event data.&amp;lt;/param&amp;gt;&lt;br /&gt;    private static void context_SavingChanges(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        var objects = ((ObjectContext)sender).ObjectStateManager;&lt;br /&gt;&lt;br /&gt;        // handle auditing&lt;br /&gt;        AuditingHelperUtility.ProcessAuditFields(objects.GetObjectStateEntries(EntityState.Added));&lt;br /&gt;        AuditingHelperUtility.ProcessAuditFields(objects.GetObjectStateEntries(EntityState.Modified), InsertMode: false);&lt;br /&gt;    }&lt;/pre&gt;

&lt;pre class="brush: csharp;"&gt;&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Auditing helper utility class&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    internal static class AuditingHelperUtility&lt;br /&gt;    {&lt;br /&gt;        internal static void ProcessAuditFields(IEnumerable&amp;lt;Object&amp;gt; list, bool InsertMode = true)&lt;br /&gt;        {&lt;br /&gt;            foreach (ObjectStateEntry item in list)&lt;br /&gt;            {&lt;br /&gt;                var appUserID = GetUserId();&lt;br /&gt;                // deal with insert and update entities&lt;br /&gt;                var auditEntity = item.Entity as IAuditable;&lt;br /&gt;                if (auditEntity != null)&lt;br /&gt;                {&lt;br /&gt;&lt;br /&gt;                    if (InsertMode)&lt;br /&gt;                    {&lt;br /&gt;                        auditEntity.CreatedByUserID = appUserID;&lt;br /&gt;                        auditEntity.CreatedDateTime = DateTime.Now;&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    auditEntity.UpdatedByUserID = appUserID;&lt;br /&gt;                    auditEntity.UpdatedDateTime = DateTime.Now;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;/pre&gt;

&lt;pre class="brush: csharp;"&gt;&lt;br /&gt;&lt;br /&gt;    public static String GetUserId()&lt;br /&gt;    {&lt;br /&gt;        return System.Web.HttpContext.Current.User.Identity.Name;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 3 – the Audit code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lets break this down into three sections&lt;/p&gt;

&lt;h4&gt;Section 1&lt;/h4&gt;

&lt;p&gt;Here we wire-up the &lt;strong&gt;SavingChanges&lt;/strong&gt; handler in the &lt;strong&gt;OnContextCreated()&lt;/strong&gt; partial method to do this we first need to create a partial class from out entities for you look in the EDMX code behind file you will see something like this;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/-v_S2byac3kk/TzkGG6SK4yI/AAAAAAAABkE/IDFAkiEf8is/s1600-h/EFClasses%25255B9%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="EFClasses" border="0" alt="EFClasses" src="http://lh3.ggpht.com/-o_018fxU26w/TzkGHvzzNEI/AAAAAAAABkI/_rw5Ed1qbP8/EFClasses_thumb%25255B5%25255D.png?imgmax=800" width="432" height="306" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 2 – Entities classes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;so we add a new class to the the project, make sure it has the same namespace as the EDMX code behind file (this is pretty much the same as for out metadata classes) and then we add the partial class same as the &lt;strong&gt;MyEntities&lt;/strong&gt; (this will be the name you gave it when creating but it is there in the code behind you can’t miss it) class, see &lt;strong&gt;Listing 3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The method is wired up with this line of code:&lt;/p&gt;
this.SavingChanges += new EventHandler(context_SavingChanges); 

&lt;br /&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;p&gt;Section 2&lt;/p&gt;

&lt;p&gt;Now in the &lt;strong&gt;context_SavingChanges&lt;/strong&gt; method we simply get the &lt;strong&gt;ObjectStateManager&lt;/strong&gt;&amp;#160; which has all the objects that are being added, updated and deleted, here we are only interested in the &lt;strong&gt;Added &lt;/strong&gt;and &lt;strong&gt;Modified&lt;/strong&gt; items. All we do is call our helper with each collection of objects.&lt;/p&gt;

&lt;h4&gt;Section 3&lt;/h4&gt;

&lt;p&gt;Looking at &lt;strong&gt;Listing 3&lt;/strong&gt; you will see the AuditingHelperUtility and it’s ProcessAuditFields method, here we first of all cast the each entity to the IAuditable interface and check for null if it isn't then set the appropriate properties and exit.&lt;/p&gt;

&lt;h4&gt;Finally&lt;/h4&gt;

&lt;p&gt;This can be expanded to cover many different requirements, I have maintained a separate audit table using this method with the addition of a little reflection.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/csS9kaG1Mrg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/2153229492236835380/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=2153229492236835380&amp;isPopup=true" title="20 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/2153229492236835380?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/2153229492236835380?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/csS9kaG1Mrg/basic-auditing-for-dynamic-data-with.html" title="Basic Auditing for Dynamic Data with Entity Framework 4.x" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-ZXM88T3p974/TzkGD9DYpDI/AAAAAAAABjs/tFoYf9ybq3U/s72-c/wlEmoticon-cryingface%25255B2%25255D.png?imgmax=800" height="72" width="72" /><thr:total>20</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2012/02/basic-auditing-for-dynamic-data-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQMQH8_cCp7ImA9WhdaEUQ.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-6925223093742230174</id><published>2011-10-21T12:23:00.001+01:00</published><updated>2011-10-21T12:26:21.148+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-21T12:26:21.148+01:00</app:edited><title>Axialis Software Ribbon &amp; Toolbar Stock Icons - Basic Set Offer</title><content type="html">&lt;p&gt;   &lt;table border="0" cellspacing="0" cellpadding="2" width="903"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" width="154"&gt;&lt;img src="https://usd.swreg.org/soft_shop/templates/47156/l4.gif" /&gt;&lt;/td&gt;          &lt;td valign="top" width="747"&gt;are offering 30%-off discount to my readers for their new &lt;a href="http://www.axialis.com/stock-icons/ribbon-toolbar.html"&gt;Windows Ribbon &amp;amp; Toolbars Stock Icons Basic Set&lt;/a&gt;, they are provided in sizes 48x48, 32x32, 24x42, 16x16, different states (normal, hot, disabled) and RGBA / RGB color depths. Called &amp;quot;Basic&amp;quot;, the first set contains 1108 unique icons. Including all sizes and derivatives, more that 29,000 images are provided. &lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.axialis.com/stock-icons/ort-illustration-2.png" /&gt;&lt;/p&gt;  &lt;p&gt;Get the offer &lt;a href="https://usd.swreg.org/cgi-bin/s.cgi?s=47156&amp;amp;p=47156-14&amp;amp;q=1&amp;amp;rc=45K2D45KC4"&gt;here&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This offer will last 30 days up to Nov 20: &lt;/p&gt;  &lt;p&gt;These look great and will be ideal for &lt;a href="http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200046556"&gt;Visual Studio LightSwitch 2011&lt;/a&gt; toolbars&lt;/p&gt; &lt;span class="sbmLink"&gt;   &lt;table cellspacing="1" cellpadding="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td class="sbmText"&gt;Share this post : &lt;/td&gt;          &lt;td&gt;&lt;a title="Post it to del.icio.us" href="http://del.icio.us/post?url=http://csharpbits.notaclue.net/2011/10/axialis-software-ribbon-toolbar-stock.html&amp;amp;;title=Axialis Software Ribbon &amp;amp; Toolbar Stock Icons - Basic Set Offer" target="_blank"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/deliciou4.png" /&gt;&lt;/a&gt;&lt;/td&gt;          &lt;td&gt;&lt;a title="Post it to digg" href="http://digg.com/submit?phase=2&amp;amp;url=http://csharpbits.notaclue.net/2011/10/axialis-software-ribbon-toolbar-stock.html&amp;amp;title=Axialis Software Ribbon &amp;amp; Toolbar Stock Icons - Basic Set Offer" target="_blank"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/digg14.png" /&gt;&lt;/a&gt;&lt;/td&gt;          &lt;td&gt;&lt;a title="Post it to dotnetkicks" href="http://www.dotnetkicks.com/kick/?url=http://csharpbits.notaclue.net/2011/10/axialis-software-ribbon-toolbar-stock.html&amp;amp;title=Axialis Software Ribbon &amp;amp; Toolbar Stock Icons - Basic Set Offer" target="_blank"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/CropperCapture154.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;          &lt;td&gt;&lt;a title="Post it to Facebook" href="http://www.facebook.com/sharer.php?u=http://csharpbits.notaclue.net/2011/10/axialis-software-ribbon-toolbar-stock.html&amp;amp;t=Axialis Software Ribbon &amp;amp; Toolbar Stock Icons - Basic Set Offer" target="_blank"&gt;&lt;img border="0" src="http://blogs.technet.com/photos/james/images/1765319/original.aspx" /&gt;&lt;/a&gt;&lt;/td&gt;          &lt;td&gt;&lt;a title="Post it to live" href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://csharpbits.notaclue.net/2011/10/axialis-software-ribbon-toolbar-stock.html&amp;amp;title=Axialis Software Ribbon &amp;amp; Toolbar Stock Icons - Basic Set Offer" target="_blank"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/live4.png" /&gt;&lt;/a&gt;&lt;/td&gt;          &lt;td&gt;&lt;a title="Post it to reddit!" href="http://reddit.com/submit?url=http://csharpbits.notaclue.net/2011/10/axialis-software-ribbon-toolbar-stock.html&amp;amp;title=Axialis Software Ribbon &amp;amp; Toolbar Stock Icons - Basic Set Offer" target="_blank"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/reddit4.png" /&gt;&lt;/a&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/span&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/5C75Us77ICE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/6925223093742230174/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=6925223093742230174&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6925223093742230174?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6925223093742230174?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/5C75Us77ICE/axialis-software-ribbon-toolbar-stock.html" title="Axialis Software Ribbon &amp;amp; Toolbar Stock Icons - Basic Set Offer" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/10/axialis-software-ribbon-toolbar-stock.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UGQno_eSp7ImA9WhdRGEw.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-6719145916617017390</id><published>2011-08-08T14:47:00.001+01:00</published><updated>2011-08-08T14:47:03.441+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-08T14:47:03.441+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic Data" /><category scheme="http://www.blogger.com/atom/ns#" term="LightSwitch" /><title>Visual Studio LightSwitch 2011 Arrives (Yes, I know it arrived a while ago!)</title><content type="html">&lt;p&gt;Well I have finally had the time to indulge in &lt;a href="http://www.microsoft.com/visualstudio/en-us/lightswitch/try" target="_blank"&gt;Visual Studio LightSwitch 2011 RTM&lt;/a&gt; (henceforth &lt;strong&gt;LS&lt;/strong&gt;), and it brings to Silverlight development what Dynamic Data (henceforth &lt;strong&gt;DD&lt;/strong&gt;) brought to Web Forms &lt;a href="http://www.urbandictionary.com/define.php?term=with+bells+on"&gt;with bells on&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;It’s faster to develop an app with &lt;strong&gt;LS&lt;/strong&gt; than it is with &lt;strong&gt;DD&lt;/strong&gt; and that’s a fact. I decided to develop an app that I had need to run my little company but had been putting off for the last two years for lack of time. You know how a builder always has work to do on his own home never completed, well no more with &lt;strong&gt;LS&lt;/strong&gt; I built it in just over one day see &lt;strong&gt;Figure 1&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-U_CCDGX4vTo/Tj_o1Mu-nFI/AAAAAAAABAE/DUaIulwVvLc/s1600-h/OneDayApp%25255B6%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="My App in one day" border="0" alt="My App in one day" src="http://lh4.ggpht.com/-H5KWfI71zTw/Tj_o1o5qYmI/AAAAAAAABAI/YXlhP-nRZuM/OneDayApp_thumb%25255B4%25255D.png?imgmax=800" width="640" height="397" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 1 – My App in one day&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;All I have to add is the Invoice report which I am going to use &lt;a href="http://www.devexpress.com" target="_blank"&gt;DevExpress&lt;/a&gt; – &lt;a href="http://www.devexpress.com/Products/NET/Controls/LightSwitch/" target="_blank"&gt;XtraReports for Light Switch&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;And the good news is that most of the Silverlight control venders are jumping in there with everything from &lt;em&gt;How to add our controls&lt;/em&gt; to custom installs for &lt;strong&gt;LS&lt;/strong&gt;;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.devexpress.com" target="_blank"&gt;DevExpress&lt;/a&gt; - &lt;a href="http://www.microsoft.com/visualstudio/en-us/lightswitch/extensions/devexpress" target="_blank"&gt;Learn more about the DevExpress extensions&lt;/a&gt;&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;See the XraReports for LightSwitch in action with this video &lt;a title="http://tv.devexpress.com/#XtraReportsGettingStartedLightSwitch;XtraReports+for+LightSwitch.product;1" href="http://tv.devexpress.com/#XtraReportsGettingStartedLightSwitch;XtraReports+for+LightSwitch.product;1" target="_blank"&gt;Getting Started with XtraReports for LightSwitch&lt;/a&gt; from &lt;a href="http://community.devexpress.com/blogs/seth/default.aspx" target="_blank"&gt;Seth Juarez&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;&lt;a href="http://www.microsoft.com/visualstudio/en-us/lightswitch/extension-videos/devexpress-drilldown" target="_blank"&gt;Video: DevExpress Visual Studio LightSwitch Extensions&lt;/a&gt;&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/site/search?f%5B0%5D.Type=VisualStudioVersion&amp;amp;f%5B0%5D.Value=VSLS&amp;amp;f%5B0%5D.Text=Visual%20Studio%20LightSwitch&amp;amp;f%5B1%5D.Type=User&amp;amp;f%5B1%5D.Value=ComponentOne&amp;amp;f%5B1%5D.Text=ComponentOne" target="_blank"&gt;ComponentOne&lt;/a&gt; - &lt;a href="http://www.microsoft.com/visualstudio/en-us/lightswitch/extensions/componentone" target="_blank"&gt;Learn more about the ComponentOne extension&lt;/a&gt;&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;&lt;a href="http://demo.componentone.com/LightSwitch/OLAP/?productID=309&amp;amp;utm_source=LandingPage&amp;amp;utm_medium=landing&amp;amp;utm_term=OLAPLightSwitchDemo&amp;amp;utm_campaign=OlapLandingJuly2011" target="_blank"&gt;Live sample&lt;/a&gt;&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/site/search?f%5B0%5D.Type=VisualStudioVersion&amp;amp;f%5B0%5D.Value=VSLS&amp;amp;f%5B0%5D.Text=Visual%20Studio%20LightSwitch&amp;amp;f%5B1%5D.Type=User&amp;amp;f%5B1%5D.Value=Infragistics&amp;amp;f%5B1%5D.Text=Infragistics" target="_blank"&gt;Infragistics&lt;/a&gt; - &lt;a href="http://www.microsoft.com/visualstudio/en-us/lightswitch/extensions/infragistics"&gt;Learn more about the Infragistics extension&lt;/a&gt;&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;&lt;a href="http://www.microsoft.com/visualstudio/en-us/lightswitch/extension-videos/infragistics-drilldown" target="_blank"&gt;Video: Infragistics Visual Studio LightSwitch Extensions&lt;/a&gt;&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/site/search?f%5B0%5D.Type=VisualStudioVersion&amp;amp;f%5B0%5D.Value=VSLS&amp;amp;f%5B0%5D.Text=Visual%20Studio%20LightSwitch&amp;amp;f%5B1%5D.Type=Tag&amp;amp;f%5B1%5D.Value=LightSwitch%20Data%20Source&amp;amp;f%5B2%5D.Type=User&amp;amp;f%5B2%5D.Value=RSSBus&amp;amp;f%5B2%5D.Text=RSSBus" target="_blank"&gt;RSSBus&lt;/a&gt; - &lt;a href="http://www.microsoft.com/visualstudio/en-us/lightswitch/extensions/rssbus"&gt;Learn more about the RSSBus extensions&lt;/a&gt;&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;&lt;!--EndFragment--&gt;&lt;a href="http://www.microsoft.com/visualstudio/en-us/lightswitch/extension-videos/rssbus-drilldown" target="_blank"&gt;Video: RSSBus Visual Studio LightSwitch Extensions&lt;/a&gt;&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;&lt;a href="http://www.telerik.com" target="_blank"&gt;Telerik&lt;/a&gt; - &lt;a href="http://www.telerik.com/products/lightswitch-support.aspx?utm_source=twitter&amp;amp;utm_medium=sm&amp;amp;utm_campaign=lightswitch-launch" target="_blank"&gt;Extend Visual Studio LightSwitch with Telerik Dev Tools&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;And there are tones of starter kits on &lt;a href="http://go.microsoft.com/?linkid=9778472"&gt;Visual Studio Gallery&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;The forums are very active;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://social.msdn.microsoft.com/Forums/en-US/lightswitch/threads" target="_blank"&gt;Visual Studio LightSwitch - General Questions&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://social.msdn.microsoft.com/Forums/en-US/lsextensibility/threads" target="_blank"&gt;Visual Studio LightSwitch Extensibility&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Blogs I’ve found so far;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://blogs.msdn.com/b/lightswitch" target="_blank"&gt;Visual Studio LightSwitch Team Blog&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/b/bethmassi/" target="_blank"&gt;Sharing the goodness that is VB&lt;/a&gt; - Beth Massi&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/b/mthalman/" target="_blank"&gt;From The Depths&lt;/a&gt; - Matt Thalman&lt;/li&gt;    &lt;li&gt;&lt;a href="http://community.devexpress.com/blogs/seth/default.aspx" target="_blank"&gt;DevExpress Reporting Blog&lt;/a&gt; - Seth Juarez&lt;/li&gt;    &lt;li&gt;&lt;a href="http://dotnettim.wordpress.com/" target="_blank"&gt;Tim Leung's Blog&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I don’t expect this is an exhaustive list but it’s very encouraging and I will be joining the band waggon and build some of my own extensions and of course blog about it here.&lt;/p&gt;  &lt;p&gt;P.S. I have not left &lt;strong&gt;DD&lt;/strong&gt; this is just some new fun that will certainly compliment &lt;strong&gt;DD&lt;/strong&gt; &lt;/p&gt;  &lt;p&gt;P.P.S. I still have loads of stuff to put on &lt;a href="http://nuget.org/" target="_blank"&gt;NuGet&lt;/a&gt; so keep an eye on me here.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/a5e13j-iKVo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/6719145916617017390/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=6719145916617017390&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6719145916617017390?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6719145916617017390?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/a5e13j-iKVo/visual-studio-lightswitch-2011-arrives.html" title="Visual Studio LightSwitch 2011 Arrives (Yes, I know it arrived a while ago!)" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/-H5KWfI71zTw/Tj_o1o5qYmI/AAAAAAAABAI/YXlhP-nRZuM/s72-c/OneDayApp_thumb%25255B4%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/08/visual-studio-lightswitch-2011-arrives.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4GR3s7cCp7ImA9WhdTFUQ.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-4391504803162160081</id><published>2011-07-13T23:38:00.001+01:00</published><updated>2011-07-13T23:58:46.508+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-13T23:58:46.508+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic Data" /><category scheme="http://www.blogger.com/atom/ns#" term="NuGet" /><category scheme="http://www.blogger.com/atom/ns#" term="FieldTemplate" /><category scheme="http://www.blogger.com/atom/ns#" term="Image Handler" /><title>Dynamic Data Image Field Template Updated</title><content type="html">&lt;p&gt;I’ve update the Database Embedded Image sample on &lt;a href="http://nuget.org" target="_blank"&gt;NuGet&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;   &lt;table border="0" cellspacing="0" cellpadding="2" width="628"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td width="1%"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Dynamic Data Database Embedded Image Field Template " border="0" alt="Dynamic Data Database Embedded Image Field Template " src="http://lh5.ggpht.com/-410tWEg-C04/Th4f1LeKZCI/AAAAAAAAA_4/91j1EbAjpMg/DatabaseEmbededImage100x100a.png?imgmax=800" width="100" height="100" /&gt;&lt;/td&gt;          &lt;td width="99%"&gt;&amp;#160;&lt;a href="http://nuget.org/List/Packages/DynamicData.ImageFieldTemplate"&gt;Dynamic Data Database Embedded Image Field Template&lt;/a&gt; &lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td width="1%"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Dynamic Data Image Handler" border="0" alt="Dynamic Data Image Handler" src="http://lh5.ggpht.com/-DGthqk2VEY0/Th4eT-V3xyI/AAAAAAAAA_8/kcHIV7RtAa4/ImageHandler100x100%25255B1%25255D.png?imgmax=800" width="100" height="100" /&gt;&lt;/td&gt;          &lt;td width="99%"&gt;&amp;#160;&lt;a href="http://nuget.org/List/Packages/Microsoft.Web.DynamicData.Handlers"&gt;Dynamic Data Image Handler&lt;/a&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;instead of depending on a &lt;a href="http://nuget.org/List/Packages/NotAClue.Web.Helpers"&gt;NotAClue.Web.Helpers&lt;/a&gt; it now depends on:&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="2" width="629"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width="1%"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="NotAClue Dynamic Data Extensions " border="0" alt="NotAClue Dynamic Data Extensions " src="http://lh3.ggpht.com/--Cx9ROgQ2OE/Th4f2Dugj0I/AAAAAAAABAA/e1VwYiXuni8/DynamicDataExtensions100x100%25255B5%25255D.png?imgmax=800" width="100" height="100" /&gt;&lt;/td&gt;        &lt;td width="99%"&gt;&amp;#160;&lt;a href="http://nuget.org/List/Packages/NotAClue.DynamicData.Extensions"&gt;NotAClue Dynamic Data Extensions&lt;/a&gt; &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;All future samples will build on this main library.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/83sXZ0-KcDQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/4391504803162160081/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=4391504803162160081&amp;isPopup=true" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/4391504803162160081?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/4391504803162160081?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/83sXZ0-KcDQ/dynamic-data-image-field-template.html" title="Dynamic Data Image Field Template Updated" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-410tWEg-C04/Th4f1LeKZCI/AAAAAAAAA_4/91j1EbAjpMg/s72-c/DatabaseEmbededImage100x100a.png?imgmax=800" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/07/dynamic-data-image-field-template.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcDSX08fSp7ImA9WhZaF0o.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-409909221399298636</id><published>2011-07-04T00:26:00.001+01:00</published><updated>2011-07-04T10:01:18.375+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-04T10:01:18.375+01:00</app:edited><title>Custom Field Templates On NuGet</title><content type="html">&lt;p&gt;In this article I am going to build some custom field templates;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;File Upload field template &lt;/li&gt;    &lt;li&gt;Image Upload field template &lt;/li&gt;    &lt;li&gt;Image Select field template &lt;/li&gt;    &lt;li&gt;Date picker field template &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="CustomFieldTemplates" border="0" alt="CustomFieldTemplates" src="http://lh5.ggpht.com/-fxr5NbafOTw/ThD6lIiIVYI/AAAAAAAAA_E/o_tGs8bT7iw/CustomFieldTemplates%25255B5%25255D.png?imgmax=800" width="437" height="529" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 1 – Our proposed field templates&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;So first of all we need specify what we want each to do.&lt;/p&gt;  &lt;h5&gt;File Upload Field Template Requirements&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;Be able to upload and file type (PDF, ZIP, DOC, XLS etc.). &lt;/li&gt;    &lt;li&gt;Restrict types to be uploaded. &lt;/li&gt;    &lt;li&gt;access uploaded file via hyperlink (enable or disable this). &lt;/li&gt;    &lt;li&gt;Store in folder in site. &lt;/li&gt;    &lt;li&gt;Replace old file if new file replaces it during edit (you would need to maintain deleting items using some business logic as the field template is not called during the deletion process). &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Image Upload Field Template Requirements&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;Be able to upload and image type (jpeg, gif, png, etc.). &lt;/li&gt;    &lt;li&gt;Restrict which image types can be uploaded (i.e. restricts to jpeg or png etc.). &lt;/li&gt;    &lt;li&gt;Store in folder in site. &lt;/li&gt;    &lt;li&gt;Replace old file if new file replaces it during edit (you would need to maintain deleting items using some business logic as the field template is not called during the deletion process).&lt;!--EndFragment--&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Image Select Field Template Requirements&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;Choose from a set of images . &lt;/li&gt;    &lt;li&gt;Use images a folder in site. &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Ajax Date picker&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;Select a date using a popup date picker from the Ajax Control toolkit. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;At another time we will do one based on the jQuery UI date picker.&lt;/p&gt;  &lt;h5&gt;Building the Field Templates&lt;/h5&gt;  &lt;p&gt;We could just pass the information we want using the UIHint attribute and it’s control parameters collection but there is no design time intellisense, so we will build an attribute that all three field template can use. We will call it the Upload attribute it will need to store the following information;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Folder to store images &lt;/li&gt;    &lt;li&gt;Folder to store file icons &lt;/li&gt;    &lt;li&gt;Size to display Icon or Image (Height and Width) &lt;/li&gt;    &lt;li&gt;Whether to display an hyperlink or not. &lt;/li&gt;    &lt;li&gt;Acceptable file type for image and file upload. &lt;/li&gt;    &lt;li&gt;Image extension for icons. &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;The Upload Attribute&lt;/h5&gt;  &lt;pre class="brush: csharp;"&gt;/// &amp;lt;summary&amp;gt;
/// Upload attribute defines values for the upload
/// field templates
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class UploadAttribute : Attribute
{
    #region Properties
    /// &amp;lt;summary&amp;gt;
    /// Gets or sets the height to display the image, 
    /// if only one of the two dimensions are specified
    /// then the aspect ration will be retained.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;value&amp;gt;The height.&amp;lt;/value&amp;gt;
    /// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    public int Height { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// Gets or sets the width to display the image, 
    /// if only one of the two dimensions are specified
    /// then the aspect ration will be retained.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;value&amp;gt;The width.&amp;lt;/value&amp;gt;
    /// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    public int Width { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// Gets or sets the uploads folder.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;value&amp;gt;The uploads folder.&amp;lt;/value&amp;gt;
    /// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    public String UploadFolder { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// Gets or sets the icons folder.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;value&amp;gt;The icons folder.&amp;lt;/value&amp;gt;
    /// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    public String ImagesFolder { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// Gets or sets a value indicating whether [show hyperlink].
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;value&amp;gt;&amp;lt;c&amp;gt;true&amp;lt;/c&amp;gt; if [show hyperlink]; otherwise, &amp;lt;c&amp;gt;false&amp;lt;/c&amp;gt;.&amp;lt;/value&amp;gt;
    /// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    public Boolean ShowHyperlink { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// Gets or sets the file types.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;value&amp;gt;The file types.&amp;lt;/value&amp;gt;
    /// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    public String[] FileTypes { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// Gets or sets the image extension.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;value&amp;gt;The image extension.&amp;lt;/value&amp;gt;
    /// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    public String ImageExtension { get; set; }
    #endregion

    /// &amp;lt;summary&amp;gt;
    /// Initializes a new instance of the &amp;lt;see cref=&amp;quot;T:System.Attribute&amp;quot;/&amp;gt; class
    /// setting the Height to 50 and the folder to &amp;quot;~/images&amp;quot;.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    public UploadAttribute()
    {
        // set a default value of 50 and constrain aspect ratio.
        Height = 50;
        // set default images folder
        UploadFolder = &amp;quot;~/images&amp;quot;;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 1 – Upload Attribute&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The attribute in &lt;strong&gt;Listing 1&lt;/strong&gt; handles all the properties we want so we can build each of the field templates.&lt;/p&gt;

&lt;h5&gt;Upload File Field Template&lt;/h5&gt;

&lt;p&gt;To start off expand the DynamicData folder to see the FieldTemplate folder and right click and choose &lt;strong&gt;Add-&amp;gt;New Item…&lt;/strong&gt; you can now choose “Dynamic Data Field” (this will create a new field template pretty much the same as the Text field template) enter the name “UploadFile” and you will see your new blank field template.&lt;/p&gt;

&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Dynamic Data Field" border="0" alt="Dynamic Data Field" src="http://lh3.ggpht.com/-k4rz6dzUN2Y/ThD6l2PrS6I/AAAAAAAAA_I/_G5gBiuf9SA/Dynamic%252520Data%252520Field%25255B7%25255D.png?imgmax=800" width="484" height="91" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 2 – Dynamic Data Field&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have decided that I want nothing to show apart form the File Upload control until there is a file uploaded&lt;/p&gt;

&lt;table border="0" cellspacing="0" cellpadding="2" width="400"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top" width="200"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WithoutData" border="0" alt="WithoutData" src="http://lh6.ggpht.com/-7prXOx4PWgw/ThD6mEy9vjI/AAAAAAAAA_M/kpB1whsutS0/WithoutData%25255B5%25255D.png?imgmax=800" width="285" height="75" /&gt;&lt;/td&gt;

      &lt;td valign="top" width="200"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WithData" border="0" alt="WithData" src="http://lh6.ggpht.com/-1Vf6HH0VsEY/ThD6nA3lw1I/AAAAAAAAA_Q/baMwWCU00hU/WithData%25255B5%25255D.png?imgmax=800" width="285" height="85" /&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="200"&gt;&lt;strong&gt;Figure 3 – Insert mode&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="200"&gt;&lt;strong&gt;Figure 4 – Edit mode&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;h5&gt;&lt;font style="font-weight: normal"&gt;In &lt;strong&gt;Figures 2 &amp;amp; 3&lt;/strong&gt; we can see both modes we only see an image and link/text when data is already present. So I have put the mark-up for this in a place holder.&lt;/font&gt;&lt;/h5&gt;

&lt;pre class="brush: csharp;"&gt;&amp;lt;asp:PlaceHolder 
    ID=&amp;quot;PlaceHolder1&amp;quot; 
    runat=&amp;quot;server&amp;quot; 
    Visible=&amp;quot;false&amp;quot;&amp;gt;
    &amp;lt;asp:Image ID=&amp;quot;Image1&amp;quot; runat=&amp;quot;server&amp;quot; /&amp;gt;&amp;amp;nbsp;
    &amp;lt;asp:Label ID=&amp;quot;Label1&amp;quot; runat=&amp;quot;server&amp;quot; Text=&amp;quot;&amp;lt;%# FieldValueString %&amp;gt;&amp;quot; /&amp;gt;
    &amp;lt;asp:HyperLink ID=&amp;quot;HyperLink1&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;&amp;lt;%# FieldValueString %&amp;gt;&amp;lt;/asp:HyperLink&amp;gt;
&amp;lt;/asp:PlaceHolder&amp;gt;&amp;lt;br /&amp;gt;
&amp;lt;asp:FileUpload 
    ID=&amp;quot;FileUpload1&amp;quot; 
    runat=&amp;quot;server&amp;quot; 
    CssClass=&amp;quot;DDTextBox&amp;quot; 
    Width=&amp;quot;150px&amp;quot;/&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 2 – Upload File field template mark-up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next we remove the current validators and replace with a custom validator.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;&amp;lt;asp:CustomValidator 
    ID=&amp;quot;CustomValidator1&amp;quot; 
    runat=&amp;quot;server&amp;quot; 
    ControlToValidate=&amp;quot;FileUpload1&amp;quot; 
    onservervalidate=&amp;quot;CustomValidator1_ServerValidate&amp;quot;&amp;gt;
&amp;lt;/asp:CustomValidator&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 4 – Custom validator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the code behind we need to setup the validator and the fileupload&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
    CustomValidator1.Text = &amp;quot;*&amp;quot;;
    SetUpValidator(CustomValidator1);

    // get attributes
    uploadAttribute = MetadataAttributes.GetAttribute&amp;lt;UploadAttribute&amp;gt;();
    if (uploadAttribute == null)
    {
        // no attribute thrw an error
        throw new InvalidOperationException(&amp;quot;FileUpload must have valid uploadAttribute applied&amp;quot;);
    }
    else
    {
        // add tooltip describing what file types can be uploaded.
        FileUpload1.ToolTip = String.Format(&amp;quot;Upload {0} files&amp;quot;, uploadAttribute.FileTypes.ToCsvString());
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 5 – Page_Load&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here we setup the custom validator and get the Upload attribute, if the attribute is missing we throw an InvalidOperationException and if the attribute is there we set the FileUpload’s tooltip to a helpful message.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
    if (FileUpload1.HasFile)
    {
        // get files name
        var fileName = FileUpload1.FileName;

        // get files extension without the dot
        String fileExtension = FileUpload1.GetFileExtension();

        // check file has an allowed file extension
        if (!uploadAttribute.FileTypes.Contains(fileExtension))
        {
            args.IsValid = false;
            CustomValidator1.ErrorMessage = String.Format(&amp;quot;{0} is not a valid upload file type (only {1} are supported).&amp;quot;,
                FileUpload1.FileName, 
                uploadAttribute.FileTypes.ToCsvString());
        }
    }
    else if (Column.IsRequired &amp;amp;&amp;amp; String.IsNullOrEmpty(Label1.Text))
    {
        args.IsValid = false;
        CustomValidator1.ErrorMessage = Column.RequiredErrorMessage;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 6 – CustomValidator1_ServerValidate method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listing 6&lt;/strong&gt; is the Custom validator method here all we are concerned with is making sure we have a valid file to upload, so we check the file type via its file extension and if it matched one from out Upload attribute the file can be uploaded but if not we invalidate the page and add a custom error to our Custom validator. Also if the field is a required field then we check to see if there is a file present either from an edit or from the FileUpload control.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;protected override void OnDataBinding(EventArgs e)
{
    base.OnDataBinding(e);

    //check if field has a value
    if (FieldValue == null)
        return;

    // when there is already a value in the FieldValue
    // then show the icon and label/hyperlink
    PlaceHolder1.Visible = true;

    // get the file extension
    String extension = FieldValueString.GetFileExtension();

    if (uploadAttribute.ShowHyperlink)
    {
        Label1.Visible = false;
        // open in new window
        HyperLink1.Target = &amp;quot;_blank&amp;quot;;
        HyperLink1.Text = FieldValueString.GetFileNameTitle();
        HyperLink1.NavigateUrl = VirtualPathUtility.AppendTrailingSlash(uploadAttribute.UploadFolder) + FieldValueString;
    }
    else
    {
        HyperLink1.Visible = false;
        Label1.Text = FieldValueString;
    }

    // show the icon
    if (!String.IsNullOrEmpty(extension))
    {
        // set the file type image
        if (!String.IsNullOrEmpty(uploadAttribute.ImagesFolder))
        {
            // get file type image from folder specified in
            Image1.ImageUrl = String.Format(&amp;quot;{0}{1}.{2}&amp;quot;,
                VirtualPathUtility.AppendTrailingSlash(uploadAttribute.ImagesFolder),
                extension,
                uploadAttribute.ImageExtension);
        }

        Image1.AlternateText = extension + &amp;quot; file&amp;quot;;

        // set width
        if (uploadAttribute.Width &amp;gt; 0)
            Image1.Width = uploadAttribute.Width;

        // set height
        if (uploadAttribute.Height &amp;gt; 0)
            Image1.Height = uploadAttribute.Height;
    }
    else
    {
        // if file has no extension then hide image
        Image1.Visible = false;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 7 – OnDataBinding event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the OnDataBinding event &lt;strong&gt;Listing 7&lt;/strong&gt; we first of all check to see if the FieldValue is null if it is we just return. If it’s not null then we show the place holder. New we have to determine if we are showing an Hyperlink or a Label for the name of the file. And lastly we check to see if we can show a icon to represent the uploaded file type. &lt;/p&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;The OnDataBinding event is the only place where we have access to the FieldValue in the field template code behind.&lt;/div&gt;



&lt;pre class="brush: csharp;"&gt;protected override void ExtractValues(IOrderedDictionary dictionary)
{
    // make sure file is valid
    if (FileUpload1.HasFile &amp;amp;&amp;amp; Page.IsValid)
    {
        // make sure we have the folder to upload the file to
        var uploadFolder = Server.MapPath(VirtualPathUtility.AppendTrailingSlash(uploadAttribute.UploadFolder));
        if(!Directory.Exists(uploadFolder))
            Directory.CreateDirectory(uploadFolder);

        // upload the file
        FileUpload1.SaveAs(uploadFolder + FileUpload1.FileName);

        // update the field with the filename
        dictionary[Column.Name] = ConvertEditedValue(FileUpload1.FileName);
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 8 – ExtractValues method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We make sure we have a file to upload and the there was no error from the custom validator, check that the upload folder exists and create it if not. We then save the file to the upload folder and update the data field.&lt;/p&gt;

&lt;h5&gt;Upload Image Field Template&lt;/h5&gt;

&lt;pre class="brush: csharp;"&gt;// show the uploaded image
Image1.ImageUrl = String.Format(&amp;quot;{0}{1}&amp;quot;, 
    VirtualPathUtility.AppendTrailingSlash(uploadAttribute.UploadFolder), 
    FieldValueString);

// add alternate text
Image1.AlternateText = FieldValueString.GetFileNameTitle();&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 9 – OnDataBinding event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There only a few minor differences between UploadImage and UploadFile and they are in the section that displays the icon, in the UploadImage instead of displaying an Icon representing the file type we display the actual image.&lt;/p&gt;

&lt;h5&gt;Select Image Field Template&lt;/h5&gt;

&lt;p&gt;Here we are using a RadioButtonList and most of the work is done in the Page_Load &lt;strong&gt;Listing 10&lt;/strong&gt; &lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
    // get attributes
    var uploadAttribute = MetadataAttributes.GetAttribute&amp;lt;UploadAttribute&amp;gt;();
    if (uploadAttribute == null)
        throw new InvalidOperationException(&amp;quot;FileUpload must have valid uploadAttribute applied&amp;quot;);

    SetUpValidator(RequiredFieldValidator1);
    SetUpValidator(DynamicValidator1);

    // if no images folder return
    var dirInfo = new DirectoryInfo(Server.MapPath(uploadAttribute.ImagesFolder));
    if (!dirInfo.Exists)
    {
        RadioButtonList1.Visible = false;
        return;
    }

    if (RadioButtonList1.Items.Count == 0)
    {
        // get a list of images in the ImageUrlAttribute folder
        var imagesFolder = ResolveUrl(uploadAttribute.ImagesFolder);
        var files = dirInfo.GetFiles(String.Format(&amp;quot;*.{0}&amp;quot;, uploadAttribute.ImageExtension));

        foreach (FileInfo file in files)
        {
            // size image to uploadAttribute
            var imgString = new StringBuilder();

            imgString.Append(
                String.Format(&amp;quot;&amp;lt;img src='{0}' alt='{1}' &amp;quot;,
                    imagesFolder + file.Name,
                    file.Name.GetFileNameTitle()
               ));

            if (uploadAttribute.Width &amp;gt; 0)
                imgString.Append(String.Format(&amp;quot;width='{0}' &amp;quot;, uploadAttribute.Width));

            if (uploadAttribute.Height &amp;gt; 0)
                imgString.Append(String.Format(&amp;quot;height='{0}' &amp;quot;, uploadAttribute.Height));

            imgString.Append(&amp;quot; /&amp;gt;&amp;quot;);

            // embed image in the radio button
            var listItem = new ListItem(imgString.ToString(), file.Name);
            listItem.Attributes.Add(&amp;quot;title&amp;quot;, file.Name.GetFileNameTitle());

            this.RadioButtonList1.Items.Add(listItem);
        }
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 10 – Page_Load&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here we get a list of file filtered by the file extension supplied by the Upload attribute the we populate the RadioButtonList with this list. it get a little clever as we add some html mark-up into the Text value of each ListItem added to the RadioButtonList showing the Image to choice.&lt;/p&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;Setting the images folder up you will need to place your selection of images for the user to choose from into the folder and name them appropriately as the file name will be used for the tool tip and be stored in the DB as the value for the selection. &lt;/div&gt;

&lt;h5&gt;Date Picker&amp;#160; Field Template&lt;/h5&gt;

&lt;p&gt;All I have done here is add an Ajax Control Toolkit CalendarExtender to the page and set it up.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;&amp;lt;asp:TextBox 
    ID=&amp;quot;TextBox1&amp;quot; 
    runat=&amp;quot;server&amp;quot; 
    CssClass=&amp;quot;DDTextBox&amp;quot; 
    Text=&amp;quot;&amp;lt;%# FieldValueEditString %&amp;gt;&amp;quot; 
    Columns=&amp;quot;20&amp;quot;&amp;gt;
&amp;lt;/asp:TextBox&amp;gt;
&amp;lt;ajaxToolkit:CalendarExtender 
    ID=&amp;quot;TextBox1_CalendarExtender&amp;quot; 
    runat=&amp;quot;server&amp;quot; 
    Enabled=&amp;quot;True&amp;quot;
    TargetControlID=&amp;quot;TextBox1&amp;quot;&amp;gt;
&amp;lt;/ajaxToolkit:CalendarExtender&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 11 – Date with Calendar Extender&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;private readonly static String DATE_FORMAT = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern

protected void Page_Load(object sender, EventArgs e)
{
    TextBox1_CalendarExtender.Format = DATE_FORMAT;
    TextBox1.ToolTip = Column.Description;

    SetUpValidator(RequiredFieldValidator1);
    SetUpValidator(RegularExpressionValidator1);
    SetUpValidator(DynamicValidator1);
    SetUpCustomValidator(DateValidator);
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listign 12 – Page_Load&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All I’ve had to do is make sure the CalendarExtender matches the localised date time format, we now get a nice data picker.&lt;/p&gt;

&lt;h5&gt;Sample Metadata&lt;/h5&gt;

&lt;pre class="brush: csharp;"&gt;[MetadataTypeAttribute(typeof(File.FileMetadata))]
public partial class File
{
    internal sealed class FileMetadata
    {
        public int ID { get; set; }
        public string Description { get; set; }

        [Upload(
            FileTypes = new String[] { &amp;quot;doc&amp;quot;, &amp;quot;xls&amp;quot; },
            UploadFolder = &amp;quot;~/FileUploads/&amp;quot;,
            ImagesFolder = &amp;quot;~/images/&amp;quot;,
            ShowHyperlink = true,
            ImageExtension = &amp;quot;png&amp;quot;,
            Height = 30)]
        [UIHint(&amp;quot;UploadFile&amp;quot;)]
        public string FileName { get; set; }

        [Upload(
            FileTypes = new String[] { &amp;quot;png&amp;quot;, &amp;quot;jpg&amp;quot;, &amp;quot;jpeg&amp;quot; },
            UploadFolder = &amp;quot;~/ImageUploads/&amp;quot;,
            ShowHyperlink = true,
            ImageExtension = &amp;quot;png&amp;quot;,
            Height = 30)]
        [UIHint(&amp;quot;UploadImage&amp;quot;)]
        public string ImageName { get; set; }

        [Upload(
            ImagesFolder = &amp;quot;~/ImageSelection/&amp;quot;,
            ImageExtension = &amp;quot;png&amp;quot;,
            Height = 30)]
        [UIHint(&amp;quot;SelectImage&amp;quot;)]
        public string Selection { get; set; }

        [DataType(DataType.Date)]
        public DateTime DateCreated { get; set; }

    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 13 – sample metadata&lt;/strong&gt;&lt;/p&gt;

&lt;h5&gt;Download NuGet Package&lt;/h5&gt;

&lt;p&gt;&lt;a href="http://nuget.org/List/Packages/NotAClue.DynamicData.CustomFieldTemplates" target="_blank"&gt;Dynamic Data Custom Field Templates - 1.0&lt;/a&gt;&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/IueOYgH6JNg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/409909221399298636/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=409909221399298636&amp;isPopup=true" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/409909221399298636?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/409909221399298636?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/IueOYgH6JNg/custom-field-templates-on-nuget.html" title="Custom Field Templates On NuGet" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-fxr5NbafOTw/ThD6lIiIVYI/AAAAAAAAA_E/o_tGs8bT7iw/s72-c/CustomFieldTemplates%25255B5%25255D.png?imgmax=800" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/07/custom-field-templates-on-nuget.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMMRXY4eCp7ImA9WhZaEko.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-7974112223867322289</id><published>2011-06-28T16:21:00.001+01:00</published><updated>2011-06-28T16:21:24.830+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-28T16:21:24.830+01:00</app:edited><title>Autocomplete ForeignKey Field Template Now on NuGet</title><content type="html">&lt;p&gt;I have just added the ForeignKey field template based on the old Futures Autocomplete filter to &lt;a href="http://nuget.org" target="_blank"&gt;NuGet&lt;/a&gt; at &lt;a title="http://nuget.org/List/Packages/NotAClue.DynamicData.AutocompleteForeignKey" href="http://nuget.org/List/Packages/NotAClue.DynamicData.AutocompleteForeignKey"&gt;NotAClue.DynamicData.AutocompleteForeignKey&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="NotAClue.DynamicData.AutocompleteForeignKeySample" border="0" alt="NotAClue.DynamicData.AutocompleteForeignKeySample" src="http://lh5.ggpht.com/-EFgoosoTQbo/TgnxdPSjWfI/AAAAAAAAA_A/t0aGGWpQQDg/NotAClue.DynamicData.AutocompleteForeignKeySample%25255B5%25255D.png?imgmax=800" width="305" height="116" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Autocomplete in action&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;All you need is to add a UIHint attribute to the to set the field template, &lt;/p&gt;  &lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;only works on Foreign Key columns&lt;/div&gt;    &lt;p&gt;you can als0 set the number of characters you need to type before autocomplete kicks in.&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;[UIHint(&amp;quot;Autocomplete&amp;quot;, null, &amp;quot;MinimumPrefixLength&amp;quot;,2)]
public Supplier Supplier { get; set; }&lt;/pre&gt;

&lt;p&gt;By setting the MinimumPrefixLength in the UIHint’s ControlParameters.
  &lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/5FN96oxLPUE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/7974112223867322289/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=7974112223867322289&amp;isPopup=true" title="14 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/7974112223867322289?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/7974112223867322289?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/5FN96oxLPUE/autocomplete-foreignkey-field-template.html" title="Autocomplete ForeignKey Field Template Now on NuGet" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-EFgoosoTQbo/TgnxdPSjWfI/AAAAAAAAA_A/t0aGGWpQQDg/s72-c/NotAClue.DynamicData.AutocompleteForeignKeySample%25255B5%25255D.png?imgmax=800" height="72" width="72" /><thr:total>14</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/06/autocomplete-foreignkey-field-template.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYDRH06cSp7ImA9WhZaEU4.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-6708547348741029033</id><published>2011-06-27T02:13:00.001+01:00</published><updated>2011-06-27T02:29:35.319+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-27T02:29:35.319+01:00</app:edited><title>My Classic Cascading Filters and Field Templates on NuGet</title><content type="html">&lt;p&gt;I’ve just released my classic Cascading Filters and Field Templates on &lt;a href="http://nuget.org" target="_blank"&gt;NuGet&lt;/a&gt; for ease of install supports both Entity Framework and Linq to SQL.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-rljYP-Oyh7Q/TgfZPPfNgLI/AAAAAAAAA-4/ZJDDFI2UJrs/s1600-h/DynamicDataCascade100x100%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="DynamicDataCascade100x100" border="0" alt="DynamicDataCascade100x100" src="http://lh4.ggpht.com/-IP53h4yDkAw/TgfZPsci0pI/AAAAAAAAA-8/9jKpcE8LjS0/DynamicDataCascade100x100_thumb%25255B2%25255D.png?imgmax=800" width="100" height="87" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Dynamic Data Filters and Field Templates&lt;/strong&gt;&lt;/p&gt;  &lt;h5&gt;Sample Metadata&lt;/h5&gt;  &lt;pre class="brush: csharp;"&gt;[MetadataTypeAttribute(typeof(Vehicle.VehicleMetadata))]
public partial class Vehicle
{
    internal sealed class VehicleMetadata
    {
        public int Id { get; set; }
        public int ManufacturerId { get; set; }
        public int VehicleTypeId { get; set; }
        public int ModelId { get; set; }
        public int StyleId { get; set; }

        [Display(Order = 0)]
        public String Name { get; set; }

        /// &amp;lt;summary&amp;gt;
        /// Note for cascade to work correctly
        /// fields must be in cascade order Parent-&amp;gt;Child
        /// &amp;lt;/summary&amp;gt;
        [FilterUIHint(&amp;quot;CascadingForeignKey&amp;quot;)]
        [UIHint(&amp;quot;CascadingForeignKey&amp;quot;)]
        [Filter(Order = 0)]
        [Display(Order = 1)]
        public Manufacturer Manufacturer { get; set; }

        [FilterUIHint(&amp;quot;CascadingForeignKey&amp;quot;)]
        [UIHint(&amp;quot;CascadingForeignKey&amp;quot;)]
        [Cascade(&amp;quot;Manufacturer&amp;quot;)]
        [Filter(Order = 1)]
        [Display(Order = 2)]
        public VehicleType VehicleType { get; set; }

        [FilterUIHint(&amp;quot;CascadingForeignKey&amp;quot;)]
        [UIHint(&amp;quot;CascadingForeignKey&amp;quot;)]
        [Cascade(&amp;quot;VehicleType&amp;quot;)]
        [Filter(Order = 2)]
        [Display(Order = 3)]
        public Model Model { get; set; }

        [FilterUIHint(&amp;quot;CascadingForeignKey&amp;quot;)]
        [UIHint(&amp;quot;CascadingForeignKey&amp;quot;)]
        [Cascade(&amp;quot;Model&amp;quot;)]
        [Filter(Order = 3)]
        [Display(Order = 4)]
        public Style Style { get; set; }

    }
}&lt;/pre&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;For cascading to work each child must follow in order Parent-&amp;gt;Child note the Ordering of both filters and fields to facilitate the cascade. &lt;/div&gt;

&lt;p&gt;Next up are hierarchical cascade field templates&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/tMlKsRf6qSw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/6708547348741029033/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=6708547348741029033&amp;isPopup=true" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6708547348741029033?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6708547348741029033?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/tMlKsRf6qSw/my-classic-cascading-filters-and-filed.html" title="My Classic Cascading Filters and Field Templates on NuGet" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/-IP53h4yDkAw/TgfZPsci0pI/AAAAAAAAA-8/9jKpcE8LjS0/s72-c/DynamicDataCascade100x100_thumb%25255B2%25255D.png?imgmax=800" height="72" width="72" /><thr:total>8</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/06/my-classic-cascading-filters-and-filed.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIGSH49eSp7ImA9WhZbF0U.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-6427776880622752333</id><published>2011-06-23T01:05:00.001+01:00</published><updated>2011-06-23T01:05:29.061+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-23T01:05:29.061+01:00</app:edited><title>Links to Sample Down :(</title><content type="html">&lt;p&gt;It would appear that &lt;a href="http://live.com"&gt;Live.com&lt;/a&gt; have done some reorganisation of my SkyDrive for me &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-disappointedsmile" alt="Disappointed smile" src="http://lh6.ggpht.com/-RbZ3-H_MG_U/TgKDSPvPP-I/AAAAAAAAA-0/dPrWkwfknT0/wlEmoticon-disappointedsmile%25255B2%25255D.png?imgmax=800" /&gt; and now ALL the links to my samples are broken, you can see my public folder here &lt;a href="https://skydrive.live.com/?wa=wsignin1.0&amp;amp;cid=96845e7b0fac1eed#cid=96845E7B0FAC1EED&amp;amp;id=96845E7B0FAC1EED%21112" target="_blank"&gt;Public&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Sorry for this but it is out of my control.&lt;/p&gt;  &lt;p&gt;Anyway on a positive note I plan to have all my old samples update to .Net 4 and on &lt;a href="http://nuget.com" target="_blank"&gt;NuGet&lt;/a&gt; as we go forward, I will post a pole with a list of proposed samples to get a vote what people want most.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/PBWLoNVJlq0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/6427776880622752333/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=6427776880622752333&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6427776880622752333?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6427776880622752333?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/PBWLoNVJlq0/links-to-sample-down.html" title="Links to Sample Down :(" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/-RbZ3-H_MG_U/TgKDSPvPP-I/AAAAAAAAA-0/dPrWkwfknT0/s72-c/wlEmoticon-disappointedsmile%25255B2%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/06/links-to-sample-down.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QGQHczcCp7ImA9WhZbF0k.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-4916347066673037271</id><published>2011-06-22T13:20:00.001+01:00</published><updated>2011-06-22T13:22:01.988+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-22T13:22:01.988+01:00</app:edited><title>Filter NuGet Package updated</title><content type="html">&lt;h5&gt;&lt;a href="http://nuget.org/List/Packages/DynamicData.ThirteenFilters"&gt;&lt;font style="font-weight: normal"&gt;Thirteen Dynamic Data Custom Filters&lt;/font&gt;&lt;/a&gt;&lt;font style="font-weight: normal"&gt; has been updated to &lt;/font&gt;&lt;a href="http://nuget.org/List/Packages/DynamicData.CustomFilters"&gt;&lt;font style="font-weight: normal"&gt;Dynamic Data 15 Custom Filters&lt;/font&gt;&lt;/a&gt;&lt;font style="font-weight: normal"&gt; and the PackageId is now “DynamicData.CustomFilters”, makes more sense than “DynamicData.ThirteenFilters” especially it now had 15 filters instead of 13.&lt;/font&gt;&lt;/h5&gt;  &lt;p&gt;I have added&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;GreaterThanOrEqual &lt;/li&gt;    &lt;li&gt;LessThanOrEqual &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Sample Metadata&lt;/h5&gt;  &lt;pre class="brush: csharp;"&gt;[MetadataTypeAttribute(typeof(Product.ProductMetadata))]
public partial class Product
{
    internal sealed class ProductMetadata
    {
        [FilterUIHint(&amp;quot;MultiForeignKey&amp;quot;)]
        public Category Category { get; set; }

        public Nullable&amp;lt;int&amp;gt; CategoryID { get; set; }

        public bool Discontinued { get; set; }

        public EntityCollection&amp;lt;Order_Detail&amp;gt; Order_Details { get; set; }

        public int ProductID { get; set; }

        public string ProductName { get; set; }

        public string QuantityPerUnit { get; set; }

        public Nullable&amp;lt;short&amp;gt; ReorderLevel { get; set; }

        public Supplier Supplier { get; set; }

        public Nullable&amp;lt;int&amp;gt; SupplierID { get; set; }

        [FilterUIHint(&amp;quot;GreaterThanOrEqual&amp;quot;)]
        public Nullable&amp;lt;decimal&amp;gt; UnitPrice { get; set; }

        [FilterUIHint(&amp;quot;LessThanOrEqual&amp;quot;)]
        public Nullable&amp;lt;short&amp;gt; UnitsInStock { get; set; }

        public Nullable&amp;lt;short&amp;gt; UnitsOnOrder { get; set; }
    }
}&lt;/pre&gt;

&lt;p&gt;Much fun I expect there will be more soon.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/qpU-A62cYwY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/4916347066673037271/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=4916347066673037271&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/4916347066673037271?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/4916347066673037271?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/qpU-A62cYwY/filter-nuget-package-updated.html" title="Filter NuGet Package updated" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/06/filter-nuget-package-updated.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkAHQXgzfCp7ImA9WhZbF04.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-7594345230616940738</id><published>2011-06-21T22:31:00.001+01:00</published><updated>2011-06-22T11:32:10.684+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-22T11:32:10.684+01:00</app:edited><title>More NuGet</title><content type="html">&lt;p&gt;I have just put up the the first instalment of my Dynamic Data Extensions this version (V1.0) we have&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;HideColumnIn attribute see &lt;a href="http://csharpbits.notaclue.net/2010/02/new-way-to-do-column-generation-in.html"&gt;A New Way To Do Column Generation in Dynamic Data 4&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;ShowColumnOnlyIn attribute does what it says on the tin shows column in particular page templates &lt;/li&gt;    &lt;li&gt;Filter attribute (I have only implemented the Order property as yet) this allows you to set the filter order. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Dynamic Data Extensions" border="0" alt="Dynamic Data Extensions" src="http://lh5.ggpht.com/-ZYKjzOiMEi4/TgEOii-dVEI/AAAAAAAAA-w/7kZs-3TP-xY/DynamicDataExtensions100x100%25255B3%25255D.png?imgmax=800" width="100" height="93" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Dynamic Data Extensions&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Search for DynamicData.Extensions on &lt;a href="http://nuget.org"&gt;NuGet&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Example Metadata&lt;/h4&gt;  &lt;pre class="brush: csharp;"&gt;[MetadataTypeAttribute(typeof(Order.OrderMetadata))]
public partial class Order
{
    internal sealed class OrderMetadata
    {
        public string CustomerID { get; set; }
        public Nullable&amp;lt;int&amp;gt; EmployeeID { get; set; }
        public Nullable&amp;lt;int&amp;gt; ShipVia { get; set; }

        [ShowColumnOnlyIn(PageTemplate.List)]
        [ScaffoldColumn(true)]
        public int OrderID { get; set; }

        public Nullable&amp;lt;DateTime&amp;gt; OrderDate { get; set; }

        [HideColumnIn(PageTemplate.List | PageTemplate.Insert)]
        public Nullable&amp;lt;DateTime&amp;gt; RequiredDate { get; set; }

        [HideColumnIn(PageTemplate.List | PageTemplate.Insert)]
        public Nullable&amp;lt;DateTime&amp;gt; ShippedDate { get; set; }
        public Nullable&amp;lt;decimal&amp;gt; Freight { get; set; }
        public string ShipName { get; set; }
        public string ShipAddress { get; set; }
        public string ShipCity { get; set; }
        public string ShipCountry { get; set; }
        public string ShipRegion { get; set; }
        public string ShipPostalCode { get; set; }

        [Filter(Order=2)]
        public Customer Customer { get; set; }
        [Filter(Order = 1)]
        public Employee Employee { get; set; }
        [Filter(Order = 3)]
        public Shipper Shipper { get; set; }

        public EntityCollection&amp;lt;Order_Detail&amp;gt; Order_Details { get; set; }
    }
}&lt;/pre&gt;

&lt;p&gt;Here you can see all three custom attributes in action.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;strong&gt;HideColumnInAttribute&lt;/strong&gt; hides columns in page templates (note the use of the ‘|’ OR operator to allows multiple pages to be selected. &lt;/li&gt;

  &lt;li&gt;The &lt;strong&gt;ShowColumnOnlyInAttribute&lt;/strong&gt; does the opposite and only shows columns in selected pages.&lt;/li&gt;

  &lt;li&gt;The &lt;strong&gt;FilterAttribute&lt;/strong&gt; here sets the order to display the filters on the list page (Note there are other properties on Filter that are not yet implemented).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next up on &lt;a href="http://nuget.org"&gt;NuGet&lt;/a&gt; are both of my original cascade and my hierarchical cascading field templates. 

  &lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/D3byZL8ILC0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/7594345230616940738/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=7594345230616940738&amp;isPopup=true" title="21 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/7594345230616940738?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/7594345230616940738?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/D3byZL8ILC0/more-nuget.html" title="More NuGet" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-ZYKjzOiMEi4/TgEOii-dVEI/AAAAAAAAA-w/7kZs-3TP-xY/s72-c/DynamicDataExtensions100x100%25255B3%25255D.png?imgmax=800" height="72" width="72" /><thr:total>21</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/06/more-nuget.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UCQH85eSp7ImA9WhZbFkk.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-5255406502177164317</id><published>2011-06-19T08:54:00.001+01:00</published><updated>2011-06-21T09:34:21.121+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-21T09:34:21.121+01:00</app:edited><title>Web Application Project vs. Website</title><content type="html">&lt;p&gt;I have a poll &lt;a href="http://twtpoll.com/tkuwkm"&gt;here&lt;/a&gt; all I’m asking is what do you prefer?&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/fG1euPIZv5U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/5255406502177164317/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=5255406502177164317&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/5255406502177164317?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/5255406502177164317?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/fG1euPIZv5U/web-application-project-vs-website.html" title="Web Application Project vs. Website" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/06/web-application-project-vs-website.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUYGSHw_eyp7ImA9WhdSGEw.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-853277950335485588</id><published>2011-06-10T17:18:00.001+01:00</published><updated>2011-07-28T01:32:09.243+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T01:32:09.243+01:00</app:edited><title>A Second NuGet Package for Dynamic Data</title><content type="html">&lt;p&gt;&lt;a href="http://nuget.org/List/Packages/NotAClue.DynamicData.CustomFilters"&gt;Dynamic Data 15 Custom Filters&lt;/a&gt; is now on &lt;a href="http://nuget.org"&gt;NuGet&lt;/a&gt;&amp;#160; this package add thirteen filters to your Web Application Project see &lt;a href="http://csharpbits.notaclue.net/2010/11/five-cool-filters-for-dynamic-data-4.html"&gt;Five Cool Filters for Dynamic Data 4&lt;/a&gt; I have added some more filters to that list;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;AutoComplete – is ForeignKey filter but pre-filters results by what users has typed in. &lt;/li&gt;    &lt;li&gt;Contains – equivalent to T-SQL LIKE ‘%text%’ &lt;/li&gt;    &lt;li&gt;DateFrom – All Dates greater than or equal to the selected date. &lt;/li&gt;    &lt;li&gt;DateRange – A range of dates &lt;/li&gt;    &lt;li&gt;DateTo – Less than or equal to the selected date. &lt;/li&gt;    &lt;li&gt;EndsWith – Ends with entered text. &lt;/li&gt;    &lt;li&gt;GreaterThan – Greater than entered value &lt;/li&gt;    &lt;li&gt;LessThan – Less than entered value &lt;/li&gt;    &lt;li&gt;MultiForeignKey – allows multiple ForeignKey values to be selected. &lt;/li&gt;    &lt;li&gt;Range – a range of values &lt;/li&gt;    &lt;li&gt;StartWith – Starts with entered text. &lt;/li&gt;    &lt;li&gt;Where – is equal to entered text &lt;/li&gt;    &lt;li&gt;WhereDropdownList – a dropdown list of values from column to filter by. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;This has a few more exciting bits that &lt;a href="http://nuget.org"&gt;NuGet&lt;/a&gt; offers &lt;strong&gt;Dependencies&lt;/strong&gt; and &lt;strong&gt;Framework Assembly References&lt;/strong&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;, here this package there is dependency upon Ajax Control Toolkit &lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency id=&amp;quot;AjaxControlToolkit&amp;quot; version=&amp;quot;4.1.50508&amp;quot; /&amp;gt;
&amp;lt;/dependencies&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Framework Assembly References&lt;/strong&gt; – is requirement for an assembly reference from the GAC&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;frameworkAssemblies&amp;gt;
    &amp;lt;frameworkAssembly assemblyName=&amp;quot;System.Data.Entity&amp;quot; targetFramework=&amp;quot;net40&amp;quot; /&amp;gt;
&amp;lt;/frameworkAssemblies&amp;gt;&lt;/pre&gt;

&lt;p&gt;This give great flexibility without resorting to PowerShell.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://nuget.org"&gt;NuGet&lt;/a&gt; truly is awesome!&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/RKXWkooMSkE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/853277950335485588/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=853277950335485588&amp;isPopup=true" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/853277950335485588?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/853277950335485588?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/RKXWkooMSkE/second-nuget-package-for-dynamic-data.html" title="A Second NuGet Package for Dynamic Data" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/06/second-nuget-package-for-dynamic-data.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcFRnw-eCp7ImA9WhZUF0Q.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-8664451811820405353</id><published>2011-06-10T14:52:00.001+01:00</published><updated>2011-06-11T13:56:57.250+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-11T13:56:57.250+01:00</app:edited><title>NuGet for Dynamic Data – First Package</title><content type="html">&lt;p&gt;I have just added my first &lt;a href="http://nuget.org/" target="_blank"&gt;NuGet&lt;/a&gt; package, and you may no know what &lt;a href="http://nuget.org/" target="_blank"&gt;NuGet&lt;/a&gt; is? so what is &lt;a href="http://nuget.org/" target="_blank"&gt;NuGet&lt;/a&gt; it’s a Package management add on for Visual Studio 2010 and above (maybe more as it is integrated with Windows PowerShell).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-HDPiRPh4hFs/TfIhgulnL3I/AAAAAAAAA-Y/U_1VHSgqE5Y/s1600-h/Install%252520NuGet%25255B10%25255D.png" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Install NuGet" border="0" alt="Install NuGet" src="http://lh3.ggpht.com/-gYRkJcyHS2s/TfIhiP_A-ZI/AAAAAAAAA-c/Rr3aZgdVeMU/Install%252520NuGet_thumb%25255B8%25255D.png?imgmax=800" width="640" height="300" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 1 – Install NuGet&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;See &lt;a href="http://docs.nuget.org/docs/start-here/installing-nuget" target="_blank"&gt;Installing NuGet&lt;/a&gt; and then you will need &lt;a href="http://nuget.codeplex.com/releases/view/58939" target="_blank"&gt;NuGet.exe Command Line&lt;/a&gt; and or &lt;a href="http://nuget.codeplex.com/releases/view/59864" target="_blank"&gt;NuGet Package Explorer v1.1&lt;/a&gt; this is the GUI version (and unlike &lt;a href="http://www.hanselman.com/blog/" target="_blank"&gt;Scott Hanselman&lt;/a&gt;&lt;strong&gt;&lt;/strong&gt; I like the GUI and try to avoid the DOS as much as possible I’m with &lt;a href="http://haacked.com/" target="_blank"&gt;Phil Haack&lt;/a&gt; on that see &lt;a href="http://channel9.msdn.com/events/MIX/MIX11/FRM09"&gt;NuGet In Depth: Empowering Open Source on the .NET Platform&lt;/a&gt; on Channel9) and can do a lot of what the command line tool does.&lt;/p&gt;  &lt;p&gt;You can get loads on information on &lt;a href="http://docs.nuget.org/" target="_blank"&gt;NuGet Docs&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;OK so I’m going to assume your all setup and ready to go.&lt;/p&gt;  &lt;h4&gt;Creating the Package&lt;/h4&gt;  &lt;p&gt;NuGet has some &lt;a href="http://docs.nuget.org/docs/creating-packages/package-conventions"&gt;Package Conventions&lt;/a&gt; and we should follow them (I’ll not explain them just go and have a read as documentation can be updated from time to time) for out package lets first of all look at what we want to package.&lt;/p&gt;  &lt;p&gt;For this Package I want to package up &lt;a href="http://blogs.msdn.com/b/scothu/" target="_blank"&gt;Scott Hunter’s&lt;/a&gt; old &lt;a href="http://blogs.msdn.com/b/scothu/archive/2008/01/14/sample.aspx"&gt;Sample for Displaying Images from the Database using Dynamic Data&lt;/a&gt; (DBImage) and it’s update &lt;a href="http://blogs.msdn.com/b/scothu/archive/2008/04/09/sample-for-displaying-images-updated-screencast.aspx"&gt;Sample for Displaying Images Updated + Screencast&lt;/a&gt; note the latest version of this is in the old &lt;a href="http://aspnet.codeplex.com/releases/view/14475"&gt;Dynamic Data Futures VS2008 SP1 RTM&lt;/a&gt; for DD 3.51 SP1.&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Embedded image field template" border="0" alt="Embedded image field template" src="http://lh3.ggpht.com/-CfUN0PLhSn0/TfIhi_fxR5I/AAAAAAAAA-g/paq68TI8xL8/Embedded%252520image%252520field%252520template%25255B9%25255D.png?imgmax=800" width="576" height="342" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 2 – Embedded image field template&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This consists of several parts;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Read-Only field template &lt;/li&gt;    &lt;li&gt;Edit field template &lt;/li&gt;    &lt;li&gt;Image Format attribute &lt;/li&gt;    &lt;li&gt;Linq extension methods &lt;/li&gt;    &lt;li&gt;Image http handler. &lt;/li&gt;    &lt;li&gt;Web.Config settings &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I have decided to keep things simple for out first &lt;a href="http://nuget.org/" target="_blank"&gt;NuGet&lt;/a&gt; Package and all the above will go into one package some of the above could be shared and as such we could spilt it between several packages and have dependencies but we will keep it simple for now.&lt;/p&gt;  &lt;p&gt;so to build our package there are some things we need to know like where do we put our files;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Package folder structure" border="0" alt="Package folder structure" src="http://lh6.ggpht.com/-gfr7UgxjTCc/TfIhjdE-BJI/AAAAAAAAA-k/tPok4wdO80s/Package%252520folder%252520structure%25255B20%25255D.png?imgmax=800" width="514" height="335" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 3 – Simple Package folder structure&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;As you can see I have broken the folder structure into three parts, the first part is quite simple, it’s the readme file which will give basic information about the package. &lt;/p&gt;  &lt;h5&gt;&lt;/h5&gt;  &lt;h5&gt;Content (files to be copied on install)&lt;/h5&gt;  &lt;p&gt;Here you can have three types of file;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Copied as is with no changes. &lt;/li&gt;    &lt;li&gt;Transform files (see &lt;a href="http://docs.nuget.org/docs/creating-packages/configuration-file-and-source-code-transformations" target="_blank"&gt;Configuration File and Source Code Transformations&lt;/a&gt; for more info)       &lt;ul&gt;       &lt;li&gt;.transform or Configuration File Transformations &lt;/li&gt;        &lt;li&gt;.pp or Source Code Transformations &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The “.transform” files transform &lt;em&gt;web.config&lt;/em&gt; or &lt;em&gt;app.config&lt;/em&gt; files by adding/merging their content with the project’s configuration file. &lt;/p&gt;  &lt;p&gt;While the “.pp” files are files that are transformed as they are copied to the project in the same folder structure they have in the package. These files are a little more complex than the configuration files, as they have Visual Studio project properties in the code and these are used to transform the code files during install ((see &lt;a href="http://docs.nuget.org/docs/creating-packages/configuration-file-and-source-code-transformations" target="_blank"&gt;Configuration File and Source Code Transformations&lt;/a&gt; and the &lt;strong&gt;Specifying Source Code Transformations&lt;/strong&gt; section for more info).&lt;/p&gt;  &lt;h5&gt;Lib Folder&lt;/h5&gt;  &lt;p&gt;This folder contains any DLLs that are required, not that the “net40” subfolder this indicates that the DLL supports .Net 4 you could have several version that support different versions of the .Net framework here we will just support .Net 4.&lt;/p&gt;  &lt;h5&gt;Next&lt;/h5&gt;  &lt;p&gt;Note this is just the basic of where you need to put files for your package to work.&lt;/p&gt;  &lt;p&gt;now we have out files ready in a folder structure we need to create our “nuspec” file, this is an XML file containing details (the manifest) about the package you can manually create this or you can use &lt;strong&gt;NuGet Package Explorer&lt;/strong&gt; to create this see &lt;a href="http://docs.nuget.org/docs/creating-packages/using-a-gui-to-build-packages" target="_blank"&gt;Using A GUI (Package Explorer) to build packages&lt;/a&gt; once created you can manually edit the “nuspec” file manually if you like.&lt;/p&gt;  &lt;p&gt;You then place your “nuspec” file in the root of the package folder structure or if you follow &lt;a href="http://docs.nuget.org/docs/creating-packages/using-a-gui-to-build-packages" target="_blank"&gt;Using A GUI (Package Explorer) to build packages&lt;/a&gt; you can add them directly.&lt;/p&gt;  &lt;p&gt;Once done you just publish and it works!&lt;/p&gt;  &lt;h5&gt;Next steps&lt;/h5&gt;  &lt;p&gt;The real power come with PowerShell scripts see &lt;a href="http://channel9.msdn.com/Events/MIX/MIX11/FRM13"&gt;Scaffolding – ASP.NET, NuGet, Entity Framework Code First and More&lt;/a&gt; with &lt;a href="http://blog.stevensanderson.com/" target="_blank"&gt;Steve Sanderson&lt;/a&gt; he shows what you can really do.&lt;/p&gt;  &lt;p&gt;I am going to add more complex post here as I discover new and interesting feature of &lt;a href="http://nuget.org/" target="_blank"&gt;NuGet&lt;/a&gt;.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/6MgLwMfYxcc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/8664451811820405353/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=8664451811820405353&amp;isPopup=true" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/8664451811820405353?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/8664451811820405353?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/6MgLwMfYxcc/nuget-for-dynamic-data-first-package.html" title="NuGet for Dynamic Data – First Package" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-gYRkJcyHS2s/TfIhiP_A-ZI/AAAAAAAAA-c/Rr3aZgdVeMU/s72-c/Install%252520NuGet_thumb%25255B8%25255D.png?imgmax=800" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/06/nuget-for-dynamic-data-first-package.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04NQX46eSp7ImA9WhZQFUk.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-7545920281970746451</id><published>2011-03-31T13:04:00.000+01:00</published><updated>2011-04-23T09:06:30.011+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-23T09:06:30.011+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".Net 4.0" /><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic Data" /><category scheme="http://www.blogger.com/atom/ns#" term="Entity Templates" /><category scheme="http://www.blogger.com/atom/ns#" term="Attributes" /><title>Custom Entity Templates – Dynamic Data 4</title><content type="html">&lt;p&gt;In Dynamic Data 4 we have &lt;em&gt;Entity Templates &lt;/em&gt;these are great for customizing layout of tables (see &lt;a href="http://msdn.microsoft.com/en-us/library/dd723645(VS.100).aspx"&gt;Walkthrough: Customizing Table Layout Using &lt;em&gt;Entity Templates&lt;/em&gt;&lt;/a&gt;&lt;strong&gt;&lt;/strong&gt;).&amp;#160; At the moment you will have to create a Custom Entity template for each table, but not only that you will need to create a set of three (&lt;em&gt;Template&lt;/em&gt;, &lt;em&gt;Template&lt;/em&gt;_Edit and &lt;em&gt;Template&lt;/em&gt;_Insert) and that can be useful to have different layout for each view. &lt;/p&gt;  &lt;p&gt;But what if you want something different from the Default, (see &lt;a href="http://csharpbits.notaclue.net/2010/02/grouping-field-on-details-edit-and.html"&gt;Grouping Fields on Details, Edit and Insert with Dynamic Data 4, VS2010 and .Net 4.0 RC1&lt;/a&gt; my first custom Entity Template which then had to replace the Default and also had to have all three defined) but not on all your tables just on a selected few? &lt;/p&gt;  &lt;p&gt;I was inspired by Brian Pritchard’s post on the forum: &lt;a href="http://forums.asp.net/p/1443492/3277785.aspx"&gt;How to reduce code duplication when using Entity Template's&lt;/a&gt; for only having to create a single template that would switch between Read-Only, Edit and Insert modes.&lt;/p&gt;  &lt;p&gt;I want to go a little further:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Override the Default Entity Template with some sort of UIHint attribute. &lt;/li&gt;    &lt;li&gt;An only have to specify one template to keep things &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Detect if an Edit or Insert version of a template exists and use that. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So now we know out goal, let’s layout the ingredients for this recipe:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;An attribute to allow us to change the default Entity Template for any given Table. &lt;/li&gt;    &lt;li&gt;Custom entity factory to allow us to override normal entity behaviour like Brian Pritchard’s. &lt;/li&gt;    &lt;li&gt;A Custom dynamic Entity Template. &lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;The Attribute&lt;/h4&gt;  &lt;p&gt;I thought I would be able to use UIHint at class level but alas we have to hand craft our own, I want some of the same feature of UIHint specifically the Control Parameters collection so that we can pass extra information into our custom Entity Templates with out creating a plethora extra attribute each specific to it’s one Entity Template. (I’ve used the Control Parameters collection before in &lt;a href="http://csharpbits.notaclue.net/2009/07/dynamic-data-custom-field-template_28.html"&gt;Dynamic Data Custom Field Template – Values List, Take 2&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;The Attribute is relatively straight forward, the only complication is the &lt;em&gt;BuildControlParametersDictionary&lt;/em&gt; method which takes the &lt;em&gt;Object&lt;/em&gt; array passed in using the &lt;em&gt;params&lt;/em&gt; key word into a Key, Value Dictionary with some validation. Note we have also set this attribute to be only useable at Class level. &lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class EntityUIHintAttribute : Attribute
{
    private IDictionary&lt;string   , object&gt; _controlParameters;

    public IDictionary&lt;string   , object&gt; ControlParameters
    {
        get { return this._controlParameters; }
    }

    /// &lt;summary&gt;
    /// Gets or sets the UI hint.
    /// &lt;/summary&gt;
    /// &lt;value&gt;The UI hint.&lt;/value&gt;
    public String UIHint { get; private set; }

    public EntityUIHintAttribute(string uiHint) : this(uiHint, new object[0]) { }

    public EntityUIHintAttribute(string uiHint, params object[] controlParameters)
    {
        UIHint = uiHint;
        _controlParameters = BuildControlParametersDictionary(controlParameters);
    }

    public override object TypeId
    {
        get { return this; }
    }

    private IDictionary&lt;string   , object&gt; BuildControlParametersDictionary(object[] objArray)
    {
        IDictionary&lt;string   , object&gt; dictionary = new Dictionary&lt;string   , object&gt;();
        if ((objArray != null) &amp;amp;&amp;amp; (objArray.Length != 0))
        {
            if ((objArray.Length % 2) != 0)
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, &amp;quot;Need even number of control parameters.&amp;quot;, new object[0]));

            for (int i = 0; i &amp;lt; objArray.Length; i += 2)
            {
                object obj2 = objArray[i];
                object obj3 = objArray[i + 1];
                if (obj2 == null)
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, &amp;quot;Control parameter key is null.&amp;quot;, new object[] { i }));

                string key = obj2 as string;
                if (key == null)
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, &amp;quot;Control parameter key is not a string.&amp;quot;, new object[] { i, objArray[i].ToString() }));

                if (dictionary.ContainsKey(key))
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, &amp;quot;Control parameter key occurs more than once.&amp;quot;, new object[] { i, key }));

                dictionary[key] = obj3;
            }
        }
        return dictionary;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 1 – EntityUIHintAttribute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now we need a method to use this attribute to change the default Entity Template, this factory need to do two things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Change the Default Entity Template based on out new EntityUIHint attribute. &lt;/li&gt;

  &lt;li&gt;Intercept the template mode so that single Entity Template can be used with out having to have three versions. &lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="brush: csharp;"&gt;public class AdvancedEntityTemplateFactory : System.Web.DynamicData.EntityTemplateFactory
{
    public override string BuildEntityTemplateVirtualPath(string templateName, DataBoundControlMode mode)
    {
        var path = base.BuildEntityTemplateVirtualPath(templateName, mode);
        var editPath = base.BuildEntityTemplateVirtualPath(templateName, DataBoundControlMode.Edit);;
        var defaultPath = base.BuildEntityTemplateVirtualPath(templateName, DataBoundControlMode.ReadOnly); ;

        if (File.Exists(HttpContext.Current.Server.MapPath(path)))
            return path;

        if (mode == DataBoundControlMode.Insert &amp;amp;&amp;amp; File.Exists(HttpContext.Current.Server.MapPath(editPath)))
            return editPath;

        if (mode != DataBoundControlMode.ReadOnly &amp;amp;&amp;amp; File.Exists(HttpContext.Current.Server.MapPath(defaultPath)))
            return defaultPath;

        return path;
    }

    public override EntityTemplateUserControl CreateEntityTemplate(MetaTable table, DataBoundControlMode mode, string uiHint)
    {
        var et = table.GetAttribute&lt;entityuihintattribute&gt;();
        if (et != null &amp;amp;&amp;amp; !String.IsNullOrEmpty(et.UIHint))
            return base.CreateEntityTemplate(table, mode, et.UIHint);

        return base.CreateEntityTemplate(table, mode, uiHint);
    }

    public override string GetEntityTemplateVirtualPath(MetaTable table, DataBoundControlMode mode, string uiHint)
    {
        var et = table.GetAttribute&lt;entityuihintattribute&gt;();
        if (et != null &amp;amp;&amp;amp; !String.IsNullOrEmpty(et.UIHint))
            return base.GetEntityTemplateVirtualPath(table, mode, et.UIHint);

        return base.GetEntityTemplateVirtualPath(table, mode, uiHint);
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 2 – AdvancedEntityTemplateFactory&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listing 1&lt;/strong&gt; shows us out AdvancedEntityTemplateFactory, we fulfil task 1. in the methods &lt;em&gt;CreateEntityTemplate&lt;/em&gt; and &lt;em&gt;GetEntityTemplateVirtualPath&lt;/em&gt; where we check for the presence of a &lt;em&gt;EntityUIHintAttribute&lt;/em&gt; and if we find one then set the name of the template to the UIHint property.&lt;/p&gt;

&lt;p&gt;Task 2. is dealt with in the &lt;em&gt;BuildEntityTemplateVirtualPath&lt;/em&gt; where we check to see if the file exists, if so we just return the path as is, otherwise we strip out the&amp;#160; _Edit or _Insert from the path and return. &lt;/p&gt;

&lt;p&gt;The last thing we need is to wire up the AdvancedEntityTemplateFactory in Global.asax.cs&lt;/p&gt;

&lt;pre style="font-family: consolas"&gt;DefaultModel.EntityTemplateFactory = &lt;span style="color: blue"&gt;new&lt;/span&gt;&amp;#160;&lt;span style="color: #2b91af"&gt;AdvancedEntityTemplateFactory&lt;/span&gt;();&lt;/pre&gt;

&lt;p&gt;just before the RegisterContext in RegisterRoutes method.&lt;/p&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;The Custom Entity Template&lt;/h4&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_UUHjb9DZhJM/TM2sWRVrPUI/AAAAAAAAA6E/EDt0tJsZABI/s1600-h/MultiColumnEntityTemplate%5B9%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Multi Column Entity Template" border="0" alt="Multi Column Entity Template" src="http://lh5.ggpht.com/_UUHjb9DZhJM/TM2sW7NYWvI/AAAAAAAAA6I/0LWRtNUIv5U/MultiColumnEntityTemplate_thumb%5B5%5D.png?imgmax=800" width="779" height="445" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 1 – Multi Column Entity Template&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This entity template will be a multi column temp[late designed to give you a little more screen for your money &lt;img alt="Big Grin" src="http://us.i1.yimg.com/us.yimg.com/i/mesg/emoticons7/4.gif" /&gt; I have decided to pass the main parameters in via the EntityUIHint attribute’s Control Parameters, in &lt;strong&gt;Figure 2&lt;/strong&gt; you can see them in pairs.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_UUHjb9DZhJM/TM2sXlNu0FI/AAAAAAAAA6M/MpIk8J32yGw/s1600-h/ControlParameters%5B9%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Control Parameters" border="0" alt="Control Parameters" src="http://lh5.ggpht.com/_UUHjb9DZhJM/TM2sX3tk7tI/AAAAAAAAA6Q/L_da6y6EPss/ControlParameters_thumb%5B5%5D.png?imgmax=800" width="427" height="183" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 2 – Control Parameters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;“Columns”, 3 sets the number of column the MultiColumn entity template will show.&lt;/p&gt;

&lt;p&gt;The next two pairs are the Title and Field CSS classes.&lt;/p&gt;

&lt;p&gt;I’ve also decided to add the ability for some columns to span more then one cell in the table.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;[AttributeUsage(AttributeTargets.Property)]
public class MultiColumnAttribute : Attribute
{
    /// &lt;summary&gt;
    /// Gets or sets the column span.
    /// &lt;/summary&gt;
    /// &lt;value&gt;The column span.&lt;/value&gt;
    public int ColumnSpan { get; private set; }

    public static MultiColumnAttribute Default = new MultiColumnAttribute();

    public MultiColumnAttribute() 
    { 
        ColumnSpan = 1;
    }

    public MultiColumnAttribute(int columnSpan)
    {
        ColumnSpan = columnSpan;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 3 – MultiColumnAttribute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The use of Default for when we use the DefaultIfEmpty method in Linq (see my &lt;a href="http://csharpbits.notaclue.net/2009/01/writing-attribute-and-extension-methods.html"&gt;Writing Attributes and Extension Methods for Dynamic Data&lt;/a&gt; more info) this allows us to get an attribute even if one is not specified so now with thi sline of code &lt;/p&gt;

&lt;pre style="font-family: consolas"&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; totalNoOfCells = metaColumns.Select(c =&amp;gt; c.GetAttributeOrDefault&amp;lt;&lt;span style="color: #2b91af"&gt;MultiColumnAttribute&lt;/span&gt;&amp;gt;().ColumnSpan).Sum();&lt;/pre&gt;

&lt;p&gt;we can get the total number of cell required with some columns having a span of more than on column see &lt;strong&gt;Figure 1&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Finally our Multi Column entity template is completed in &lt;strong&gt;Listing 4&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;public partial class MultiColumnEntityTemplate : System.Web.DynamicData.EntityTemplateUserControl
{
    private const string COLUMNS = &amp;quot;Columns&amp;quot;;
    private const string TITLE_CSS_CLASS = &amp;quot;TitleCssClass&amp;quot;;
    private const string FIELD_CSS_CLASS = &amp;quot;FieldCssClass&amp;quot;;

    protected override void OnLoad(EventArgs e)
    {
        // get columns from table
        var metaColumns = Table.GetScaffoldColumns(Mode, ContainerType).ToList();

        // do not render any HTML table if there are no columns returned
        if (metaColumns.Count == 0)
            return;

        // default the HTML table columns and CSS class names
        int columns = 2;
        String titleCssClass = String.Empty;
        String fieldCssClass = String.Empty;

        // Get the CssClass for the title &amp;amp; Field from the attribute
        var entityUHint = Table.GetAttribute&lt;entityuihintattribute&gt;();
        if (entityUHint != null)
        {
            if (entityUHint.ControlParameters.Keys.Contains(COLUMNS))
                columns = (int)entityUHint.ControlParameters[COLUMNS];
            if (entityUHint.ControlParameters.Keys.Contains(TITLE_CSS_CLASS))
                titleCssClass = entityUHint.ControlParameters[TITLE_CSS_CLASS].ToString();
            if (entityUHint.ControlParameters.Keys.Contains(FIELD_CSS_CLASS))
                fieldCssClass = entityUHint.ControlParameters[FIELD_CSS_CLASS].ToString();
        }

        // start in the left column
        int col = 0;

        // create the header &amp;amp; data cells
        var headerRow = new HtmlTableRow();
        if (!String.IsNullOrEmpty(titleCssClass))
            headerRow.Attributes.Add(&amp;quot;class&amp;quot;, titleCssClass);
        var dataRow = new HtmlTableRow();
        if (!String.IsNullOrEmpty(fieldCssClass))
            dataRow.Attributes.Add(&amp;quot;class&amp;quot;, fieldCssClass);

        // step through each of the columns to be added to the table
        foreach (var metaColumn in metaColumns)
        {
            // get the MultiColumn attribute for the column
            var multiColumn = metaColumn.GetAttributeOrDefault&lt;multicolumnattribute&gt;();
            if (multiColumn.ColumnSpan &amp;gt; columns)
                throw new InvalidOperationException(String.Format(&amp;quot;MultiColumn attribute specifies that this 
                    field occupies {0} columns, but the EntityUIHint attribute for the class only allocates {1} 
                    columns in the HTML table.&amp;quot;, multiColumn.ColumnSpan, columns));

            // check if there are sufficient columns left in the current row
            if (col + multiColumn.ColumnSpan &amp;gt; columns)
            {
                // save this header row
                this.Controls.Add(headerRow);
                headerRow = new HtmlTableRow();
                if (!String.IsNullOrEmpty(titleCssClass))
                    headerRow.Attributes.Add(&amp;quot;class&amp;quot;, titleCssClass);

                // save this data row
                this.Controls.Add(dataRow);
                dataRow = new HtmlTableRow();
                if (!String.IsNullOrEmpty(fieldCssClass))
                    dataRow.Attributes.Add(&amp;quot;class&amp;quot;, fieldCssClass);

                // need to start a new row
                col = 0;
            }

            // add the header cell
            var th = new HtmlTableCell();
            var label = new Label();
            label.Text = metaColumn.DisplayName;
            //if (Mode != System.Web.UI.WebControls.DataBoundControlMode.ReadOnly)
            //    label.PreRender += Label_PreRender;

            th.InnerText = metaColumn.DisplayName;
            if (multiColumn.ColumnSpan &amp;gt; 1)
                th.ColSpan = multiColumn.ColumnSpan;
            headerRow.Cells.Add(th);

            // add the data cell
            var td = new HtmlTableCell();
            var dynamicControl = new DynamicControl(Mode);
            dynamicControl.DataField = metaColumn.Name;
            dynamicControl.ValidationGroup = this.ValidationGroup;

            td.Controls.Add(dynamicControl);
            if (multiColumn.ColumnSpan &amp;gt; 1)
                td.ColSpan = multiColumn.ColumnSpan;
            dataRow.Cells.Add(td);

            // record how many columns we have used
            col += multiColumn.ColumnSpan;
        }
        this.Controls.Add(headerRow);
        this.Controls.Add(dataRow);
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 4 – MultiColumnEntityTemplate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #f0d0f0; margin: 4px; padding-left: 4px; padding-right: 4px; color: #800080; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Updated: &lt;/strong&gt; MultiColumnEntityTemplate updated by Phil Wigglesworth who kindly found a bug and fixed it, the bug was shown when there were no enough columns left on a row, this caused a crash. So thanks again to Phil.&lt;/div&gt;
Also we will need some styles to make out new Multi Column entity template look good. &lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;TR.SmallTitle
{
    background-color: #F7F7FF;
}
TR.SmallTitle TD
{
    font-size: 0.8em !important;
    font-weight: bold;
    background-color: #F7F7FF;
    padding: 2px !important;
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Listing 5 – CSS styles&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hope this expand your use of Entity Templates.&lt;/p&gt;

&lt;p&gt;P.S. I’ll do an updated version of the Grouping entity template.&lt;/p&gt;

&lt;p&gt;Download&lt;/p&gt;
&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="http://cid-96845e7b0fac1eed.office.live.com/embedicon.aspx/Public/CustomEntityTemplates.zip" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/jrSO7AhPWnc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/7545920281970746451/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=7545920281970746451&amp;isPopup=true" title="14 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/7545920281970746451?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/7545920281970746451?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/jrSO7AhPWnc/custom-entity-templates-dynamic-data-4.html" title="Custom Entity Templates – Dynamic Data 4" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_UUHjb9DZhJM/TM2sW7NYWvI/AAAAAAAAA6I/0LWRtNUIv5U/s72-c/MultiColumnEntityTemplate_thumb%5B5%5D.png?imgmax=800" height="72" width="72" /><thr:total>14</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2010/10/custom-entity-templates-dynamic-data-4.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MHRn86fCp7ImA9Wx9WEk0.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-6617020443337423406</id><published>2011-01-16T19:05:00.001Z</published><updated>2011-01-16T19:17:17.114Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-16T19:17:17.114Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Sorting" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.Net 4.0" /><title>Setting the Initial Sort Order – Dynamic Data</title><content type="html">&lt;p&gt;This is just a quick note on a post I made on the &lt;a href="http://forums.asp.net/1145.aspx"&gt;Dynamic Data Forum&lt;/a&gt; to answer a question where setting the &lt;strong&gt;DisplayColumnAttribute&lt;/strong&gt; should set the default sort order of the &lt;strong&gt;GridView&lt;/strong&gt; on the &lt;strong&gt;List&lt;/strong&gt; page but didn’t. Here’s how I solved it with a hint or two from &lt;a href="http://blogs.msdn.com/marcinon/default.aspx"&gt;Marcin Dobosz&lt;/a&gt;.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:65e740b5-2b9c-4419-91c8-cd427a529715" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;[MetadataType(typeof(Orders_Metadata ))]
[DisplayColumn("OrderID", "OrderID", true)]
public partial class Orders
{
    public class Orders_Metadata
    {       
        // ...
    }
}&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Listing 1 – Example Metadata&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assuming you have a table with the &lt;strong&gt;DisplayColumnAttribute&lt;/strong&gt; set you could put this on your List page:&amp;#160; &lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:9c1fef38-b3bd-4239-b62c-1a8eedf3d3a3" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;table = GridDataSource.GetTable();

// set default sort
if (!IsPostBack &amp;amp;&amp;amp; table.SortColumn != null)
    GridView1.Sort(table.SortColumn.Name, table.SortDescending ? SortDirection.Descending : SortDirection.Ascending);&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Listing 2 – Add to Page_Init (.Net 3.5)&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:01a0d4fe-56b2-472e-bcf4-884bee05d537" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;// set default sort
if (!IsPostBack &amp;amp;&amp;amp; table.SortColumn != null)
{
    var order = new OrderByExpression()
    {
        DataField = table.SortColumn.Name,
        Direction = table.SortDescending ? SortDirection.Descending : SortDirection.Ascending,
    };
    GridQueryExtender.Expressions.Add(order);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 3 – Add to Page_Init (.Net 4)&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:4ec042d4-0cf2-460e-b3ef-1f125768284f" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;public static T GetAttribute&amp;lt;T&amp;gt;(this MetaTable table) where T : Attribute
{
    return table.Attributes.OfType&amp;lt;T&amp;gt;().FirstOrDefault();
}&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Listing 3 – you will also need this extension method see &lt;/strong&gt;&lt;a href="http://csharpbits.notaclue.net/2009/01/writing-attribute-and-extension-methods.html"&gt;Writing Attributes and Extension Methods for Dynamic Data&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add your &lt;strong&gt;DisplayColumnAttribute&lt;/strong&gt; (&lt;strong&gt;see Listing 1&lt;/strong&gt;) to the table you want sorted (&lt;strong&gt;note:&lt;/strong&gt; it must have the second string constant even if it’s the same name, as the second string it the one that the sort is done on, and the third value if true causes the sort to be descending). Then in &lt;strong&gt;Listing 2&lt;/strong&gt; you get the attribute using the extension method from &lt;strong&gt;Listing 3&lt;/strong&gt; and apply the relevant sort.&lt;/p&gt;

&lt;p&gt;This is here mainly so I can find it again! &lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="HappyWizard" border="0" alt="HappyWizard" src="http://lh5.ggpht.com/_UUHjb9DZhJM/TTNBiafQrOI/AAAAAAAAA8M/gHlRETXv0Sk/HappyWizard4.png?imgmax=800" width="19" height="33" /&gt;&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/8ePfq62yHxM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/6617020443337423406/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=6617020443337423406&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6617020443337423406?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6617020443337423406?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/8ePfq62yHxM/setting-initial-sort-order-dynamic-data.html" title="Setting the Initial Sort Order – Dynamic Data" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_UUHjb9DZhJM/TTNBiafQrOI/AAAAAAAAA8M/gHlRETXv0Sk/s72-c/HappyWizard4.png?imgmax=800" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/01/setting-initial-sort-order-dynamic-data.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4EQHY-fCp7ImA9Wx9WE00.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-1813432532438792940</id><published>2011-01-13T00:03:00.001Z</published><updated>2011-01-17T23:45:01.854Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-17T23:45:01.854Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic Data" /><category scheme="http://www.blogger.com/atom/ns#" term="Filtering" /><category scheme="http://www.blogger.com/atom/ns#" term="Multi Column Search" /><category scheme="http://www.blogger.com/atom/ns#" term="Searching" /><title>Adding a Multi-Column Search to the Default List page in Dynamic Data (UPDATED)</title><content type="html">&lt;p&gt;This will extend the default filters that Dynamic Data provides by adding a free text search box the will search multiple text fields on the same page. I have done this in a few projects now as one off but after this post &lt;a href="http://forums.asp.net/t/1640135.aspx"&gt;Custom filters &amp;amp; searches within DD in Visual Web Developer 2010 &lt;/a&gt;on the &lt;a href="http://forums.asp.net/1145.aspx"&gt;Dynamic Data Forum&lt;/a&gt; I decided to document it here.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_UUHjb9DZhJM/TS5BZl-w1uI/AAAAAAAAA78/6AAb99HK39I/s1600-h/MultiColumnSearch%5B5%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Multi Column Search" border="0" alt="Multi Column Search" src="http://lh3.ggpht.com/_UUHjb9DZhJM/TS5BaA9sgBI/AAAAAAAAA8A/3cR6dDWXav0/MultiColumnSearch_thumb%5B3%5D.png?imgmax=800" width="307" height="260" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 1 – Multi Column Search&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Here in &lt;strong&gt;Figure 1 &lt;/strong&gt;you can see the multi column search box, in this example the search is on FistName, LastName, Address, City and Country, it will even allow search across entities e.g. on Orders Employee.LastName etc. which make it very flexible.&lt;/p&gt;  &lt;h4&gt;Things we will need to do&lt;/h4&gt;  &lt;ul&gt;   &lt;li&gt;Attribute to tell the system which columns to search on. &lt;/li&gt;    &lt;li&gt;Add mark-up to show the UI on the List page. &lt;/li&gt;    &lt;li&gt;Code to wire up the UI and QueryExtender. &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;The Attribute&lt;/h4&gt;  &lt;p&gt;This attribute will be added to the Class/Table not it’s columns and will have only one property Columns.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:3b206a04-2e8a-4280-a648-2141689aa302" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;[AttributeUsage(AttributeTargets.Class)]
public class MultiColumnSearchAttribute : Attribute
{
    public String[] Columns { get; private set; }

    public MultiColumnSearchAttribute(params String[] columns)
    {
        Columns = columns;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 1 – MultiColumnSearchAttribute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and we apply it as in &lt;strong&gt;Listing 2&lt;/strong&gt; The Employee table show standard multi-column search but the Order table shows how we can search across entity boundaries you can see this in &lt;strong&gt;Figure 2&lt;/strong&gt;.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:28115f29-7bb9-4b21-bab4-fddb0c5624d1" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;[MetadataTypeAttribute(typeof(Employee.EmployeeMetadata))]
[MultiColumnSearch(
    "LastName", 
    "FirstName", 
    "Address", 
    "City", 
    "Country")]
public partial class Employee
{
    internal sealed class EmployeeMetadata
    {
        //...
    }
}

[MetadataTypeAttribute(typeof(Order.OrderMetadata))]
[MultiColumnSearch(
    "Employee.LastName", 
    "Employee.FirstName", 
    "Customer.CompanyName", 
    "Customer.ContactName", 
    "Shipper.CompanyName")]
public partial class Order
{
    internal sealed class OrderMetadata
    {
        //...
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 2 – sample metadata&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://lh3.ggpht.com/_UUHjb9DZhJM/TS5BaZXnnII/AAAAAAAAA8E/XYTnfH1gyWQ/s1600-h/Cross%20Entity%20Search%5B4%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Cross Entity Search" border="0" alt="Cross Entity Search" src="http://lh3.ggpht.com/_UUHjb9DZhJM/TS5BbLAgZVI/AAAAAAAAA8I/JQW17gOWznA/Cross%20Entity%20Search_thumb%5B2%5D.png?imgmax=800" width="706" height="247" /&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 2 – cross entity search&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;Adding UI Mark-Up&lt;/h4&gt;

&lt;p&gt;I have added the multi column search UI in between the validators and the QueryableFilterRepeater see &lt;strong&gt;Listing 3&lt;/strong&gt; &lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:9738cb06-fbda-44b4-a4b7-0df680c1d5be" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;asp:DynamicValidator runat="server" ID="GridViewValidator" ControlToValidate="GridView1"
    Display="None" CssClass="DDValidator" /&amp;gt;

&amp;lt;fieldset id="MultiSearchFieldSet" class="DD" runat="server" visible="false"&amp;gt;
    &amp;lt;legend&amp;gt;Full Text Search&amp;lt;/legend&amp;gt;
    &amp;lt;asp:TextBox ID="txbMultiColumnSearch" CssClass="DDTextBox" runat="server" /&amp;gt;
    &amp;lt;asp:Button ID="btnMultiColumnSearchSubmit" CssClass="DDControl" runat="server" Text="Search"
        OnClick="btnMultiColumnSearch_Click" /&amp;gt;
    &amp;lt;asp:Button ID="btnMultiColumnSearchClear" CssClass="DDControl" runat="server" Text="Clear"
        OnClick="btnMultiColumnSearch_Click" /&amp;gt;
&amp;lt;/fieldset&amp;gt;
&amp;lt;br /&amp;gt;

&amp;lt;asp:QueryableFilterRepeater runat="server" ID="FilterRepeater"&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 3 – Multi Column Search UI&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;Code to wire up the UI and QueryExtender&lt;/h4&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:fb5c20e3-dc28-4ad8-8dcf-088828d72230" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;/// &amp;lt;summary&amp;gt;
/// Setups the multi column search.
/// &amp;lt;/summary&amp;gt;
private void SetupMultiColumnSearch()
{
    // get multi column search attribute
    var multiColumnSearch = table.GetAttribute&amp;lt;MultiColumnSearchAttribute&amp;gt;();

    if (multiColumnSearch != null)
    {
        var searchExpression = new SearchExpression()
            {
                DataFields = multiColumnSearch.Columns.ToCsvString(),
                SearchType = SearchType.Contains
            };
        
        // create control parameter
        var controlParameter = new ControlParameter() { ControlID = txbMultiColumnSearch.ID };
        
        // add control parameter to search expression
        searchExpression.Parameters.Add(controlParameter);

        // set context
        searchExpression.SetContext(GridQueryExtender, Context, GridDataSource);

        // add search expression to query extender
        GridQueryExtender.Expressions.Add(searchExpression);

        // make multicolumn search field set visible
        MultiSearchFieldSet.Visible = true;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 5 – SetupMultiColumnSearch method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Listing 5&lt;/strong&gt; (which is called from the Page_Init method) we get the attribute and the SearchExpression the if both are not null we add the fields to the SearchExpressions DataFileds property, then we make the whole thing visible. 

  &lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;Much thanks to &lt;a href="http://blog.davidebbo.com/"&gt;David Ebbo&lt;/a&gt; who sorted out the issue I had had with adding the search expression in code rather than declaratively. &lt;/div&gt;
&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:43cc61ef-de07-48f2-b2e2-25a0e6ce302e" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;protected void btnMultiColumnSearch_Click(object sender, EventArgs e)
{
    var button = (Button)sender;
    if (button.ID == btnMultiColumnSearchClear.ID)
        txbMultiColumnSearch.Text = String.Empty;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 6 – button event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And lastly we need an event to fire when the clear button is fired. &lt;/p&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;I have both buttons wired-up to this handler as I also add session history here so that when you search on something and go to another page when you return you get the same search, but I also want it cleared if I click the clear button.&lt;/div&gt;

&lt;h4&gt;Download&lt;/h4&gt;
&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="http://cid-96845e7b0fac1eed.office.live.com/embedicon.aspx/Public/MultiColumnSearch.zip" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/LOsofPU2Fzg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/1813432532438792940/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=1813432532438792940&amp;isPopup=true" title="34 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/1813432532438792940?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/1813432532438792940?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/LOsofPU2Fzg/adding-multi-column-search-to-default.html" title="Adding a Multi-Column Search to the Default List page in Dynamic Data (UPDATED)" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_UUHjb9DZhJM/TS5BaA9sgBI/AAAAAAAAA8A/3cR6dDWXav0/s72-c/MultiColumnSearch_thumb%5B3%5D.png?imgmax=800" height="72" width="72" /><thr:total>34</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2011/01/adding-multi-column-search-to-default.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QNRnwzcSp7ImA9Wx9RFU0.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-6746854902610109773</id><published>2010-12-08T13:08:00.001Z</published><updated>2010-12-16T12:09:57.289Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-16T12:09:57.289Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".Net 4.0" /><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic Data" /><category scheme="http://www.blogger.com/atom/ns#" term="History" /><category scheme="http://www.blogger.com/atom/ns#" term="Filters" /><title>Filter History for Dynamic Data 4</title><content type="html">&lt;p&gt;I did a &lt;a href="http://csharpbits.notaclue.net/2009/02/ajax-history-in-dynamic-data-website.html"&gt;AJAX History in a Dynamic Data Website&lt;/a&gt; article back in February 2009 to make filter respect the back button in the browser, this however was not enough for my customers they wanted the filter to be remembered even when they came back to the page without using the back button.&lt;/p&gt;  &lt;p&gt;So I decided to store the filter info in Session state for this sample sample (but you could also use a database I have where the client wanted the filters to be remembered across sessions and by user).&lt;/p&gt;  &lt;p&gt;I’m adding this extension to the previous sample from &lt;a href="http://csharpbits.notaclue.net/2010/11/five-cool-filters-for-dynamic-data-4.html"&gt;Five Cool Filters for Dynamic Data 4&lt;/a&gt; (which now has a couple more filters added) to give history across all the filters.&lt;/p&gt;  &lt;h4&gt;Extension Methods&lt;/h4&gt;  &lt;p&gt;So to the code there are two extension methods for this sample AddFilterValueToSession which you can guess adds a filters current value to session and GetFilterValuesFromSession which retrieves an Dictionary of values for the specified table.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:5f098a54-7fb9-44a0-add8-6547b385da25" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;/// &amp;lt;summary&amp;gt;
/// Adds the filters current value to the session.
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="page"&amp;gt;The page.&amp;lt;/param&amp;gt;
/// &amp;lt;param name="column"&amp;gt;The column.&amp;lt;/param&amp;gt;
/// &amp;lt;param name="value"&amp;gt;The value.&amp;lt;/param&amp;gt;
public static void AddFilterValueToSession(this Page page, MetaColumn column, Object value)
{
    Dictionary&amp;lt;String, Object&amp;gt; filterValues;
    var objectName = column.Table.DataContextPropertyName;

    // get correct column name 
    var columnName = column.Name;
    if (column is MetaForeignKeyColumn)
        columnName = ((MetaForeignKeyColumn)column).ForeignKeyNames.ToCommaSeparatedString();

    // check to see if we already have a session object
    if (page.Session[objectName] != null)
        filterValues = (Dictionary&amp;lt;String, Object&amp;gt;)page.Session[objectName];
    else
        filterValues = new Dictionary&amp;lt;String, Object&amp;gt;();

    // add new filter value to session object
    if (filterValues.Keys.Contains(columnName))
        filterValues[columnName] = value;
    else
        filterValues.Add(columnName, value);

    // add back to session
    if (page.Session[objectName] != null)
        page.Session[objectName] = filterValues;
    else
        page.Session.Add(objectName, filterValues);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 1 – AddFilterValueToSession&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you follow the code and comments you will see that first we try to get the session object for this table from session and if it is not there we simply create one. Then we add/update the value for this column and finally save back to session.&lt;/p&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #ffffcc; margin: 4px; padding-left: 4px; padding-right: 4px; color: #666666; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Note: &lt;/strong&gt;that &lt;strong&gt;Listing 1&lt;/strong&gt; uses an extension method ToCommaSeperatedString() this just simplifies the code for us by removing reusable code. &lt;/div&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #f0d0f0; margin: 4px; padding-left: 4px; padding-right: 4px; color: #800080; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Updated: &lt;/strong&gt;As ValZ posted in the comments I have updated the GetFilterValuesFromSession extension method to make sure any links from other List pages are honoured, for instance if you go to the Suppliers page and click on View Products link but already have a filter value that will now be honoured. I’ve also used IDictionary so we don’t have to cast the default values that are passed in.&lt;/div&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:fa21218e-239a-4400-bfd3-d9b3ed51e5c5" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;/// &amp;lt;summary&amp;gt;
/// Gets the filter values from session.
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="page"&amp;gt;The page.&amp;lt;/param&amp;gt;
/// &amp;lt;param name="table"&amp;gt;The table.&amp;lt;/param&amp;gt;
/// &amp;lt;param name="defaultValues"&amp;gt;The default values.&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;An IDictionary of filter values from the session.&amp;lt;/returns&amp;gt;
public static IDictionary&amp;lt;String, Object&amp;gt; GetFilterValuesFromSession(this Page page, 
    MetaTable table, 
    IDictionary&amp;lt;String, Object&amp;gt; defaultValues)
{
    var queryString = new StringBuilder();
    var objectName = table.DataContextPropertyName;
    if (page.Session[objectName] != null)
    {
        var sessionFilterValues = new Dictionary&amp;lt;String, Object&amp;gt;((Dictionary&amp;lt;String, Object&amp;gt;)page.Session[objectName]);
        foreach (string key in defaultValues.Keys)
        {
            if (!sessionFilterValues.Keys.Contains(key) || sessionFilterValues[key] == null)
                sessionFilterValues.Add(key, defaultValues[key]);
            else
                sessionFilterValues[key] = defaultValues[key];
        }
        var t = (Dictionary&amp;lt;String, Object&amp;gt;)page.Session[objectName];
        return sessionFilterValues;
    }
    else
        return defaultValues;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 2 – GetFilterValuesFromSession&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Listing 2&lt;/strong&gt; we simply get the Dictionary object back from session and then return it.&lt;/p&gt;

&lt;h4&gt;Applying to the Filters&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Listing 3&lt;/strong&gt; is a for the ForeignKey filter, here call the AddFilterValueToSession extension method passing in the Column and value from the DropdownList.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:9a4c4615-a08f-48bf-afcf-8eff8babfd9e" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
    OnFilterChanged();
    Page.AddFilterValueToSession(Column, DropDownList1.SelectedValue);
}&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Listing 3 – ForeignKey filter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every filter in that sample has this applied and there are several different examples in there.&lt;/p&gt;

&lt;h4&gt;Extracting the Filter Values&lt;/h4&gt;

&lt;p&gt;Now all we need is to get the values and pass them back to the filters each time we arrive at a List page. In &lt;strong&gt;Listing 4&lt;/strong&gt; I have updated the Page_Init method,&amp;#160; I first attempt to get the filter values from session if none are found I fall back to default List page behaviour.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:d7210b11-c2b0-463f-8889-5f5882aeb7c8" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;protected void Page_Init(object sender, EventArgs e)
{
    table = DynamicDataRouteHandler.GetRequestMetaTable(Context);

    var defaultValues = Page.GetFilterValuesFromSession(table, table.GetColumnValuesFromRoute(Context));
    GridView1.SetMetaTable(table, defaultValues);

    GridDataSource.EntityTypeFilter = table.EntityType.Name;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 4 – Updating the List page&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now if we switch back to the ForeignKey filter and the Page_Init method &lt;strong&gt;Listing 5&lt;/strong&gt; you will see that I have not had to change anything here, because we are adding the default values in the List page they will arrive in each filter via the DefaultValue property.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:dc6eb2e4-8698-4c54-8bba-6cc87b94736c" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;protected void Page_Init(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        if (!Column.IsRequired)
        {
            DropDownList1.Items.Add(new ListItem("[Not Set]", NullValueString));
        }
        PopulateListControl(DropDownList1);

        // Set the initial value if there is one
        string initialValue = DefaultValue;
        if (!String.IsNullOrEmpty(initialValue))
        {
            DropDownList1.SelectedValue = initialValue;
            // optional add auto filters to history
            Page.AddFilterValueToSession(Column, initialValue);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 5 – updating the filter&lt;/strong&gt;&lt;/p&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #f0d0f0; margin: 4px; padding-left: 4px; padding-right: 4px; color: #800080; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Updated: &lt;/strong&gt;I’ve also added a optional Page.AddFilterValueToSession(Column, initialValue); to each filter so that filter values passed in in query string can be added to history, &lt;strong&gt;NOTE:&lt;/strong&gt; &lt;strong&gt;I’ve only added this to the ForeignKey filter so it’s easy to remove if not required.&lt;/strong&gt;&lt;/div&gt;

&lt;p&gt;I’ll show one complex example of setting up the values in a filter, we will look at me DateRange filter for this. First look at &lt;strong&gt;Listing 6&lt;/strong&gt; here I am concatenating both values together separated by ‘|’.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:ba75de3f-ad08-4a68-9f73-5b9601be22f5" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;protected void btnRangeButton_Click(object sender, EventArgs e)
{
    var button = (Button)sender;
    if (button.ID == btnClear.ID)
    {
        txbDateFrom.Text = String.Empty;
        txbDateTo.Text = String.Empty;
    }
    OnFilterChanged();
    Page.AddFilterValueToSession(Column, String.Format("{0}|{1}", txbDateFrom.Text, txbDateTo.Text));
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 6 – DateRange button click event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then if you look at the DateRange filters Page_Init method all need to do is check I have a value, reveres the concatenation and put the values in the correct textboxes.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:f97ee9dc-072e-4e59-9224-18e58cff011b" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;protected void Page_Init(object sender, EventArgs e)
{
    // set correct date time format
    txbDateFrom_CalendarExtender.Format = DATE_FORMAT;
    txbDateTo_CalendarExtender.Format = DATE_FORMAT;

    if (!Column.ColumnType.Equals(typeof(DateTime)))
        throw new InvalidOperationException(String.Format("A date range filter was loaded for column '{0}' but the column has an incompatible type '{1}'.",
            Column.Name, Column.ColumnType));

    if (DefaultValue != null)
    {
        var values = DefaultValue.Split(new char[] { '|' });
        if (values.Length == 2)
        {
            txbDateFrom.Text = values[0];
            txbDateTo.Text = values[1];
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 7 – DateRange Page_Init method&lt;/strong&gt;&lt;/p&gt;

&lt;div style="border-bottom: gray 1px dotted; border-left: gray 1px dotted; padding-bottom: 4px; background-color: #f0d0f0; margin: 4px; padding-left: 4px; padding-right: 4px; color: #800080; border-top: gray 1px dotted; border-right: gray 1px dotted; padding-top: 4px"&gt;&lt;strong&gt;Updated: &lt;/strong&gt;Add clear filters button to clear all filters for a table.&lt;/div&gt;

&lt;h4&gt;Clear Filters&lt;/h4&gt;

&lt;p&gt;Last we add a button to clear the filters&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:43291070-8dff-478b-b2ce-d4dc34982e45" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: python;"&gt;&amp;lt;div class="DD"&amp;gt;
    &amp;lt;asp:ValidationSummary ID="ValidationSummary1" runat="server" EnableClientScript="true"
        HeaderText="List of validation errors" CssClass="DDValidator" /&amp;gt;
    &amp;lt;asp:DynamicValidator runat="server" ID="GridViewValidator" ControlToValidate="GridView1"
        Display="None" CssClass="DDValidator" /&amp;gt;
    &amp;lt;asp:QueryableFilterRepeater runat="server" ID="FilterRepeater"&amp;gt;
        &amp;lt;ItemTemplate&amp;gt;
            &amp;lt;asp:Label runat="server" Text='&amp;lt;%# Eval("DisplayName") %&amp;gt;' OnPreRender="Label_PreRender" /&amp;gt;
            &amp;lt;asp:DynamicFilter runat="server" ID="DynamicFilter" OnFilterChanged="DynamicFilter_FilterChanged" /&amp;gt;
            &amp;lt;br /&amp;gt;
        &amp;lt;/ItemTemplate&amp;gt;
    &amp;lt;/asp:QueryableFilterRepeater&amp;gt;
    &amp;lt;asp:Button 
        ID="ClearFiltersButton" 
        runat="server" 
        Text="Clear Filters" 
        CssClass="DDControl"
        OnClick="ClearFiltersButton_Click" /&amp;gt;
    &amp;lt;br /&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 8 – Clear filters button&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and in the post back of the button&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:d3b6a80a-7478-48d9-888f-7c038948142d" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;protected void ClearFiltersButton_Click(object sender, EventArgs e)
{
    Page.ClearTableFilters(table);
    Response.Redirect(table.ListActionPath);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 9 – Clears filters button method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and lastly we need the method the clears the filters for us,&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:a5727fb5-3006-4c9b-9686-87a2c47d2d46" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;public static void ClearTableFilters(this Page page, MetaTable table)
{
    var objectName = table.DataContextPropertyName;

    if (page.Session[objectName] != null)
        page.Session[objectName] = null;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 10 – Clear filters extension method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lastly we will need to hide the button when there are no filters.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:1e6da780-1a8e-490d-b9be-8b9236df454d" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: c#;"&gt;protected override void OnPreRenderComplete(EventArgs e)
{
    RouteValueDictionary routeValues = new RouteValueDictionary(GridView1.GetDefaultValues());
    InsertHyperLink.NavigateUrl = table.GetActionPath(PageAction.Insert, routeValues);
    if (FilterRepeater.Controls.Count == 0)
        ClearFiltersButton.Visible = false;
    base.OnPreRenderComplete(e);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Listing 11 – hiding the clear filters button&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So then all done then.&lt;/p&gt;

&lt;h4&gt;Download&lt;/h4&gt;
&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="http://cid-96845e7b0fac1eed.office.live.com/embedicon.aspx/Public/CustomFiltersWithFilterHistory%202010-12-15.zip" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/MuaYegIKufw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/6746854902610109773/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=6746854902610109773&amp;isPopup=true" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6746854902610109773?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/6746854902610109773?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/MuaYegIKufw/filter-history-for-dynamic-data-4.html" title="Filter History for Dynamic Data 4" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2010/12/filter-history-for-dynamic-data-4.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIAQ3g8cSp7ImA9Wx9TGEg.&quot;"><id>tag:blogger.com,1999:blog-6907873803403737979.post-422892713307885809</id><published>2010-11-26T21:42:00.001Z</published><updated>2010-11-27T11:15:42.679Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-27T11:15:42.679Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Advertisement" /><title>BLACK FRIDAY/CYBER MONDAY DEAL:</title><content type="html">&lt;p&gt;Note&amp;#160; I don’t normally post adds for products but this is really easy to create icons I’m always creating favicons for my sites and it make the task real easy.&lt;/p&gt;  &lt;h4&gt;&lt;a href="http://www.axialis.com/iconworkshop/index.html" target="_blank"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="sale" border="0" alt="sale" src="http://lh4.ggpht.com/_UUHjb9DZhJM/TPAprX5Oy3I/AAAAAAAAA7Q/XSjhvEzEfpE/sale%5B4%5D.jpg?imgmax=800" width="200" height="143" /&gt;&lt;/a&gt; &lt;/h4&gt;  &lt;p&gt;All Axialis products are available at 50 percent Off. Starting Black Friday, this offer ends Nov 30. This is for 5 days, and 5 days only. Half price but full service! You get the same Axialis advantages: professionally-designed products, LIFETIME LICENCE! (never pay for future updates), access to thousands of ready-to-use image object packs, and more...&lt;/p&gt;  &lt;p&gt;&lt;em&gt;So don't miss this opportunity! ACT NOW and get 50 percent off your total order!&lt;/em&gt;&lt;/p&gt;  &lt;h4&gt;IconWorkshop 6.53 Released:&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://www.axialis.com/iconworkshop/" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IconWorkshop" border="0" alt="IconWorkshop" src="http://lh3.ggpht.com/_UUHjb9DZhJM/TPDoXUXh9VI/AAAAAAAAA7Y/cmxdrZ-zIwY/iw%5B1%5D.jpg?imgmax=800" width="120" height="115" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This minor release includes various bug fixes and enhancements:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Compatible with Visual Studio 2010: The installer detects and add the IconWorkshop add-in in Visual Studio 2010. &lt;/li&gt;    &lt;li&gt;Ability to create icons for iPhone 4: This new version includes new image presets to create those icons. &lt;/li&gt;    &lt;li&gt;New Object Packs: Two new object packs are provided to create iPhone icons (Applications and Tab Bar Icons). &lt;/li&gt;    &lt;li&gt;Various other enhancements and bug fixes. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Registered users can freely upgrade to this latest version using the built-in update feature.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/notaclue/IYRx/~4/lr2ASBzRO00" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://csharpbits.notaclue.net/feeds/422892713307885809/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6907873803403737979&amp;postID=422892713307885809&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/422892713307885809?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6907873803403737979/posts/default/422892713307885809?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/notaclue/IYRx/~3/lr2ASBzRO00/black-fridaycyber-monday-deal.html" title="BLACK FRIDAY/CYBER MONDAY DEAL:" /><author><name>Steve</name><uri>http://www.blogger.com/profile/17435527974910745156</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://bp1.blogger.com/_UUHjb9DZhJM/SDtH0AxIZOI/AAAAAAAAAEM/TFDI9vas7Sc/S220/Me+63x80.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_UUHjb9DZhJM/TPAprX5Oy3I/AAAAAAAAA7Q/XSjhvEzEfpE/s72-c/sale%5B4%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://csharpbits.notaclue.net/2010/11/black-fridaycyber-monday-deal.html</feedburner:origLink></entry></feed>
