Showing posts with label Telerik. Show all posts
Showing posts with label Telerik. Show all posts

Friday, 12 December 2008

Telerik Releases "Open Access", a Database Agnostic ORM Product that Works with LINQ

My favourite 3rd party WebUI control provider Telrik just released its new ORM product called "Open Access" - http://www.telerik.com/products/orm.aspx. I didn't realise they were developing such a thing - but it turns out they just acquired German company Vanatec that specializes in ORM products. They have performed a few updates to the original Vanatec software since they acquired it (such as removing a dependency on J#) - so they have grabbed this product and are running with it full steam. If the quality of their controls is anything to go by, this could be a valuable asset in any .NET developer's toolbelt.

I'm going to try it out and evaluate it against some of the custom LINQ, LINQ to SQL and Nhibernate-based efforts that I've created and worked with on previous projects. It also supports non-SQL Server databases such as Oracle. Now there is also a fledgling Codeplex project called LINQ to Oracle http://www.codeplex.com/LinqToOracle) but this ORM product could shoot it out of the water. Telerik Open Access also supports direct SQL. I'll do a a review before the end of the year.

Wednesday, 5 March 2008

A simple reminder to all: MS AJAX update panel and DataSources interaction - FormView.Update not passing values to DataSource

My Brazillian colleague Andre Gallo was having issues today with one of our datasources not being updated from an ASP.NET formview (a modified Object Container DataSource, part of the Web Client Software Factory package). While the formview had all the values (clearly visible via FormView.FindControl("myControlName"), a call to FormView.Updateitem() was not setting the value on the Object Container Data Source (aka OCDS). I had a look and the problem was that the datasource was OUTSIDE the AJAX panel - and so was not being passed through to the server by the partial postback.

There were 2 possible resolutions to that one:
  1. To put the object container datasource into the same panel
  2. To use the Telerik controls RadAjaxManager which allows you to point to specific trigger and destination controls for the partial postback.

We resolved the issue with option 2.

Wednesday, 19 December 2007

Telerik RadGrid V5.0 Sorting Bug with Nullable DateTime Types - "Property [ColumnName] does not support IComparable"

It turns out the Telerik RadGrid does not support sorting for nullable types (e.g. DateTime?) out of the box. For example, if you use a LINQ datasource for your grid based on a column that is nullable in SQL Server, you will get an error when trying to sort the column "Property [BoundColumnName] does not implement IComparable".

The simplest fix for this is to just make your column non-nullable if this is possible in your business situation.

Friday, 14 December 2007

Telerik RadGrid - Creating A Grouped Grid that allows sorting and editing

Today, I wanted to get the Telerik RadGrid (http://www.telerik.com/products/aspnet/controls/grid/overview.aspx) 5.0 edit functionality working in conjunction with its grouping functionality.

Background: I have been temporarily seconded from the Lend Lease Property Pipeline project onto a high-profile BI project that has several dashboards for KPIs used by management (hosted within MOSS 2007 - parameters are passed into my page via Request.Params). I have a few management-style pages that need to be created - but they have to be editable so this excludes Reporting Services from the equation.

One of the requirements of this particular page was to have automatic grouping of risks and opportunities into different sections of the grid. However, when I set up the grid my code triggered the edit event, I get the following error:

[InvalidConstraintException: Cannot have 0 columns.]

Google only returned 2 results on this error - and they didn't give me a direct solution. After looking through the Telerik site, I found a few clues which pointed to the fact I had to have both the "Select Fields" and "GroupByFields" Set in the grid. Here is my current (unfinished) version of the page) which show that magic combination of code hacks and declarative settings to get the grid to work in all its Databound AJAX-enabled editable groupable glory!


Code:





<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="RiskOpportunity.aspx.cs"
Inherits="ddkonline.MRP.Client.RiskOpportunity" %>


<%@ Register Assembly="Microsoft.Practices.Web.UI.WebControls" Namespace="Microsoft.Practices.Web.UI.WebControls"
TagPrefix="pp" %>

<%@ Register Assembly="RadGrid.Net2" Namespace="Telerik.WebControls" TagPrefix="radG" %>
<%@ Register Assembly="RadCalendar.Net2" Namespace="Telerik.WebControls" TagPrefix="radCln" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Risks and Opportunities</title>
</head>
<body>
<form id="form1" runat="server">
<pp:ObjectContainerDataSource ID="OdsRiskOpportunityDataSource" runat="server" DataObjectTypeName="ddkonline.MRP.Service.Persistence.Entity.ODS_Risk_Opportunity"
OnInserted="OdsRiskOpportunityDataSource_Inserted" OnUpdated="OdsRiskOpportunityDataSource_Updated"
OnSelecting="OdsRiskOpportunityDataSource_Selecting" />
<asp:LinqDataSource ID="BusinessUnitDataSource" runat="server" ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="Sort_Order" TableName="Dim_Business_Hierarchy_PCs" Where="ETL_Region == @ETL_Region &amp;&amp; Member_Level == @Member_Level"
OnSelecting="BusinessUnitDataSource_Selecting">
<WhereParameters>
<asp:Parameter Name="ETL_Region" Type="String" />
<asp:Parameter DefaultValue="&quot;3&quot;" Name="Member_Level" Type="Int32" />
</WhereParameters>
</asp:LinqDataSource>
<asp:LinqDataSource ID="ReportingCurrencyDataSource" runat="server" ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="Currency_Name" Select="new (Currency_Name, Currency_Code, Reporting_Currency_SKEY)"
TableName="Dim_Reporting_Currencies">
</asp:LinqDataSource>
<asp:LinqDataSource ID="RiskConsequenceDataSource" runat="server" ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="Sort_Order" Select="new (Lookup_SKEY, Lookup_Value)" TableName="Dim_Lookups"
Where="Type == @Type">
<WhereParameters>
<asp:Parameter DefaultValue="RiskConsequence" Name="Type" Type="String" />
</WhereParameters>
</asp:LinqDataSource>
<asp:LinqDataSource ID="StatusDataSource" runat="server" ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="Sort_Order" Select="new (Lookup_SKEY, Lookup_Value)" TableName="Dim_Lookups"
Where="Type == @Type">
<WhereParameters>
<asp:Parameter DefaultValue="Status" Name="Type" Type="String" />
</WhereParameters>
</asp:LinqDataSource>
<%--<asp:LinqDataSource ID="peopleDataSource" runat="server"
ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="ETL_Extract_User" Select="new (People_SKEY, ETL_Extract_User)"
TableName="Dim_People">
</asp:LinqDataSource>--%>
<div>
<radG:RadGrid ID="BusinessRiskGrid" ShowGroupPanel="False" runat="server" AutoGenerateColumns="False"
DataSourceID="OdsRiskOpportunityDataSource" GridLines="None" OnItemCommand="BusinessRiskGrid_ItemCommand"
Skin="Windows" AllowSorting="True" OnItemDataBound="BusinessRiskGrid_ItemDataBound"
GroupingEnabled="true" EnableAJAX="true" EnableAJAXLoadingTemplate="true" LoadingTemplateTransparency="25">
<ExportSettings>
<Pdf PageWidth="8.5in" PageHeight="11in" PageTopMargin="" PageBottomMargin="" PageLeftMargin=""
PageRightMargin="" PageHeaderMargin="" PageFooterMargin=""></Pdf>
</ExportSettings>
<MasterTableView AllowAutomaticInserts="True" AllowAutomaticUpdates="True" CommandItemDisplay="Bottom"
DataSourceID="OdsRiskOpportunityDataSource" EditMode="InPlace" DataKeyNames="Id">
<GroupByExpressions>
<radG:GridGroupByExpression>
<SelectFields>
<radG:GridGroupByField FieldAlias="IsRisk" FieldName="IsRisk"></radG:GridGroupByField>
</SelectFields>
<GroupByFields>
<radG:GridGroupByField FieldName="IsRisk"></radG:GridGroupByField>
</GroupByFields>
</radG:GridGroupByExpression>
</GroupByExpressions>
<CommandItemTemplate>
<table width="100%">
<tr>
<td width="50%">
<asp:LinkButton ID="AddNewLink" runat="server" CommandName="InitInsert">
<img style="border:0px" alt="" src="Image/Insert.gif" /> Add new Record</asp:LinkButton>
</td>
<td width="50%" align="right">
<asp:HyperLink ID="PrintLink" runat="server" NavigateUrl="http://172.24.27.157/ReportserverDEV?%2fBLL+MRP%2fBusiness+Plan+Status&amp;period=20071101&amp;hierarchy=838&amp;businessArea=6">
<img style="border:0px" alt="" src="Image/Insert.gif"/> Print
</asp:HyperLink>
</td>
</tr>
</table>
</CommandItemTemplate>
<Columns>
<%--Issue Detail --%>
<radG:GridTemplateColumn DataField="IssueDetail" HeaderText="Issue Details" SortExpression="IssueDetail"
UniqueName="IssueDetail" ItemStyle-Width="5pc">
<EditItemTemplate>
<asp:TextBox ID="IssueDetailTextBox" runat="server" Text='<%# Bind("IssueDetail")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="IssueDetailRequiredFieldValidator" ControlToValidate="IssueDetailTextBox"
Display="Dynamic" ErrorMessage="* This field is required" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="IssueDetailLabel" runat="server"><%# Eval("IssueDetail")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--Business Unit--%>
<%--
<radG:GridDropDownColumn DataField="BusinessUnitId" DataSourceID="BusinessUnitDataSource"
HeaderText="Business Unit" ListTextField="Lookup_Value" ListValueField="BusinessUnitId"
UniqueName="BusinessUnitId">
</radG:GridDropDownColumn>
--%>
<%--Reporting Currency --%>
<radG:GridDropDownColumn DataField="Reporting_Currency_SKEY" DataSourceID="ReportingCurrencyDataSource"
ItemStyle-Width="5pc" HeaderText="Reporting Currency" ListTextField="Currency_Name"
ListValueField="Reporting_Currency_SKEY" UniqueName="Reporting_Currency_SKEY"
Groupable="True" GroupByExpression="Reporting_Currency_SKEY Group By Reporting_Currency_SKEY">
</radG:GridDropDownColumn>
<%--PBT--%>
<radG:GridTemplateColumn DataField="PBT" HeaderText="PBT" UniqueName="PBT" SortExpression="PBT"
ItemStyle-Width="1pc">
<EditItemTemplate>
<asp:TextBox ID="PBTTextBox" runat="server" Text='<%# Bind("PBT", "{0:N1}")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="PBTRequiredFieldValidator" ControlToValidate="PBTTextBox"
ErrorMessage="* This field is required" runat="server" Display="Dynamic" />
<asp:RegularExpressionValidator ID="PBTRegularExpressionValidator" ControlToValidate="PBTTextBox"
ValidationExpression="-{0,1}\d*\.{0,1}\d{0,1}" ErrorMessage="* You must enter a valid value (1 decimal place)"
runat="server" Display="Dynamic" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="PBTLabel" runat="server"><%# Eval("PBT", "{0:N1}")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--PAT--%>
<radG:GridTemplateColumn DataField="PAT" HeaderText="PAT" UniqueName="PAT" SortExpression="PAT"
ItemStyle-Width="1pc">
<EditItemTemplate>
<asp:TextBox ID="PATTextBox" runat="server" Text='<%# Bind("PAT", "{0:N1}")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="PATRequiredFieldValidator" ControlToValidate="PATTextBox"
ErrorMessage="* This field is required" runat="server" Display="Dynamic" />
<asp:RegularExpressionValidator ID="PATRegularExpressionValidator" ControlToValidate="PATTextBox"
ValidationExpression="-{0,1}\d*\.{0,1}\d{0,1}" ErrorMessage="* You must enter a valid value (1 decimal place)"
runat="server" Display="Dynamic" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="PATLabel" runat="server"><%# Eval("PAT","{0:N1}")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--Probability--%>
<radG:GridTemplateColumn DataField="Probability" HeaderText="% Probability" UniqueName="Probability"
SortExpression="Probability" ItemStyle-Width="5pc">
<EditItemTemplate>
<asp:TextBox ID="ProbabilityTextBox" runat="server" Text='<%# Bind("Probability")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="ProbabilityRequiredFieldValidator" ControlToValidate="ProbabilityTextBox"
ErrorMessage="* This field is required" runat="server" Display="Dynamic" />
<asp:RegularExpressionValidator ID="ProbabilityRegularExpressionValidator" ControlToValidate="ProbabilityTextBox"
ValidationExpression="-{0,1}\d*\.{0,1}\d{0,1}" ErrorMessage="* You must enter a numeric value" runat="server"
Display="Dynamic" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="ProbabilityLabel" runat="server"><%# Eval("Probability", "{0}%")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--Commentary--%>
<radG:GridTemplateColumn DataField="Commentary" HeaderText="Commentary" SortExpression="Commentary"
UniqueName="Commentary" ItemStyle-Width="5pc">
<EditItemTemplate>
<asp:TextBox ID="CommentaryTextBox" runat="server" Text='<%# Bind("Commentary")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="CommentaryRequiredFieldValidator" ControlToValidate="CommentaryTextBox"
Display="Dynamic" ErrorMessage="* This field is required" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="CommentaryLabel" runat="server"><%# Eval("Commentary")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--Person Responsible --%>
<radG:GridTemplateColumn DataField="Person_Responsible_Id" UniqueName="PersonResponsible"
HeaderText="Person Responsible" SortExpression="Person_Responsible_Id">
<EditItemTemplate>
<asp:DropDownList ID="PersonResponsible" runat="server" SelectedValue='<%# Bind("Person_Responsible_Id") %>'>
<asp:ListItem Value="0" Text="" />
<asp:ListItem Value="1" Text="David Klein" />
<asp:ListItem Value="2" Text="Andrew Muller" />
<asp:ListItem Value="3" Text="Damien Herslet" />
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="dtLabel1" runat="server" Text='<%# Eval("PersonName") %>' />
</ItemTemplate>
</radG:GridTemplateColumn>
<radG:GridTemplateColumn DataField="ResolutionDate" DataType="System.DateTime" HeaderText="Resolution Date"
SortExpression="ResolutionDate" UniqueName="ResolutionDate" ForceExtractValue="Always">
<EditItemTemplate>
<radCln:RadDatePicker ID="ResolutionDateDatePicker" runat="server" DbSelectedDate='<%# Bind("ResolutionDate") %>'>
</radCln:RadDatePicker>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="ResolutionDateLabel" runat="server"><%# Eval("ResolutionDate", "{0:d}")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<radG:GridTemplateColumn DataField="Status_Lookup_SKEY" UniqueName="Status" HeaderText="Status"
SortExpression="Status_Lookup_SKEY">
<EditItemTemplate>
<asp:DropDownList ID="Status" runat="server" DataSourceID="StatusDataSource" DataTextField="Lookup_Value"
DataValueField="Lookup_SKEY" SelectedValue='<%# Bind("Status_Lookup_SKEY") %>'>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Image ID="Image1" runat="server" ImageAlign="Middle" ImageUrl='<%# Eval("StatusImageURL") %>' />
</ItemTemplate>
</radG:GridTemplateColumn>
<radG:GridTemplateColumn DataField="Period_Date_SKEY" HeaderText="Period_Date_SKEY"
UniqueName="Period_Date_SKEY" Visible="false">
<EditItemTemplate>
<asp:Label ID="PeriodDateLabel" runat="server" Text='<%# Bind("Period_Date_SKEY")%>' />
</EditItemTemplate>
</radG:GridTemplateColumn>
<radG:GridTemplateColumn DataField="IsRisk" HeaderText="IsRisk" UniqueName="IsRisk"
Groupable="True" GroupByExpression="IsRisk Group By IsRisk" Visible="False">
<ItemTemplate>
<asp:Label ID="IsRiskLabel" runat="server" Text='<%# Eval("IsRisk")%>' />
</ItemTemplate>
<EditItemTemplate>
<asp:Label ID="IsRiskLabel" runat="server" Text='<%# Eval("IsRisk")%>' />
</EditItemTemplate>
</radG:GridTemplateColumn>
<radG:GridEditCommandColumn UniqueName="Edit" ButtonType="ImageButton">
</radG:GridEditCommandColumn>
</Columns>
</MasterTableView>
<ClientSettings AllowDragToGroup="True">
<Resizing AllowColumnResize="True" EnableRealTimeResize="True" />
</ClientSettings>
</radG:RadGrid>
</div>
</form>
</body>
</html>




using System;
using System.Collections.Specialized;
using ddkonline.MRP.Service;
using ddkonline.MRP.Service.Persistence.Entity;
using Microsoft.Practices.Web.UI.WebControls;
using Telerik.WebControls;
using ddkonline.MRP.Global;

namespace ddkonline.MRP.Client
{
/// <summary>
/// Risk Management page
/// </summary>
public partial class RiskOpportunity : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
}

/// <summary>
/// Defaults the newly inserted items
/// </summary>
/// <param name="sender">Default event sender</param>
/// <param name="e">Grid command event arguments</param>
protected void BusinessRiskGrid_ItemCommand(object sender, GridCommandEventArgs e)
{
//// Default values for the items to insert in grid
//// http://www.telerik.com/community/forums/thread/b311D-emgdc.aspx
if (e.CommandName == RadGrid.InitInsertCommandName)
{
e.Canceled = true;
ListDictionary newValues = new ListDictionary();
newValues["IssueDetail"] = string.Empty;
newValues["Commentary"] = string.Empty;
newValues["BusinessUnitId"] = 871;
newValues["Reporting_Currency_SKEY"] = 0;
newValues["PBT"] = 0;
newValues["PAT"] = 0;
newValues["Probability"] = 0;
newValues["CreatedOn"] = DateTime.Now;
newValues["ModifiedOn"] = DateTime.Now;
newValues["ResolutionDate"] = null;
newValues["Person_Responsible_Id"] = 0;
newValues["Period_Date_SKEY"] = Controller.Current_Period;
newValues["Status_Lookup_SKEY"] = Constant.ON_TRACK;
e.Item.OwnerTableView.InsertItem(newValues);
}
}
/// <summary>
/// Handles the insert of an Item and Saves via partial method in the LINQ Entity (via a Service wrapper class)
/// </summary>
/// <param name="sender">Default event sender</param>
/// <param name="e">Object container event arguments</param>
protected void OdsRiskOpportunityDataSource_Inserted(
object sender, ObjectContainerDataSourceStatusEventArgs e)
{
ODS_Risk_Opportunity RiskOpportunity = (ODS_Risk_Opportunity)e.Instance;

// Set audit attributes
RiskOpportunity.CreatedOn = DateTime.Now;
RiskOpportunity.CreatedBy = Context.User.Identity.Name;
RiskOpportunity.ModifiedOn = DateTime.Now;
RiskOpportunity.ModifiedBy = Context.User.Identity.Name;
RiskOpportunity.Original_Risk_Opportunity_Id = 0;
//RiskOpportunity.Business_Area_Lookup_SKEY = GetBusinessAreaId(Controller.Current_BusinessArea);
RiskOpportunity.Business_Hierarchy_PC_SKEY = Controller.Current_BusinessHierarchy;
RiskOpportunityService.Save(RiskOpportunity);
}

/// <summary>
/// Handles the update of an Item
/// </summary>
/// <param name="sender">Default event sender</param>
/// <param name="e">Object container event arguments</param>
protected void OdsRiskOpportunityDataSource_Updated(
object sender, ObjectContainerDataSourceStatusEventArgs e)
{
ODS_Risk_Opportunity RiskOpportunity = (ODS_Risk_Opportunity)e.Instance;
// Set audit attributes
RiskOpportunity.ModifiedOn = DateTime.Now;
RiskOpportunity.ModifiedBy = Context.User.Identity.Name;
//RiskOpportunity.Business_Area_Lookup_SKEY = GetBusinessAreaId(Controller.Current_BusinessArea);
RiskOpportunity.Business_Hierarchy_PC_SKEY = Controller.Current_BusinessHierarchy;
RiskOpportunityService.Save(RiskOpportunity); ;
}

protected void OdsRiskOpportunityDataSource_Selecting(object sender, ObjectContainerDataSourceSelectingEventArgs e)
{
OdsRiskOpportunityDataSource.DataSource = RiskOpportunityService.GetAllFiltered(Controller.Current_BusinessHierarchy, Controller.Current_BusinessArea, Controller.Current_Period);
}

protected void BusinessUnitDataSource_Selecting(object sender, System.Web.UI.WebControls.LinqDataSourceSelectEventArgs e)
{
e.WhereParameters["ETL_Region"] = Controller.Current_BusinessHierarchy;
//e.SelectParameters. ["ETL_Region"]
//BusinessUnitDataSource.SelectParameters. = Controller.Current_BusinessHierarchy;
}

protected void BusinessRiskGrid_ItemDataBound(object sender, GridItemEventArgs e)
{
//Render Correct Header (RISK/OPPORTUNITY) on ItemDataBound of Telerik Grid.
if (e.Item is GridGroupHeaderItem)
{
GridGroupHeaderItem item = (GridGroupHeaderItem)e.Item;
System.Data.DataRowView groupDataRow = (System.Data.DataRowView)e.Item.DataItem;
item.DataCell.Text = Boolean.Parse(groupDataRow["IsRisk"].ToString()) ? "RISKS (enter -ve)" : "OPPORTUNITIES (enter +ve)";

//Calculations
//item.DataCell.Text += ((System.Decimal)groupDataRow["total"] / (int.Parse(groupDataRow["count"].ToString()))).ToString();
}
}
}
}

