Data Binding

Thus far, getting and setting of values in StateContext Data has been done programmatically, as has the formation of the Crumb Trail. Examples of some problems this approach can cause are:
  1. Bloated codebehinds – from maintenance, unit testability and reusability perspectives, the smaller the codebehind class the better
  2. Tight coupling – A business method might access StateContext Data which could make it dependent on a particular Navigation route
To remedy this the Navigation Framework has classes that extend the ASP.NET DataBinding Framework and allow almost all NavigationUI code to be removed from the codebehind and business methods (see table below). The only bit that cannot be removed relates to Hyperlink construction and will be tackled in the Navigation Hyperlink and Data Expression section.
Navigation DataBinding Support
Navigation Class ASP.NET Base Class Purpose
NavigationDataAttribute ValueProviderSourceAttribute Binds a StateContext Data item to a method parameter. The method parameter name identifies the item to bind to, but a custom Key can be used instead
NavigationDataParameter Parameter Binds a StateContext Data item to a Parameter object. The Key property identifies the item to bind to, if it is not provided the Name property will be used instead
NavigationDataSource DataSourceControl Supports 2-way DataBinding with StateContext Data as the DataSource. Used to bind Control properties to StateContext Data items. Use the square bracket (e.g. [key]) binding syntax
CrumbTrailDataSource DataSourceControl Supports 1-way DataBinding with StateController Crumbs as the DataSource. The Crumb class is the data item, so can bind to the NavigationLink and Title properties. Can also bind to the Crumb data items using the square bracket (e.g. [key]) binding syntax

The classes that allow code to be cleared from the codebehind and moved into the Design tab are the NavigationDataSource and CrumbTrailDataSource. They allow DataBinding to StateContext and CrumbTrail Data respectively.

The classes that relate to the removal of StateContext Data access from the business methods are NavigationDataAttribute and NavigationDataParameter. The former is for use in the value provider DataBinding framework provided by VS 2012; and the latter is for use in the DataSource binding mechanism prior to VS 2012.

Sample Web Site

The NavigationDataSource will allow the codebehind of Listing.aspx to be cleared, the CrumbTrailDataSource will allow the codebehind of Details.aspx to be cleared and the NavigationDataAttribute (NavigationDataParameter prior to VS 2012) will remove StateContext Data access from the methods in the PersonSearch class.

To begin, remove all the methods apart from the GridView1_CallingDataMethods event listener from the codebehind of Listing.aspx (and the associated OnClick attribute). Turn to the Design view and register the Navigation assembly at the top by adding the code below.

<%@ Register assembly="Navigation" namespace="Navigation" tagprefix="cc1" %>
The setting of StateContext Data from the TextBox values and vice versa will be handled by 2-way DataBinding with a NavigationDataSource control. So, wrap the search criteria (including the Search Button and CompareValidator) of Listing.aspx inside a FormView attached to a NavigationDataSource and an EditItemTemplate as shown below.

<asp:FormView ID="FormView1" runat="server" DataSourceID="NavigationDataSource1" DefaultMode="Edit">
	<EditItemTemplate>
		<asp:Label ID="Label1" runat="server" Text="Name" AssociatedControlID="TextBox1" />
		<asp:TextBox ID="TextBox1" runat="server" />
		<asp:Label ID="Label2" runat="server" Text="Min Date of Birth" AssociatedControlID="TextBox2" />
		<asp:TextBox ID="TextBox2" runat="server" />
		<asp:Button ID="Button1" runat="server" Text="Search" />
		<asp:CompareValidator ID="CompareValidator1" runat="server" ControlToValidate="TextBox2" EnableClientScript="False" ErrorMessage="date error" Operator="DataTypeCheck" Type="Date" />
	</EditItemTemplate>
</asp:FormView>
<cc1:NavigationDataSource ID="NavigationDataSource1" runat="server">
</cc1:NavigationDataSource>

Pressing F5 will display the Person List although the search criteria no longer filter the list. So, set the Text properties of the two TextBoxes via the two-way DataBinding expression, using the keys that were previously assigned to the StateContext Data as shown below.

<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("[name]") %>' />
<asp:Label ID="Label2" runat="server" Text="Min Date of Birth" AssociatedControlID="TextBox2" />
<asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("[minDateOfBirth]") %>' />
Pressing F5 will display the Person List but the search criteria still do not filter the list. Set the Search Button’s CommandName attribute to ‘Update’ (see below). This will update the NavigationDataSource and the Text Box Text strings will be set into StateContext Data.

<asp:Button ID="Button1" runat="server" Text="Search" CommandName="Update" />
However, this still does not allow the Person List to be filtered because the GridView has not been refreshed. The NavigationDataAttribute will get around this problem. Adding name and minDateOfBirth parameters, adorned with NavigationDataAttributes, to the Search method will cause the latter to be called whenever there is a change in either of these parameters and to rebind the GridView accordingly. This means the StateContext Data access can be removed from the method body, using the method parameters instead, as shown below.

public IEnumerable Search([NavigationData] string name, [NavigationData] string minDateOfBirth)
{
	return from p in _People
			where (name == null || p.Name.ToUpperInvariant().Contains(name.ToUpperInvariant()))
			&& (minDateOfBirth == null || p.DateOfBirth >= DateTime.Parse(minDateOfBirth))
			select new
			{
				p.Name,
				p.DateOfBirth,
				Link = StateController.GetNavigationLink("Select", new NavigationData() { { "id", p.Id } })
			};
}
This time Pressing F5 will display the Person List with fully functioning search criteria. Searching on an invalid date works without adding any code as this is a by-product of using DataBinding since the NavigationDataSource will only be updated if the Page is valid.

The same treatment can be done to the Details.aspx Page. First, remove the Page_Load method from its codebehind. This has stopped the Hyperlink from the Details back to the Listing from working, but the CrumbTrailDataSource will be used to restore this functionality. Register the Navigation assembly at the top of the Design view. Delete the Hyperlink and replace it with a ListView, DataBound to the CrumbTrailDataSource, containing a Hyperlink with its NavigateUrl property one-way bound to the NavigationLink Property of the Crumb class (see below).

<asp:ListView ID="ListView1" runat="server" DataSourceID="CrumbTrailDataSource1" ItemPlaceholderID="PlaceHolder1">
	<LayoutTemplate>
		<asp:PlaceHolder ID="PlaceHolder1" runat="server" />
	</LayoutTemplate>
	<ItemTemplate>
		<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%# Eval("NavigationLink") %>'>Listing</asp:HyperLink>
	</ItemTemplate>
</asp:ListView>
<cc1:CrumbTrailDataSource ID="CrumbTrailDataSource1" runat="server" />
Add an id parameter, adorned with a NavigationDataAttribute, to the GetDetails method and remove the StateContext Data access from the method body, as shown below.

public Person GetDetails([NavigationData] int id)
{
	return (from p in _People
			where p.Id == id
			select p).First();
}
Pressing F5 will display fully functioning Listing and Details Pages.

Last edited Aug 4, 2013 at 6:26 PM by GrahamMendick, version 4