Wijmo Open for Juice UI is quite cool and offers an alternative to using Ajax Control Toolkit which is still cool but Wijmo Open for Juice UI supports IE6+, Firefox 3+, Safari 3+, and Chrome browsers which should mean everything works.
I started customising Entity Templates here Custom Entity Templates – Dynamic Data 4 I decided to take this a little further and create a Tabbed UI for editing really long forms, I have done this with the Ajax Control Toolkit but thought I like to have a jQuery UI version which brings theming to the table.
Creating the Entity Template
Figure 1 – Wijmo tabs in action
<asp:Panel ID="Panel1" runat="server"> <ul> <li><a href="#tabs-1">Nunc tincidunt</a></li> <li><a href="#tabs-2">Proin dolor</a></li> <li><a href="#tabs-3">Aenean lacinia</a></li> </ul> <div id="tabs-1"> <p> Proin elit arcu, rutrum commodo, vehicula tempus...
</p>
</div> <div id="tabs-2"> <p> Morbi tincidunt, dui sit amet facilisis feugiat...
</p> </div> <div id="tabs-3"> <p> Mauris eleifend est et turpis. Duis id erat...
</p> </div> </asp:Panel> <wijmo:WijTabs ID="Tabs1" runat="server" TargetControlID="Panel1"> </wijmo:WijTabs>
Listing 1 – mark-up to create the Wijmo tabs
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.
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.
protected override void OnLoad(EventArgs e) { var groupAttribute = Table.GetAttribute<GroupNamesAttribute>(); 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<String, HtmlGenericControl>(); // 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<GroupAttribute>().Index == gi.Key orderby c.GetAttributeOrDefault<DisplayAttribute>().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("<a href=\"#{0}\" >{1}</a>", 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); }
Listing 2 – the main code for the Entity Template
Figure 2 – the finished Wijmo Tabs EntityTemplate
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.
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 }); }
Listing 3 – setting up the project Global.asax.cs
[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<DateTime> 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<DateTime> HireDate { get; set; } [Group(1)] [Display(Order = 9)] public Employee Manager { get; set; } [Group(1)] [Display(Order = 10)] public Nullable<int> ReportsTo { get; set; } [Group(1)] [Display(Order = 10)] public EntityCollection<Employee> Staff { get; set; } [Group(1)] [Display(Order = 11)] public EntityCollection<Order> Orders { get; set; } [Group(1)] [Display(Order = 12)] public EntityCollection<Territory> 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; } } }
Listing 4 – Sample Metadata
You will also need NuGet and add the Wijmo Open for Juice UI to your project.
Later I will add all the features that you get with jQuery UI such as tab sorting and alignment see the online Juice Explorer for all the features.
Just for good measure I have added the Wijmo Accordion to the project
Figure 3 – Wijmo Accordion Entity Template
You can of course get even more by getting Studio for Studio for ASP.NET Wijmo from ComponentOne this is the best thing for ASP.Net I have seem come out for a while as everyone else seems to be concentrating on either pure client or MVC
Download from my sky drive WijmoTabs.zip