Thursday, 13 December 2007

Problems Using Telerik Controls for inserts

I had an issue today using the Telerik RadGrid control (Version 5.0) to do inserts (edits work fine). If you don't initialize the fields in your control properly, you will get the following error:

DataBinding: 'Telerik.WebControls.GridInsertionObject' does not contain a property with the name 'Person_Responsible_Id'.

I don't think this is an ideal situation - the control should be smart enough to initialize its own fields - but the way around this is described here on the Telerik site:

http://www.telerik.com/help/aspnet/grid/?grdInsertingValuesUserControlFormTemplate.html



   1:  protected void RadGrid1_InsertCommand(object source, GridCommandEventArgs e)

   2:  {

   3:             GridEditableItem editedItem = e.Item as GridEditableItem;

   4:             UserControl userControl = (UserControl)e.Item.FindControl(GridEditFormItem.EditFormUserControlID);

   5:   

   6:             //Create new row in the DataSource

   7:             DataRow newRow = this.Employees.NewRow();

   8:   

   9:             //Insert new values

  10:             Hashtable newValues = new Hashtable();

  11:   

  12:             newValues["Country"] = (userControl.FindControl("TextBox7") as TextBox).Text;

  13:             newValues["City"] = (userControl.FindControl("TextBox8") as TextBox).Text;

  14:             newValues["Region"] = (userControl.FindControl("TextBox9") as TextBox).Text;

  15:             newValues["HomePhone"] = (userControl.FindControl("TextBox10") as TextBox).Text;

  16:             newValues["BirthDate"] = (userControl.FindControl("TextBox11") as TextBox).Text;

  17:             newValues["TitleOfCourtesy"] = (userControl.FindControl("ddlTOC") as DropDownList).SelectedItem.Value;

  18:   

  19:             newValues["Notes"] = (userControl.FindControl("TextBox1") as TextBox).Text;

  20:             newValues["Address"] = (userControl.FindControl("TextBox6") as TextBox).Text;

  21:             newValues["FirstName"] = (userControl.FindControl("TextBox2") as TextBox).Text;

  22:             newValues["LastName"] = (userControl.FindControl("TextBox3") as TextBox).Text;

  23:             newValues["HireDate"] = (userControl.FindControl("Textbox5") as TextBox).Text;

  24:             newValues["Title"] = (userControl.FindControl("TextBox4") as TextBox).Text;

  25:   

  26:             //make sure that unique primary key value is generated for the inserted row

  27:             newValues["EmployeeID"] = (int)this.Employees.Rows[this.Employees.Rows.Count - 1]["EmployeeID"] + 1;

  28:             try

  29:             {

  30:                 foreach (DictionaryEntry entry in newValues)

  31:                 {

  32:                     newRow[(string)entry.Key] = entry.Value;

  33:                 }

  34:                 this.Employees.Rows.Add(newRow);

  35:                 this.Employees.AcceptChanges();

  36:             }

  37:             catch (Exception ex)

  38:             {

  39:                 RadGrid1.Controls.Add(new LiteralControl("Unable to update/insert Employees. Reason: " + ex.Message));

  40:                 e.Canceled = true;

  41:             }

  42:  }