User Interface

Labels
AJAX(112) App Studio(8) Apple(1) Application Builder(245) Application Factory(207) ASP.NET(95) ASP.NET 3.5(45) ASP.NET Code Generator(72) ASP.NET Membership(28) Azure(18) Barcode(2) Barcodes(3) BLOB(18) Business Rules(1) Business Rules/Logic(140) BYOD(13) Caching(2) Calendar(5) Charts(29) Cloud(14) Cloud On Time(2) Cloud On Time for Windows 7(2) Code Generator(54) Collaboration(11) command line(1) Conflict Detection(1) Content Management System(12) COT Tools for Excel(26) CRUD(1) Custom Actions(1) Data Aquarium Framework(122) Data Sheet(9) Data Sources(22) Database Lookups(50) Deployment(22) Designer(177) Device(1) DotNetNuke(12) EASE(20) Email(6) Features(101) Firebird(1) Form Builder(14) Globalization and Localization(6) How To(1) Hypermedia(2) Inline Editing(1) Installation(5) JavaScript(20) Kiosk(1) Low Code(3) Mac(1) Many-To-Many(4) Maps(6) Master/Detail(36) Microservices(4) Mobile(63) Mode Builder(3) Model Builder(3) MySQL(10) Native Apps(5) News(18) OAuth(9) OAuth Scopes(1) OAuth2(13) Offline(20) Offline Apps(4) Offline Sync(5) Oracle(11) PKCE(2) Postgre SQL(1) PostgreSQL(2) PWA(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(184) Reports(48) REST(29) RESTful(29) RESTful Workshop(15) RFID tags(1) SaaS(7) Security(81) SharePoint(12) SPA(6) SQL Anywhere(3) SQL Server(26) SSO(1) Stored Procedure(4) Teamwork(15) Tips and Tricks(87) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(338) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(40) Web.Config(9) Workflow(28)
Archive
Blog
User Interface
Saturday, March 31, 2012PrintSubscribe
Auto Select in Data Views

Complex master/detail pages in Code On Time web applications are hiding detail records until a specific master record is selected.

For example, this is the initial state of the Suppliers page in the Northwind sample. This page is capable of rendering a list of suppliers with their respective products. If a master supplier is not selected then the Products child data view is not visible.

The initial state of the master/detail page 'Suppliers' without a selected master record.

Users can click on a link in the first column to activate the Suppliers form view. This will result in the linked products displayed at the bottom of the page below the form.

You can configure an application data view to simulate a click on a link in the first column of the first row as soon as a page loads in the web browser.

Start web application generator, select the project name, and activate the Project Designer.

Select Suppliers / container1 / view1 in Project Explorer.

Page data view selected in the Project Explorer

Enable property “Auto Select First Row” under Presentation section of the data view properties and click OK to save the changes.

Data view property 'Auto Select First Row' in the Project Designer

Click Browse on the tool bar and navigate to the Suppliers page. The very first row in the master view of suppliers will be selected. Products from the selected supplier are displayed beneath the form view.

Property 'Auto Select First Row' causes automatic execution of the first action in the action group with the 'Grid' scope.

Setting the Auto Select First Row property to True causes automatic execution of the first action in the action group with the “Grid” scope.

The default configuration of this action group in shown next. As you can see the first row will be selected in the form view editForm1 if a user clicks on a link in the first column. The same effect is caused by Auto Select First Row property when page loads in the web browser.

Action group with scope 'Grid' expanded in Project Explorer

Right-click action group ag1 and select Show All Actions option.

Context menu of the action group in Project Explorer

Select the action group ag2 in Project Designer and click Up on the tool bar.

Changing the order of actions in the action group

The hierarchy of nodes in Project Explorer will change. Action a2 with command name Edit is now the first action in the action group ag1 with the scope of “Grid”. Note that this action does not have a view specified as the command argument.

Modified action group in Project Explorer

Click Browse button on the tool bar of Project Designer and navigate to the Suppliers page once more. The first row is selected and presented in edit mode.

'Edit' action executed without an argument on a page with the master data view that has its property  'Auto Select First Row' set to 'True'

Saturday, March 31, 2012PrintSubscribe
Auto Highlight in Data Views

The following screen shot shows the automatically generated page Suppliers from the Northwind sample. If you navigate to the page and sort or filter records then only the master data view Suppliers is visible.

Standard master/detail page 'Suppliers' in the 'Northwind' sample created with Code On Time web application generator

Click on any data row and it will become highlighted. Linked detail records will be displayed at the bottom of the page.

Linked 'Products' are displayed if a user clicks on a master row of 'Suppliers' view

Sometimes it may be desirable to highlight the first row in the master view automatically.

Start the application generator, click on the project name, choose Design, and select the master data view of the page in Project Explorer.

Data view selected in Project Explorer

Check the box labeled “Auto Highlight First Row” under the Presentation section of the data view properties and click OK.

'Auto Highlight First Row' property of a data view

Click Browse button on the tool bar to view the page in the web browser.

The very first visible row will be automatically highlighted. Linked details will be displayed as well.

The initial state of the page loaded in a web browser if 'Auto Highlight First Row' property of the master view is enabled

Thursday, March 29, 2012PrintSubscribe
Workflow Dashboard Demo

Fast paced and hectic business days exert a high toll on information workers. Having summary views of the current task items replaces digging and searching through numerous screens in a line-of-business application.

Well constructed summary task views will reflect the actual workflow of the business process. Summary views ensure happy and productive business users. Throw in automatic task view refreshing without any intervention and the level of happiness in application users is likely to increase even more.

Objective

Consider the home page of the Northwind sample. We can greatly improve the life of folks working in the shipping department by replacing the standard site map and login instructions with the summary of orders waiting to ship and orders that were shipped late. Both workflow task views will refresh at predefined intervals.

Standard home page of the Northwind sample created with Code On Time web application generator

This is how the home page of the application may look.

'Summary Task Views' in the Northwind sample reflect the workflow of the shipping deparment

Changing Home Page

Select the project name on the start page of the web application generator and click Design.

Expand the Home node in the Project Explorer and delete the user control instances Home / container1 / control1 and Home / container2 / control2. Right-click each control node and choose Delete option to delete a control instance.

Deleting a user control instance from a page container

Change the properties of Home / container2 as follows and click OK button.

Property Value
Flow New Row
CSS Style Properties margin-top:8px;

Right-click Home / container1 and add a new data view to the container.

Adding a new data view to a page container

Enter the properties of the data view as shown in the table and save changes.

Property Value
Controller Orders
View grid1
Tag OrdersWaitingToShip
Text Orders Waiting to Ship
Page Size 5
Show View Description False
Show View Selector False
Refresh Interval 30

Add another data view to Home / container2. This time the properties of the data view are slightly different.

Property Value
Controller Orders
View grid1
Tag OrdersShippedLate
Text Orders Shipped Late
Page Size 5
Show View Description False
Show View Selector False
Refresh Interval 300

Click OK button to save the properties of the second data view. The Home page node in the Project Explorer will look as follows.

image

Click Browse button to preview the changes.

Modified start page of the Workflow Dashboard Demo with two identical views of 'Orders'

The start page of the application shows two identical data views of Orders. Both views allow changing any orders on screen and show the entire set of orders stored in the database.

Enabling Dedicated Login Page

The home page of the Northwind sample application is not protected. Anonymous users can see the contents of the page. Users are authenticated by entering name and password in the fly-over login window. The login window is activated when users hover over the “Login” link in right-hand corner of the membership bar at the top of the page.

Standard fly-over login window in a Code On Time web application

Perform the following steps to hide the home page from anonymous users.

Exit the Project Designer and click Settings.

Select  Authentication and Membership option in the menu and proceed to Login Window section. Enable a dedicated login page instead of a fly-over login window.

Activating a dedicated login page in Code On Time web application

Click Finish to save the changes.

The application baseline needs to be refreshed. Select Refresh option on the project Summary page.  The Refresh dialog will be displayed with the list of application data controllers.

Project Refresh dialog in Code On Time web application generator

Do not select anything in the list. Simply click the Refresh button at the bottom of the dialog to complete the refresh process.  A dedicated login page will be created next time you re-generate the application.

Enabling Shared Business Rules

We will change the appearance of the Orders on the Home page with the help of data controller virtualization and dynamic access control rules supported in the application framework. This will require writing some code.

For the purpose of this demo we will create a SharesBusinessRules class. Click Settings on the project Summary page and continue to Business Logic Layer. Activate shared business rules and click Finish. You will arrive back to the project Summary page. Proceed to generate the application.

You will be greeted by the dedicated login page when the code generation completes.

Standard dedicated login page in a Code On Time web application

The application framework creates an instance of SharedBusinessRules class whenever you access a page that displays data.  Page data views send requests to your application. Instances of business rules are created to service each and every request.

You will not see any effect of shared business rules at this time - custom business logic has not been implemented yet.

Altering Presentation of Orders on Home Page

First we will change the appearance of orders waiting to ship and orders that were shipped late.

Select the project name on the start page of the application generator and click Develop. The project source code will be displayed in Visual Studio or Visual Web Developer.

Open the file ~/App_Code/Rules/SharedBusinessRules.cs(vb) in the text editor of your development environment.

Replace the default implementation with the following code.

C#:

using System;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using MyCompany.Data;

namespace MyCompany.Rules
{
    public partial class SharedBusinessRules : MyCompany.Data.BusinessRules
    {
        public override bool SupportsVirtualization(string controllerName)
        {
            if (controllerName == "Orders" && IsTagged("OrdersWaitingToShip", 
"OrdersShippedLate")) return true; return false; } } }

Visual Basic:

Imports MyCompany.Data
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Linq

Namespace MyCompany.Rules

    Partial Public Class SharedBusinessRules
        Inherits MyCompany.Data.BusinessRules

        Public Overrides Function SupportsVirtualization(controllerName As String) As Boolean
            If controllerName = "Orders" AndAlso IsTagged("OrdersWaitingToShip", 
"OrdersShippedLate") Then Return True End If Return False End Function End Class End Namespace

Our application will detect when Orders data controller is supposed to produce data in response to the requests from the Orders data views located on the Home page. The code verifies the controller name and ensures that the requesting data views are tagged as OrdersWaitingToShip or OrdersShippedLate.  If the method SupportsVirtualization returns true then the application framework will give business rules a chance to modify the definition of the Orders data controller.

We do not want any virtualization changes to go beyond the home page. If users visit the automatically generated Orders page, then no unusual behavior will be seen there.

Now it is time to decide what are we going to change in the presentation of orders on the Home page.

We will:

  • make the controller read-only by removing editing actions;
  • delete all remaining actions in the context menu of the grid view;
  • add new 'Navigate'  action redirecting application user to the “unchanged” Orders page when an order is selected in grid view;
  • hide “ShippedDate” data field in the “orders waiting to ship” view;
  • sort “orders waiting to ship” in ascending order of “RequiredDate”;
  • add “ShipCountry” data field to the “orders waiting to ship”;
  • sort “orders shipped late” in descending order of “RequiredDate”;
  • rearrange “orders shipped late” in such a way that “ShippedDate”, “EmployeeID”, and “ShipCity”  are displayed first.

These sound like a handful!

The snippet of the Orders controller shows the content that must be affected by our modifications.

<?xml version="1.0" encoding="utf-8"?>
<dataController name="Orders" conflictDetection="overwriteChanges" label="Orders" 
                xmlns="urn:schemas-codeontime-com:data-aquarium">
  . . . . .
  <views>
    <view id="grid1" type="Grid" commandId="command1" label="Orders">
      <headerText>$DefaultGridViewDescription</headerText>
      <dataFields>
        <dataField fieldName="CustomerID" aliasFieldName="CustomerCompanyName" />
        <dataField fieldName="EmployeeID" aliasFieldName="EmployeeLastName" />
        <dataField fieldName="OrderDate" columns="10" />
        <dataField fieldName="RequiredDate" columns="10" />
        <dataField fieldName="ShippedDate" columns="10" />
        <dataField fieldName="ShipVia" aliasFieldName="ShipViaCompanyName" />
        <dataField fieldName="Freight" dataFormatString="c" columns="15" />
        <dataField fieldName="ShipName" columns="40" />
        <dataField fieldName="ShipAddress" />
        <dataField fieldName="ShipCity" columns="15" />
      </dataFields>
    </view>
  . . . . .
  <actions>
    <actionGroup id="ag1" scope="Grid">
      <action id="a1" commandName="Select" commandArgument="editForm1" />
      <action id="a2" commandName="Edit" />
      <action id="a3" commandName="Delete" />
      <action id="a6" />
      <action id="a7" commandName="Duplicate" commandArgument="createForm1" />
      <action id="a8" commandName="New" commandArgument="grid1" />
    </actionGroup>
    <actionGroup id="ag2" scope="Form">
      <action id="a1" commandName="Edit" />
      <action id="a2" commandName="Delete" />
      . . . . .
    </actionGroup>
    <actionGroup id="ag3" scope="ActionBar" headerText="New" flat="true">
      <action id="a1" commandName="New" commandArgument="createForm1" cssClass="NewIcon" />
    </actionGroup>
    <actionGroup id="ag4" scope="ActionBar" headerText="Edit/Delete" flat="true">
      <action id="a1" whenKeySelected="true" commandName="Edit" commandArgument="editForm1" 
              cssClass="EditIcon" whenView="grid1" />
      <action id="a2" whenKeySelected="true" commandName="Delete" 
              cssClass="DeleteIcon" whenView="grid1" />
    </actionGroup>
    <actionGroup id="ag5" scope="ActionBar" headerText="Actions">
      . . . . .
      <action id="a6" commandName="Import" commandArgument="createForm1" />
    </actionGroup>
  </actions>
</dataController>

Making changes to the data controller in a text editor would not be difficult. One could copy, rename, move, and change various portions of the file to accomplish the desired result.

We don’t want to change the static definition of the data controller.
Multiple versions of the same controller are not welcomed either  -
this would become a maintenance nightmare.

Data Controller Virtualization comes to the rescue. It allows conditional modification of the data controller at runtime. Developer becomes a true magician and dynamically alters the actual definition of the controller based on a given use case.

Add the following implementation of the method VirtualizeController to the SharedBusinesRules class. The implementation takes advantage of the method BusinessRules.NodeSet() and molds the data controller definition at runtime according to the specification suggested above.

C#:

protected override void VirtualizeController(string controllerName)
{
    if (controllerName == "Orders" && IsTagged("OrdersWaitingToShip", "OrdersShippedLate"))
    {
        // make the controller read-only by removing editing actions
        NodeSet("action[@commandName = $name]",
            "New", "Edit", "Delete", "Duplicate", "Import").Delete();
        // delete all remaining actions in the 'Grid' scope 
        NodeSet("actionGroup[@scope='Grid']")
            .Select("action").Delete();
        // add new 'Navigate' action to the 'Grid' scope 
        NodeSet("<action>")
                .Attr("commandName", "Navigate")
                .Attr("commandArgument",
                        "Orders.aspx?OrderID={OrderID}&_controller=Orders" +
                        "&_commandName=Edit&_commandArgument=editForm1")
                .AppendTo("c:actionGroup[@scope='Grid']");
    }
    if (IsTagged("OrdersWaitingToShip"))
    {
        // sort 'grid1' and hide the 'ShippedDate' data field
        NodeSet("view[@id='grid1']")
            .Attr("sortExpression", "RequiredDate asc")
            .Select("dataField[@fieldName='ShippedDate']")
            .Attr("hidden", "true");
        // add data field 'ShipCountry' to 'grid1' view
        NodeSet("<dataField>").Attr("fieldName", "ShipCountry")
            .AppendTo("view[@id='grid1']/dataFields");
    }
    if (IsTagged("OrdersShippedLate"))
        // sort and rearrange 'grid1' by placing ShippedDate, EmployeeID, and ShipCity first
        NodeSet("view[@id='grid1']")
            .Attr("sortExpression", "RequiredDate desc")
            .Select("dataField")
            .Arrange("@fieldName", "ShippedDate", "EmployeeID", "ShipCity");
}

Visual Basic:

Protected Overrides Sub VirtualizeController(controllerName As String)
    If (controllerName = "Orders" AndAlso IsTagged("OrdersWaitingToShip", "OrdersShippedLate")) Then
        ' make the controller read-only by removing editing actions
        NodeSet("action[@commandName = $name]",
            "New", "Edit", "Delete", "Duplicate", "Import").Delete()
        ' delete all remaining actions in the 'Grid' scope 
        NodeSet("actionGroup[@scope='Grid']") _
            .Select("action").Delete()
        ' add new 'Navigate' action to the 'Grid' scope 
        NodeSet("<action>") _
            .Attr("commandName", "Navigate") _
            .Attr("commandArgument",
                "Orders.aspx?OrderID={OrderID}&_controller=Orders" +
                "&_commandName=Edit&_commandArgument=editForm1") _
            .AppendTo("c:actionGroup[@scope='Grid']")
    End If
    If (IsTagged("OrdersWaitingToShip")) Then
        ' sort grid1 and hide the 'ShippedDate' data field
        NodeSet("view[@id='grid1']") _
            .Attr("sortExpression", "RequiredDate asc") _
            .Select("dataField[@fieldName='ShippedDate']") _
            .Attr("hidden", "true")
        ' add data field 'ShipCountry' to 'grid1' view
        NodeSet("<dataField>").Attr("fieldName", "ShipCountry") _
            .AppendTo("view[@id='grid1']/dataFields")
    End If
    If (IsTagged("OrdersShippedLate")) Then
        ' sort and rearrange 'grid1' by placing ShippedDate, EmployeeID, and ShipCity first
        NodeSet("view[@id='grid1']") _
            .Attr("sortExpression", "RequiredDate desc") _
            .Select("dataField") _
            .Arrange("@fieldName", "ShippedDate", "EmployeeID", "ShipCity")
    End If
End Sub

The code only executes when the data is requested from the home page by the views tagged as OrdersWaitingToShip and OrdersShippedLate. Go ahead and take a look at the effect of modifications in the web browser.

Presenting Orders Waiting To Ship or Shipped Late

We need to filter both home page data views to show a specific subset of orders reflecting the view’s purpose. The following implementation of method EnumerateDynamicAccessControlRules will do the job.

C#:

protected override void EnumerateDynamicAccessControlRules(string controllerName)
{
    if (IsTagged("OrdersWaitingToShip"))
        RegisterAccessControlRule("OrderID",
            "[ShippedDate] is null",
            AccessPermission.Allow);
    if (IsTagged("OrdersShippedLate"))
        RegisterAccessControlRule("OrderID",
            "[ShippedDate] is not null and [RequiredDate] < [ShippedDate]",
            AccessPermission.Allow);
}

Visual Basic:

Protected Overrides Sub EnumerateDynamicAccessControlRules(controllerName As String)
    If (IsTagged("OrdersWaitingToShip")) Then
        RegisterAccessControlRule("OrderID",
            "[ShippedDate] is null",
            AccessPermission.Allow)
    End If
    If (IsTagged("OrdersShippedLate")) Then
        RegisterAccessControlRule("OrderID",
            "[ShippedDate] is not null and [RequiredDate] < [ShippedDate]",
            AccessPermission.Allow)
    End If
End Sub

The data view tagged as OrdersWaitingToShip will show the orders with the empty “ShippedDate”.

The data view tagged with OrdersShippedLate will show the orders that were shipped but the required date is less than the shipped date.

Analyzing Dashboard Capabilities

Here is the dashboard reflecting the business workflow of the shipping department at our fictitious mail order company Northwind.

Completed 'Workflow Dashboard' with 'Summary Task Views' in the Northwind sample reflecting the business workflow of the shipping deparment

Users are not able to change data in the views. The row context menu is not displayed when users move the mouse pointer over the links in the first column. Action bar does not display New Orders and Import actions.

Columns in the grid views are rearranged.

The top view is sorted in ascending order of “Required Date”. Column “Shipped Date” is not displayed.

The bottom view is sorted in descending order of “Required Date”. The first columns are “Shipped Date”, “Employee ID” (aliased with “Employee Last Name”), and “Ship City”.

The top view is automatically refreshed every 30 seconds. The bottom one is refreshed every 5 minutes. The refreshing happens if user is not interacting with the views longer than their respective refresh intervals.

If a user clicks on any link in the first column of either grid view then the web browser will navigate to the Orders page. The page will open with the selected order presented in edit mode.

'Orders' page displayed when a user selects an order on the dashboard

Users can edit or add  new Order Details while remaining on the same Orders page.

Users will be transferred back to the home page as soon they click on OK or Cancel buttons in the Orders form.

Notice that the automatically generated Orders page is not affected by virtualization rules. Navigate to the Orders page by selecting Customers / Orders menu option and you will see the default layout of the grid view and data editing  commands unchanged.

URL Hashing

Look close at the URL in the address bar of the browser when user navigates to the Orders page. You will see something like this:

Data controller URL parameters displayed in the web browser address bar.

You can easily spot the OrderID and data controller URL parameters activating the edit mode of the order form.

Sometimes you do not wish to reveal this information.

Select the project name on the start page of the application generator and click Settings. Continues to Features and activate EASE Configuration. Enable the URL Hashing option.

Enabling URL Hashing in the project created with Code On Time web application generator

Click Finish button and generate the app. Select any order and observer that the URL is not as revealing as previously.

Data controller URL parameters are 'hidden' if URL Hashing is enabled in a Code On Time web application

Any attempts to alter the URL will result in Access Denied message. Learn about URL Hashing.

Conclusion

Data Controller Virtualization enables rapid development of complex workflow dashboards. Developers can treat the core application data controllers as a collection of building blocks. Developers can  alter the definition of data controllers based on arbitrary conditions such as user identity or use case of the data controller as was explained above.

Virtualization plugins allows rapid development of virtualization rules by eliminating the need to use XML elements in the node sets.

Continue to Web App Themes V-Y