The UltraWebGrid control provided by Infragistics offers abundant functionality. However, implementing the UltraWegGrid in a professional application environment requires some thinking and customization as well. This article describes a real life implementation scenario.
You should not expect that the UltraWebGrid does the job right out of the box. Although the code base of the web controls from Infragistics is well documented, those who are new to the UltraWebGrid might want to see a complete picture of how it can be implemented under real life conditions.
Currently no place in the web seems to be providing this for free.
In this article I address a couple of important findings that should be relevant for any developer using the UltraWebGrid. Some aspects go beyond the Infragistics stuff and should be considered general design recommendations. I expect that you are already familiar with the basic functionality of the UltraWebGrid control and will not explain basics such as how to add and configure grid columns. It is also recommended that you make yourself familiar with custom inheritance controls and user controls.
The source code of the application I am using is monstrous, and cannot be shared in this article. Please do not expect source code that you can just copy and use. I am just using code snippets for better understanding. However, the code is presented in a meaningful context covering code behind and client script.
You need to transfer this knowledge into your context. It took me a couple of days to find out about all these issues and I hope this article can prevent you from going through the same painful experience.
In this article the Client Side Object Model of the Infragistics controls is referred to as CSOM.
I will refer to the UltraWebGrid as CustUltraWebGrid because I use a custom control that inherits from UltraWebGrid. If you don't use a custom control, the grid is referred to as UltraWebGrid.
- Implement the grid with all data editing related functionality enabled. The objective is to create a friendly user interface keeping in mind that this will result in more load for the server.
- The application must support remote users; therefore page state must not be transmitted in the view state included in the page. Page state persisting should be used instead. The page state persistence medium shall be configurable in session, cache, database or even the file system.
Note: Do not try to code around the page state of the UltraWebGrid. You need the page state in order to enjoy the best features of the grid. I tried to get along without page state using the control state of the grid. However, I had to abandon this attempt for the sake of productivity and returned to using page state. Now I persist the page state on the server instead of moving it across the wire as the page's view state.
Desired Behaviors of the Grid Control
The desired behaviors explained below are definitely worth reading. I believe that much of that matches with what you would expect from a well designed grid control.
The records shall be displayed as a hierarchy therefore multiple bands must be supported.
1. New rows must be added on the client side without resubmitting the page after a row was added until the save button for the grid or for the entire page is pressed.
2. Rows shall be deleted by clicking on a delete button in the row. The delete key on the keyboard shall be disabled. A post back shall be initiated whenever a row is deleted which exists in the database already. The code behind on the server will then actually delete the record from the database.
3. New rows that have not been submitted or that did not pass validation shall be deleted on the client side without resubmitting the page after the row was deleted.
4. The default add box of the UltraWegGrid which contains the buttons for adding new rows shall be replaced by an image button. Clicking the image button shall add a new record to the highest level of the grid without causing a post back.
5. Adding new child records to an existing parent row shall be handled by an add button in the grid row as this is by far more user friendly than the default add buttons for multiple bands provided by the grid.
6. The rows in the grid shall provide buttons that redirect from the list view to the editable form view of the selected entity. These buttons shall be functional only for those records that are already present in the dataset. No post back shall be caused when the record has not been submitted or failed validation.
The final product should look like the following example of a multiband grid that is used by the configuration client of a web application:
Figure 1: Screenshot of the final product
Don't get confused by the German shown in the grid. The application supports database configured localization. I have not yet translated this screen.
At the top of the page you can see a webpage with an UltraWebToolbar provided by the master page assigned to the page. Then we have an UltraWebTab managing the access to the functions of the module chosen. Below the tab items there is another UltraWebToolbar control. This toolbar is part of the webpage. Finally there is an UltraWebGrid which supports up to 6 bands. Each row has got a green add button and a red delete button. Clicking the add button adds a new child row to the selected row. Clicking the delete button deletes the selected row. All the behaviors explained previously are fully implemented.
The add button for adding a row to the highest level of the hierarchy can be found at the bottom of the grid control. There is a bar comprising of four asp image buttons.
Figure 2: Bar with command buttons
The following screenshot shows a grid which includes the buttons for adding and deleting new records as well as two buttons that cause a postback and a server transfer to the detail pages.
Figure 3: The grid with inline command buttons
Implement the UltraWebGrid as an Inheritance Control
The grid control itself should be implemented as a custom control. I suggest that you create a custom control that inherits from the
UltraWebGrid class. All standard functionality that you need in connection with a grid should be implemented in that custom control. My implementation has got almost everything, but that is by far too much to share at this point. The following example shows only the code regions for the functionality that I added to my custom grid control. The methods behind the regions may be subject for a future article.
Listing 1: Class File for Custom Control derived from UltraWebGrid
I also suggest that you do not put all the grid related functionality in the user control that I will cover in the next paragraph. There are situations where you might want to use the pure grid control without all the other components included in the user control. Therefore it's quite reasonable to have the core functionality included in the custom grid class.
Create a user Control for the Custom Grid Control and all other Controls that are needed to manipulate Data in a Grid
In most cases a grid control needs additional controls such as a header row and a grid specific toolbar at the bottom. The best way to do this seems to be a user control that contains all the controls. This is the user control that I am using:
Listing 2: XHTML File of the User Control
Please note that the event handlers
OnClickCellButton represent server side events. Your code behind must contain these methods for server side processing. The buttons defined in the toolbar container also have server side event handlers assigned:
I should mention that I am using themes and that all assemblies are registered in the web.config. That is why the XHTML file looks so clean. In the following article I will refer to the
CustUltraWebGrid because I use a custom control that inherits from
UltraWebGrid. If you don't use a custom control the grid is referred to as
Make sure the Client can react on the custom add Record Button
New records shall be added to the grid by clicking the custom add button in the button bar at the bottom of the custom grid control instead of using the default buttons provided by the grid control.
Figure 4: Bar with command buttons
This button is used to add a new row to the highest level of the grid. The grid column buttons will be covered later. The image button named "ButtonAdd" in the user control has no server side event handler assigned because we do not want a postback being fired when this button gets pressed. However, we want that the client can react on the button. The client should also identify the name of the button and the name of the grid to which the button belongs, keeping in mind that a page can contain multiple grid user controls.
The following code needs to be added to the grid user control in the code behind (where
this refers to the Grid Control in the code behind):
This will ensure that the event handler
AddNewRow in the client script will be called whenever the button is clicked.
The event handler in the script expects that the name of the button includes the server id of the grid. We will need the server id of the grid control later to resolve the client id of the grid.
In this example the grid id includes underscores because I use grid names like
GRID_GRIDMAIN_1. The client replaces underscores with the character
x. Therefore all instances of underscore need to be replaced with
At this point the client will be able to react to the button being clicked, provided that the event handler is added to the client script. However, clicking the add button will still result in a postback. This is not the desired behavior because we want rows to be added by the client
Make sure the Image Button ID="ButtonAdd" does not cause a postback when clicked
The image button does not provide a property for deactivating auto postback. The desired result can be accomplished by adding the following attribute to the image button:
This is a kind of no operation for the button. It works for both ASP.NET buttons and ASP.NET image buttons. At this point the client can theoretically react to the button and will not cause a post back when the button is clicked.
Add the buttons to the bands of your grid control
Add the buttons to the band of your grid as usual. I suggest that you add and configure grid buttons programmatically. I assume that you are already familiar with the basic functionality of the UltraWebGrid.
Listing 5: Adding the Button Columns to the Grid Control
Enable the Client to add and delete Rows
Listing 6: Configuring the Display Layout of the Grid Control
The CSOM of the grid knows the properties
Theoretically it should be possible to allow adding and deleting rows by setting
AllowDelete=1 in the client script, but this does not work as described. Therefore we need to get along with applying these settings on the server side.
Enable the Client to handle the Events needed to add and delete Rows on the Client Side using Grid Column Buttons.
Add the following client side events to your grid control.
Listing 7: Enabling the Client Side Events of the Grid Control
DisplayLayout is a nested Type of the type
UltraWebGrid. You should take some time and look at dwhat it can do. You'll find an appropriate event handler for almost every event you can think of in connection with a grid control. In my opinion client side event handling is a real strength of the controls provided by Infragistics.
Here are the scripts that are needed to support client side adding and deleting of grid rows. The following script must be added to the page in which the user control is embedded.
Note: By adding this code to the webpage which contains the grid user control, you get a collection named
aGridId which contains the client ids of all grid controls that are included in the page. The variable
bGridButtonDeleteClicked is used to determine whether the user clicked the delete button in the grid row or the delete key on the keyboard.
Pressing the delete key on the keyboard would - normally - instantly remove the row from the grid. We do not want this behavior and will therefore deactivate this behavior later.
Listing 9: The following code must be added to the user control - Function 1: AddNewRow
The script tag is closed in the last of the 3 functions that need to be added.
Note: Please note that in my application the column containing the primary key of a record / row is named
ID. Whenever a grid is submitted to the server it gets validated and processed by classes on the server. The ID value of new rows added to the client is always
null. When the new rows get submitted to the server the ID value is temporarily set to
-1. Therefore new rows that failed validation can be identified by the client based on their ID value. Rows that are processed by the server and pass validation show the primary key of the record in the ID column.
The function receives the name of the main button for adding new rows to
band. The name of the button includes the server id of the grid. If the server side id of the Grid is
GRID_GRIDMAIN the name of the button is
ButtonAddGRIDxGRIDMAIN. This is what you accomplished by adding the following event handler to the button.
foreach loop we are looking for a client id that contains the string
GRIDxGRIDMAIN and use that id to refer to the grid object on the client.
Then we add a new row to
band and deactivate auto post back right after the row was added. This will prevent the page from being submitted to the server after adding a new row, which would be the default behavior of the UltraWebGrid.
Listing 11: The following code must be added to the user control - Function 2: BeforeRowDeleted
Remember: we allowed explicitly deleting rows by setting the following property of the grid:
By allowing deletions a user is able to simply press the delete button on the keyboard to discard a row from the grid. Although those deletions affect the client side only, this is considered unwanted behavior.
The event handler
BeforeRowDeleted is hit before a row is deleted from the grid. If the code within that function returns the value
true, the deletion is cancelled and nothing happens.
We just check if the deletion was caused by an authorized button. If not, the deletion is cancelled.
Listing 13: The following code must be added to the user control - Function 3: ClickCellButton
This function determines whether the row already exists or not. If the row has not been saved yet, it is identified by the ID value
-1. If that is the case, all deletions will not be submitted to the server. The row will be deleted from the grid on the client side only. If a button is clicked that would normally redirect to a details page, this is also suppressed for rows that have not yet been saved.
It is also impossible to add child rows to parent rows that have not yet been saved. We then enter a switch block detecting which grid cell button was clicked.
Case 1 ButtonAdd
We do not allow adding child rows to parent rows that have not yet been saved. We then get the band of the row which fired the event and set the target band of the child row by incrementing the band of the parent row. Then we activate the parent row. This is important to do, otherwise nothing will happen. Finally we add the row to the target band. And cancel any pending post back which might be fired by the grid automatically after adding a new row.
Case 2 ButtonDelete
Deleting a row does normally require a post back because when a row gets deleted from the grid it disappears completely. It is impossible to access that row when processing the grid on the server in batch mode because deleted rows do not have the property
DataChanged=DataChanged.Deleted assigned. They simply disappear completely.
In our application we do not use the standard server side event which is fired by the grid whenever a row gets deleted. We use the grid cell button instead of the delete key on the keyboard.
A postback is necessary whenever a row gets deleted that exists in the database. The server has to handle that. If a row gets deleted that exists on the client side only, we don't need that postback behavior and can delete that record on the client side only.
I have got a workaround for that, but this is not the place for dealing with that kind of problem.
Derive a new Page class from System.Web.UI.Page to change the persistence medium for page state
As I explained earlier, the full functionality of the UltraWebGrid requires that you enable the view state of the grid control. In order to prevent the page state - which can easily reach 100 Kilobytes and more depending on the complexity of the grid - from being submitted together with the page you must override the methods that are used to manage the page state.
I suggest that you create a new page class which is derived from
This derived class can then be used for all pages that host large editable UltraWebGrids. Actually my class is derived from a navigation page. This page contains 90% of the functionality needed to create, manage and navigate web pages. The class
PageNavigationBase itself is derived from
Listing 14: Example of a derived Page Class that Changes the Persistence Medium of Page State
This class uses a class named
PersistenceManager to load and save the view state. The
PersistenceManager class manages how and where information gets stored that needs to be persisted beyond the lifecycle of a single page. In the addendum to this article I will only explain the two methods that are used to deal with page state. The class itself is too big and can do much more. I recommend that you make yourself familiar with this topic. The MSDN Library provides a couple of helpful articles on managing page state.
If you plan to use the UltraWebGrid effectively you need to understand the server-side object model and the client-side object model. If you use the UltraWebGrid out of the box you will most certainly experience performance and load problems and you might not get the user acceptance that you expected. These problems can be overcome by adding just a few small client scripts. The techniques that helped me most are explained in this article.
The grid as such should be brushed up by creating a custom inheritance control with all functionality that is typically needed for a grid control. The custom control should be embedded in a user control which contains complementary controls and the client scripts.
You should also use view state whenever you allow grid updating. Although it is possible to code around view state and use control state instead, it does not seem to be worth the effort in my opinion.
When you use view state you must get your hands on managing page state as explained in this article. Otherwise the amount of data transmitted in view state might become a show stopper. It seems to be a good practice to create a class which acts as a wrapper for all HTTP-context related activities. This will enable you to change the media where information is physically persisted by just changing a switch in the configuration file without touching the code of your application.
The following thought is not for the ears of IT-controllers that are sitting on the bucks:
It is better to add memory to your server or even spend money on a powerful sate server than giving up on much of the functionality provided by the UltraWebGrid or even make users upset by a poor performing application.
Addendum Supplementary Code Samples
The code in this addendum is not intended to serve as a copy and paste solution for your application. I am adding this code just to show you a simple context in which page state persistence management can be used.
My recommendation at this point is that you implement the persistence management in way that supports all 4 modes covered by this code sample. You will then be able to respond quickly to performance issues or system changes.
In my applications I even go a step further than that. All attempts to read or write to or from the cache or the session state are routed through methods of the persistence manager class, so I can even route session related object to the cache by just setting a switch in the configuration file.
The method in the next listing is a member of the type
PersistenceManager. It is used for persisting the page state either in the file system, the session state, a state database on a SQL server or the cache. The persistence medium is configured in the web.config. The formatting looks a bit ugly due to the limited space available in the code box. You should copy the code into an editor for better readability.
Mode FileSystem: The page state is stored in the path defined in web.config. It can either be a path relative to the application root path or a physical path. The nested type
PersistenceManager.Parameters has properties that provide the current path based on the current settings in web.config.
Mode SessionState: The page state is stored in the session object.
Mode Database: The page state is stored in a page state database on a SQL server. It is a simple database that has only one table and stored procedures for inserting, selecting and removing page state records.
Mode Cache: The page state is stored in the cache using the current parameters held by the type
Listing 15: The method used to persist the page state in the media configured in web.config. This method is a member of type PersistenceManager
The following method is also a member of the type PersistenceManager. It reads the page state from the medium configured in web.config supporting the modes as described before.
Listing 16: The method used to load the page state from the media configured in web.config. This method is a member of type Persistence Manager.
The following class is a nested type of the type PersistenceManager. This type holds the current application settings for the persisting of the page state. The global object of the application (Global_asax) owns a static variable that holds the reference to the current instance of this type. Assuming that the name of the instance is
PersistenceMediumParameters the parameters can be retrieved everywhere in the application by using the reference
Listing 17: The type used to manage the parameters of the currently selected mode for persisting page state
Listing 18: The enumeration used to define the persistence medium
This method is a member of the type PersistenceManager
. It simply stores an object in the cache using the typical parameters.
Listing 19: The method used to persist the pagestate in the cache if defined in web.config. This method is a member of type PersistenceManager.
Listing 20: The enumeration used to define the cache operation
Sorry, no bio is available
View complete profile here.
Please login to rate or to leave a comment.