As far as I can see there are three (oops! four then) types of Custom Page:
- Custom Pages Part 1 - Standard Custom Page based on an existing PageTemplate and customised in the DynamicData\CustomPages folder.
- Custom Pages Part 2 - A completely Custom Page again in the DynamicData\CustomPages folder.
- Custom Pages Part 3 - Standard ASP.Net Page with Dynamic Data features added to take advantage of the FieldTemplates.
- Custom Pages Part 4 - A DetailsView and a GridView using Validation Groups
- Custom Pages Part 5 - I18N? Internationalisation Custom Page
Creating a Standard Custom Page
To customise a standard PageTemplate all you do is create a folder with the name of the entity collection (e.g. Order entity would have the folder Orders).
Figure 1 – Copy PageTemplate to CustomPages folder
All you do then is copy the PageTemplate you want to modify to the CustomPages sub-folder.
Figure 2 - Copying Details.aspx to the CustomPages <TableName>folder
Customising the Standard Custom Page
For out first step we will wire up the LinqDataSource to the Orders Table/Entity set, this will cause the column of the DetailsView to be updated see below.
<Fields> <asp:BoundField DataField="OrderID" HeaderText="OrderID" InsertVisible="False" ReadOnly="True" SortExpression="OrderID" /> <asp:BoundField DataField="CustomerID" HeaderText="CustomerID" SortExpression="CustomerID" /> <asp:BoundField DataField="EmployeeID" HeaderText="EmployeeID" SortExpression="EmployeeID" /> ...
<asp:BoundField DataField="ShipPostalCode" HeaderText="ShipPostalCode" SortExpression="ShipPostalCode" /> <asp:BoundField DataField="ShipCountry" HeaderText="ShipCountry" SortExpression="ShipCountry" /> </Fields>
Listing 1 – Columns collection from the Details.aspx
Now to edit his to take advantage of DynamicData:
<Fields> <asp:DynamicField DataField="OrderID" /> <asp:DynamicField DataField="Customer" /> <asp:DynamicField DataField="Employee" /> ...
<asp:DynamicField DataField="ShipPostalCode" /> <asp:DynamicField DataField="ShipCountry" /> </Fields>
Listing 2 – Updated columns collection from the Details.aspx
Here what I did was search and replace BoundField with DynamicField and remove all other unneeded properties (I used regular expressions to remove the extra fields here is the expression HeaderText=\".*\" SortExpression=\".*\" and replaced with an empty string), (these should come from the metadata from the column) then rearrange the order and replace the columns I didn’t want displaying with columns that I did (i.e. ShipVia with Shipper, CustomerID with Customer, etc) you can find the names of the EntitySet and EntityRef in the designer.cs/designer.vb file under the dbml file of your LinqToSql classes just drop the ‘_’ underscore at the beginning (you will see the actual property for each later on but this bit at the beginning always gets me what I want).
private EntitySet<Order_Detail> _Order_Details; private EntityRef<Customer> _Customer; private EntityRef<Employee> _Employee; private EntityRef<Shipper> _Shipper;
Listing 3 – from Northwind.designer.cs file
If we run the DynamicData website now we will get what seems similar to the default Details.aspx page, but missing the Edit and Delete links.
Now whart we need is to add Edit and Delete functionality again.
<asp:TemplateField> <ItemTemplate> <asp:HyperLink ID="EditHyperLink" runat="server" NavigateUrl='<%# table.GetActionPath(PageAction.Edit, GetDataItem()) %>' Text="Edit" /> <asp:LinkButton ID="DeleteLinkButton" runat="server" CommandName="Delete" CausesValidation="false" OnClientClick='return confirm("Are you sure you want to delete this item?");' Text="Delete" /> </ItemTemplate> </asp:TemplateField>
Listing 4 – copied from the original List.aspx
Here I’ve copied and pasted the TemplateField from the original List.aspx page to get the same functionality for Edit, Details and Delete.
Adding Master Details page funtionality
Now we add a GridView and LinqDataSource to the page for the Order_Details, (which all I did was copy the one from the List.aspx PageTemplate and then edit it).
<asp:GridView ID="GridView1" runat="server" DataSourceID="GridDataSource" AllowPaging="True" AllowSorting="True" CssClass="gridview"> <Columns> <asp:TemplateField> <ItemTemplate> <asp:HyperLink ID="EditHyperLink" runat="server" NavigateUrl='<%# table.GetActionPath(PageAction.Edit, GetDataItem()) %>' Text="Edit" /> <asp:LinkButton ID="DeleteLinkButton" runat="server" CommandName="Delete" CausesValidation="false" Text="Delete" OnClientClick='return confirm("Are you sure you want to delete this item?");' /> <asp:HyperLink ID="DetailsHyperLink" runat="server" NavigateUrl='<%# table.GetActionPath(PageAction.Details, GetDataItem()) %>' Text="Details" /> </ItemTemplate> </asp:TemplateField> </Columns> <PagerStyle CssClass="footer"/> <PagerTemplate> <asp:GridViewPager runat="server" /> </PagerTemplate> <EmptyDataTemplate> There are currently no items in this table. </EmptyDataTemplate> </asp:GridView> <asp:LinqDataSource ID="GridDataSource" runat="server" EnableDelete="true"> <WhereParameters> <asp:DynamicControlParameter ControlID="FilterRepeater" /> </WhereParameters> </asp:LinqDataSource> <br />
Listing 5 – Extra GridView and LinqDataSource which I copied from the List.aspx PageTemplate
Linking the two GridViews together is done in the customising of the LinqDataSource switch to design view of the Details.aspx page and find the new LinqDataSource and click on the tasks button:
Figure 3 – Configuring the LinqDataSource
Follow the wizard through and select Order_Details as the source table and then click on the Where button. Then configure the where expression to limit the list to the record in the DetailsView.
Figure 4 - Configure the where expression
Say yes to updating the GridViews column when asked. Then edit the GridView’s columns collection the same way we did the DetailsView’s fileds collection, edit the columns so that any EntitySets/EntityRefs are shown instead of their foreign keys.
Now if we run the app and choose Orders and then Details we will see something like this:
Figure 5 – Output from our custom Details.aspx page
We need to ad a new class level variable:
protected MetaTable table1;
Then the Page_Init must updated:
protected void Page_Init(object sender, EventArgs e) { DynamicDataManager1.RegisterControl(DetailsView1, true); DynamicDataManager1.RegisterControl(GridView1, false); }
Listing 6 – Updated Page_Init
Also in the Page_Load event handler add the following line right after one for that default table so that its metadata for the second table can be referenced:
table1 = GridDataSource.GetTable();
and then in the NavigateUrl declaration change table to table1
We need to put the edit capability back into the GridView to do this all we have to do is copy them from the List.aspx PageTemplate and then add them to the beginning of the Columns collection:
<asp:TemplateField> <ItemTemplate> <asp:HyperLink ID="EditHyperLink" runat="server" NavigateUrl='<%# table1.GetActionPath(PageAction.Edit, GetDataItem()) %>' Text="Edit" /> <asp:LinkButton ID="DeleteLinkButton" runat="server" CommandName="Delete" CausesValidation="false" Text="Delete" OnClientClick='return confirm("Are you sure you want to delete this item?");' /> <asp:HyperLink ID="DetailsHyperLink" runat="server" NavigateUrl='<%# table1.GetActionPath(PageAction.Details, GetDataItem()) %>' Text="Details" /> </ItemTemplate> </asp:TemplateField>
Listing 6 – Adding the Edit, Delete and Details functionality
As you can see from running the app again the Edit, Delete and Details functionality is back.
Figure 6 – With Edit, Delete and Details functionality
And we finish off by adding paging to the DetailsView
<asp:DetailsView ID="DetailsView1" runat="server" DataSourceID="DetailsDataSource" OnItemDeleted="DetailsView1_ItemDeleted" CssClass="detailstable" FieldHeaderStyle-CssClass="bold" AutoGenerateRows="False" DataKeyNames="OrderID" AllowPaging="True"> <PagerSettings Mode="NextPreviousFirstLast" />
Listing 7 – Adding paging to the DetailsView
I think that will do for this part of the series, we can add other features to the page in the next edition.
28 comments:
Thanks :-)
Thanks :-)
Stephen,
i did it the same way and i get a error message.
error CS0103: The name 'table1' does not exist in the current context.
its comming up when dynamic data tries to open the list.aspx page template.
Whats wrong?
It sounds like an error with your project youve not created a Linq to SQL DD website and then added an ADO.Net model or the otherway around?
Steve :D
p.s. try posting your problem here http://forums.asp.net/1145.aspx and give the whole error page as it helps a lot with diagnosing issues.
Hi Steve,
I'm having a problem when I copy a (listdetails) template into a custom page folder (as per your instructions) The errors say there's ambiguity because it's defined more than once... I tried changing the partial class name which works but becuase it is autogenerated it always reverts back.
Any help would be appreciated.
Cheers.
Mel
Hi Mel, can send me the the error as in copy an paste the error into an e-mail and I'll have a look.
Steve
steve@notaclue.net
Steve, what was the answer to Mels problem above, I get the same thing. Could it be because I am referencing a DataContext in an extrernal dll/namespace?
Thanks
Tom
See this thread http://forums.asp.net/t/1381287.aspx on the forum
Steve :D
I've followed this example and I've tried to add another datagrid to show the client data, I've added ClientID to DetailsView DataKeyNames, and I've added the where clause to the LinqDataSource of this new gridview:
asp:ControlParameter ControlID="DetailsView1" Name="CustomerID" PropertyName="SelectedValue" Type="String"
I've also added the ClientID column to detailsview, but it doesn't work.
It seems as if one could only bind the master details gridview to the master detailsview by using it's primary key.
Any ideas on how to solve this?
Hi Niner, if you have multiple child grids to show have a look at this article here •An Advanced FieldTemplate with a GridView this basically uses a field template that is a gridview and allows you to show children relationships in a gridview. ans Also see A variation of Part 1 with the Details and SubGrid in Tabs
Hope this is some use.
Steve :D
Would it be possible to have 'insert' functionality in the gridview?
Hi Niner, have a look at Dynamic/Templated Grid with Insert (Using ListView)
Steve :D
How can I make a custompage which will only show a few fields from five different tables?
I would create a view (if you don't need it to be updateable)
You can make a view updateable just give it a primary key and setup some SPROCS to do the Insert, Update and Delete.
Steve :D
Steve,
As has already been stated. You are a genius. Dynamic data websites have a lot of potential for me but I am struggling with some of the fundamentals of custom pages. Specifically right now, when I see that a list.aspx generated for a table provides a hyperlink reference "View tables" for the foreign key attributes and then automaically provide page parameters in the hyperlink ?ID=[foreigh key value] that posts the foreign p key back to the table that uses it as a primary key, I am having a hard time understanding
1. why/how these additional entries are generated in the gridview
2. why the foreign key is automatically used when passed to the related table and how the related table control knows how to use that foreign key to filter the displayed results.
Hi billgrowjr,
1. there are generated byt the foreign key relationship column the Linq to SQL and Entity Framewoke creates, the actual foreign key columns are always hidden,
2. the foreign key values are auto matically picked up by the relavent filter and the filter applied.
What version of DD are you using?
Steve :)
Hey there, I am just following along on your example there and I have a few questions:
I have a table (PurchaseOrders) and it has a one to many relationship with another table (LineItems)
I am using the scaffolding TRUE option, so visual studio generates all of the pages for me.
I am trying to get the PurchaseOrder Insert page to allow me to create a new PurchseOrder as well as add multiple LineItems to that PurchaseOrder and then insert into the database (a SQL server 2008 backend) at once.
Can I customise one of the dynamic pages to do this?
Yes you could, and I have a field template that does just that, see it here: http://csharpbits.notaclue.net/2008/09/dynamic-data-and-field-templates.html
Steve
Great. Thanks, I will read over the article now, cheers.
Will there be many differences between the dynamic-data-field template version you have listed, and the visual studio 2010 dynamic linq to sql asp.net 4.0 version I am using?
Yes there are a number of differences between DD1 and DD4 but none are killers just look at the Page_Init in both and you will quickly see them.
Steve
For all of those who copy a page from the pageTemplate folder to the CustomPages folder and get the table already exist some place else error, if you make the CustomPage folder plural and then attach that name to the end of the namespace, that should make everything works as the documentation describes. It worked for me after much frustration and back and forth over the months.
Thanks
A good point but that is specific to Web Application Project not Website project.
Steve
Hi Steve thanks for the post!
One question. How do I create a custom page for derived types?
I am able to create a custom page for my base type, but none of the pages for my derived types work. They all go to the standard page templates.
I have made sure that the folder names match the table names for the derived types to no avail.
Thanks
Hi Steve, thanks for the post!
I am able to create custom pages for a base type, but not for any of its derived types. I have made sure that the custom page folders match the names of the derived types database tables to no avail.
Is this a limitation of Dynamic Data?
Thank you.
Not sure what you mean by derived type, if you want you can just e-mail me directly, my address is in the top right of this site.
Steve
Hi Steve, Good Day!
I have been trying with your above post but due to difference of detailsview to formsview in DD4, I have not been able to progress. May you please suggest some way of doing the parent child page functionality (as your above post) in DD4. Better if using tabs for multi child tables :). THANKS
Hi Faizan, it would be real hard work getting that to work in DD now :) I have a new project coming out soon that has ALL my bits included in a new shiny Project Template you will be able to get it all then.
Steve
Post a Comment