- The Anatomy of a FieldTemplate.
- Your First FieldTemplate.
- An Advanced FieldTemplate.
- A Second Advanced FieldTemplate.
- An Advanced FieldTemplate with a GridView.
- An Advanced FieldTemplate with a DetailsView.
- An Advanced FieldTemplate with a GridView/DetailsView Project.
The Idea for this FieldTemplate came from Nigel Basel post on the Dynamic Data forum where he said he needed to have a GridView emended in another data control i.e. FormView so he could use the AjaxToolkit Tab control. So here it is with some explanation.
Files Required for Project
In this project we are going to convert a PageTemplate into a FieldTemplate so in your project you will need to copy the List.aspx and it’s code behind List.aspx.cs to the FieldTemplate folder. When copied rename the file to GridView_Edit.ascx and change the class name to GridView_EditField see Listings 1 & 2.
<%@ Page Language="C#" MasterPageFile="~/Site.master" CodeFile="List.aspx.cs" Inherits="List" %>
<%@ Control Language="C#" CodeFile="GridView_Edit.ascx.cs" Inherits="GridView_EditField" %>
Listing 1 – Changing the class name of the GridView_Edit.ascx file
public partial class List : System.Web.UI.Page {
...
}
to
public partial class GridView_EditField : FieldTemplateUserControl {Listing 2 - Changing the class name of the GridView_Edit.ascx.cs code behind file
...
}
Now in the GridView_Edit.ascx file trim out all the page relavent code:
i.e. remove the following tags (and their closing tags where applicable)
<asp:Content
<asp:UpdatePanel
<ContentTemplate>
<%@ Register src="~/DynamicData/Content/FilterUserControl.ascx" tagname="DynamicFilter" tagprefix="asp" %>
<asp:DynamicDataManager runat="server" ID="DynamicDataManager1" AutoLoadForeignKeys="true" />
Also remove from the GridView the columns tags and everything in them, and then add the following properties to the GridView:
AutoGenerateColumns="true" AutoGenerateDeleteButton="true" AutoGenerateEditButton="true"
and you should end up with something like Listing 3.
<%@ Control Language="C#" CodeFile="GridView_Edit.ascx.cs" Inherits="GridView_EditField" %> <%@ Register src="~/DynamicData/Content/GridViewPager.ascx" tagname="GridViewPager" tagprefix="asp" %> <asp:DynamicDataManager runat="server" ID="DynamicDataManager1" AutoLoadForeignKeys="true" /> <asp:ScriptManagerProxy runat="server" ID="ScriptManagerProxy1" /> <asp:ValidationSummary runat="server" ID="ValidationSummary1" EnableClientScript="true" HeaderText="List of validation errors" /> <asp:DynamicValidator runat="server" ID="GridViewValidator" ControlToValidate="GridView1" Display="None" /> <asp:GridView runat="server" ID="GridView1" DataSourceID="GridDataSource" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="true" AutoGenerateDeleteButton="true" AutoGenerateEditButton="true" CssClass="gridview"> <PagerStyle CssClass="footer"/> <PagerTemplate> <asp:GridViewPager runat="server" /> </PagerTemplate> <EmptyDataTemplate> There are currently no items in this table. </EmptyDataTemplate> </asp:GridView> <asp:LinqDataSource runat="server" ID="GridDataSource" EnableDelete="true"> </asp:LinqDataSource>
Listing 3 – the finished GridView_Edit.ascx file
Now we’ll trim down the GridView_Edit.ascx.cs, the first things to remove are the following methods and event handlers:
protected void Page_Load(object sender, EventArgs e)
protected void OnFilterSelectedIndexChanged(object sender, EventArgs e)
This will leave us with just the Page_Init to fill in see Listing 4 for it.
protected void Page_Init(object sender, EventArgs e) { var metaChildColumn = Column as MetaChildrenColumn; var attribute = Column.Attributes.OfType<ShowColumnsAttribute>().SingleOrDefault(); if (attribute != null) { if (!attribute.EnableDelete) EnableDelete = false; if (!attribute.EnableUpdate) EnableUpdate = false; if (attribute.DisplayColumns.Length > 0) DisplayColumns = attribute.DisplayColumns; } var metaForeignKeyColumn = metaChildColumn.ColumnInOtherTable as MetaForeignKeyColumn; if (metaChildColumn != null && metaForeignKeyColumn != null) { GridDataSource.ContextTypeName = metaChildColumn.ChildTable.DataContextType.Name; GridDataSource.TableName = metaChildColumn.ChildTable.Name; // enable update, delete and insert GridDataSource.EnableDelete = EnableDelete; GridDataSource.EnableInsert = EnableInsert; GridDataSource.EnableUpdate = EnableUpdate; GridView1.AutoGenerateDeleteButton = EnableDelete; GridView1.AutoGenerateEditButton = EnableUpdate; // get an instance of the MetaTable table = GridDataSource.GetTable(); // Generate the columns as we can't rely on // DynamicDataManager to do it for us. GridView1.ColumnsGenerator = new FieldTemplateRowGenerator(table, DisplayColumns); // setup the GridView's DataKeys String[] keys = new String[metaChildColumn.ChildTable.PrimaryKeyColumns.Count]; int i = 0; foreach (var keyColumn in metaChildColumn.ChildTable.PrimaryKeyColumns) { keys[i] = keyColumn.Name; i++; } GridView1.DataKeyNames = keys; GridDataSource.AutoGenerateWhereClause = true; } else { // throw an error if set on column other than MetaChildrenColumns throw new InvalidOperationException("The GridView FieldTemplate can only be used with MetaChildrenColumns"); } }
Listing 4 – the Page_Init ***UPDATED 2008/09/24***
protected override void OnDataBinding(EventArgs e) { base.OnDataBinding(e); var metaChildrenColumn = Column as MetaChildrenColumn; var metaForeignKeyColumn = metaChildrenColumn.ColumnInOtherTable as MetaForeignKeyColumn; // get the association attributes associated with MetaChildrenColumns var association = metaChildrenColumn.Attributes. OfType<System.Data.Linq.Mapping.AssociationAttribute>().FirstOrDefault(); if (metaForeignKeyColumn != null && association != null) { // get keys ThisKey and OtherKey into Pairs var keys = new Dictionary<String, String>(); var seperator = new char[] { ',' }; var thisKeys = association.ThisKey.Split(seperator); var otherKeys = association.OtherKey.Split(seperator); for (int i = 0; i < thisKeys.Length; i++) { keys.Add(otherKeys[i], thisKeys[i]); } // setup the where clause // support composite foreign keys foreach (String fkName in metaForeignKeyColumn.ForeignKeyNames) { // get the current pk column var fkColumn = metaChildrenColumn.ChildTable.GetColumn(fkName); // setup parameter var param = new Parameter(); param.Name = fkColumn.Name; param.Type = fkColumn.TypeCode; // get the PK value for this FK column using the fk pk pairs param.DefaultValue = Request.QueryString[keys[fkName]]; // add the where clause GridDataSource.WhereParameters.Add(param); } } // doing the work of this above because we can't // set the DynamicDataManager table or where values //DynamicDataManager1.RegisterControl(GridView1, false); }
Listing 4a – OnDataBinding event handler ***ADDED 2008/09/24***
And now we will need to implement the GridViewColumnGenerator to fill in the rows as the DynamicDataManager would have done.
public class GridViewColumnGenerator : IAutoFieldGenerator { protected MetaTable _table; public GridViewColumnGenerator(MetaTable table) { _table = table; } public ICollection GenerateFields(Control control) { List<DynamicField> oFields = new List<DynamicField>(); foreach (var column in _table.Columns) { // carry on the loop at the next column // if scaffold table is set to false or DenyRead if (!column.Scaffold) continue; DynamicField field = new DynamicField(); field.DataField = column.Name; oFields.Add(field); } return oFields; } }Listing 5 – the GridViewColumnGenerator class
In Listing 5 we have the GridViewColumnGenerator class which you can just tag onto the end the GridView_Edit.ascx.cs file as it is only used here.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class GridViewTemplateAttribute :Attribute { public String ForeignKeyColumn { get; private set; } public GridViewTemplateAttribute(string foreignKeyColumn) { ForeignKeyColumn = foreignKeyColumn; } }
Listing 6 – GridViewTemplateAttribute for the above ***UPDATE 2008/08/08 *** :D
Figure 1 GridView_Edit FieldTemplate in action
[UIHint("GridView")] public object Order_Details { get; set; }
Listing 7 – Metadata
Until next time
27 comments:
Thanks for all the great information. The grid view sample helps expose even more of the capabilities of Dynamic Data and your work with the security model is right where a lot of people are thinking.
Keep up the excellent work!
Thanks Angry Tech Guy glad you like it, where are you from?
From Maine, USA
Sadly I've moved to more over IT Management from the strict programming and design side, but DynamicData is allowing me easily work through some things I ordinarily wouldn't have had the time to pull off. It was missing a few things but the gridview article, security, and the dynamic filters are helping close the gaps.
I'm interested in using a gridview in place of a dropdownlist for a foreign key field. The reason being is two-fold: the parent table has too many rows for the dropdownlist control as far as performance is concerned, and selection of the parent row would be made easier with the ability to see other column data and the use of filters.
Hello,
That is just excellent but ..
is this possible to do the same thing using Entities instead of LINQ to SQL ?
Yes it is possible I will get around to doing a post on that when we get to Beta 2 of VS2010/.Net 4.0
Steve :D
No offence, but the above is almost impossible to read, what with all the edits, deletes, etc.
As someone who manages people and code, I would never post anything like this w/o a downloadable file or set of files. What's the point of trying to read betwixt all the early mistakes you made? I see none, and irregardless, a clean solution would be many times more valuable than reading how a flawed design gets worked on.
if you go to the final article in the series you will find the source code
Steve :D
P.S. the article is old and had many changes and I wanted readers to see my errors.
hey steve!! got my job done BUT i have an issue, results are not being filtered out i mean say i have customers and shipping information table, instead of showing me only that particular customer ID shipping info , child grid displays the whole shipping info table. can you help me with this?
Any chance of post LINQ to SQL?
Cheers
"is this possible to do the same thing using Entities instead of LINQ to SQL ?
1 June 2009 16:58
Steve said...
Yes it is possible I will get around to doing a post on that when we get to Beta 2 of VS2010/.Net 4.0"
I'm sure it should but I havent tried as all my projects have been Linq to SQL.
Steve :D
P.S. with the advent of VS2010 I think all my projects will go EF :)
Where is ShowColumnsAttribute? I'm using 2010 RC, is that class no longer part of the dynamic data libraries?
Hi there, ShowColumnsAttribute was one of my custom attributes see my latest blog post for stuff on VS2010 RC and newer.
Steve :D
Instead of:
[code]
GridDataSource.ContextTypeName = metaChildColumn.ChildTable.DataContextType.Name;
[/code]
you should use:
[code]
GridDataSource.ContextTypeName = metaChildColumn.ChildTable.DataContextType.FullName;
[/code]
And in C# 4 instead of :
[code]
if (!attribute.EnableDelete)
EnableDelete = false;
if (!attribute.EnableUpdate)
EnableUpdate = false;
[/code]
you should use:
[code]
EnableDelete = attribute.EnableDelete;
EnableUpdate = attribute.EnableUpdate;
[/code]
Hi paulovila, this article was for DD1 in 2008 and is now out of date but thanks for the update I will try and fix it sometime.
Steve
Hi Steve,
Is there updated version of of this? I am having issues porting this to VS2010 EF.
Thanks,
San
PS: Love ur work, I have learned a lot Thanks
I will be doing an article for the child grid for VS2010 and EF soon
Steve.
Hi,
Thanks for all the publishing on DynamicData. Appreciate it.
When is the new child gridview article coming? Waiting for it!
I still have at least one problem with this approach, the ValidationException(s) are not caught somehow (for db errors) and the "yellow screen of death" as you intimately call it, is still disturbing me!
You tell in this article that we can't rely on the DynamicDataManager, why not? Why is it not as simple as putting another, nested, dynamicDataManager and BOUM! It should be! Or why is it not possible to reference nested controls in the "root" dynamicDataManager.
If only I could tweak it...
A bit frustrating!
Hi Lener, I am working on a new version of the ChildrenList as I've now called it :) for .Net 3.5 and .Net 4 and Linq to SQL and Entity Framework. I will do a new article when work schedule allows.
I'm not sure of the reason why the DynamicDataManager is of no use here. BTW the DynamicDataManager does not contain the nested controls the GridViews/DetailsViews/FormViews do, they are just wrapped in field templates and DynamicControls.
Steve :)
Hello sir,
Can you say,how can we create a sales page in asp.net.Either in Dynamic Data or Web forms.What i mean is that,i want to enter the date customer name etc and the order details below it in a gridview. Such a thing can easily be achieved in deskop applications.Please help
Hi Faizal, I do have somthing like that but I have made it puclic yet sorry, I hope to get it on NuGet when I get the time but stuck doing paid work at the moment.
Got to eat :D
Steve
Hi,
Thanks for all of the work, it has been very helpful. I am working on modifying this code to create a user control that displays a gridview for the parent table of each foreign key of a given table. The problem I am having is that I am using a LINQ to Entities project, and I am getting the error:
"The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'."
Some other resources say this has to do with using the wrong type of dynamic data project. Your example is in LINQ to SQL. How can I modify your code to work with LINQ to Entities (or am I missing something and that is not the problem)?
Thanks,
Jonathan
Hi Jonathan, yes I already did that just not published it I can send you the code if you direct e-mail me
Steve
Hi,
Great post. Any idea if it's possible to insert one or more new "order_details" in the gridview before sending the whole bunch into the database via the FormView's "update" button?
Thanks,
red
it is possible but I don't have a sample for it. the editable Grid I have does the inserts one at a time. What you want is there in Visual Studio LightSwitch you can create a new record and add child records and then click save all in one.
Steve
Hi,
Thanks for this great work. Do you have already published somewhere the version with Linq to Entity Framework?
Thanks,
Marco
I have but you will need to e-mail me if you want just the bare minimum sample else you can look on my open source project here
Steve
Post a Comment