Friday, November 27, 2015

C# - DataTable to Entity List

When accessing data in C#, the generally accepted way is to use List & Generics. There are many advantages of those such as performance and rich with features such as LINQ to Entities. What if we need a DataTable to be converted into a Entity List? There are easiest ways as discussed here but the following methods will be able to use for easier conversion of DataTables in to relevant Entity List.

 public static T? GetValue<T>(this DataRow row, string columnName) where T : struct  
     {  
       if (!row.Table.Columns.Contains(columnName))  
         return null;  
       if (row.IsNull(columnName))  
         return null;  
       return row[columnName] as T?;  
     }  //HANDLE NULLABLE VALUES TOO
public static string GetText(this DataRow row, string columnName)  
     {  
       if (!row.Table.Columns.Contains(columnName))  
         return string.Empty;  
       if (row.IsNull(columnName))  
         return string.Empty;  
       return row[columnName] as string ?? string.Empty;  
     }  //FOR STRINGS

These two methods will convert the values in the data table to lists in a way as it used below;
 foreach (var item in dataTable.Select())  
       {  
         entityList.Add(new myEntity()  
         {  
             id = ExtensionMethods.GetValue<int>(item, "idColumnName").Value,  
             dateTime = ExtensionMethods.GetValue<DateTime>(item, "dateTimeColumnName").Value,  
             dateTimeNullable = ExtensionMethods.GetValue<DateTime>(item, "dateTimeNullableColumnName"),  
             string = ExtensionMethods.GetText(item, "stringColumnName"),            
             number = ExtensionMethods.GetValue<int>(item, "numberColumnName").Value,  
             numberNullable = ExtensionMethods.GetValue<int>(item, "numberNullableColumnName")  
         });  
       }  

The list can be passed as a return value of the method if needed.
Note that this is only to convert DataTable to a list and if you write a data access method, always try to use DataReader instead of DataTables.

Copy these codes and modify, reuse as needed. :)



Wednesday, November 25, 2015

tablesorter - A sort-able HTML table with JQuery plugin for ASP.Net GridView Control

When displaying information, such as a table in HTML, it is always better if an additional features can be provided in a way that the users can filter on client side without posting back. The benefits is that its faster as it processes on client side and it has rich contents which is able to filter as well as sort columns.
The following example will show how it can be applied to ASP.Net GridView Control.

1. Create your own GridView with the following properties.
 ClientIDMode="Static" OnDataBound="grdMyGrid_DataBound"   
This declaration must be needed to keep the id of the grid to be constant after rendered especially if there are any master pages.
The grdMyGrid_DataBound is important to set the header properties for the grid (table after rendered).

2. In code behind, add the following,
 protected void grdMyGrid_DataBound(object sender, EventArgs e)  
   {  
     if (grdMyGrid.Rows.Count > 0)  
     {  
       grdMyGrid.UseAccessibleHeader = true;  
       grdMyGrid.HeaderRow.TableSection = TableRowSection.TableHeader;  
     }  
   }  

3. Now you need to refer the tablesorter js and css files to the page.
 <link rel="stylesheet" href="style/TableSorter/theme.blue.css" type="text/css" />  
 <script src="script/TableSort/jquery.tablesorter.min.js" type="text/javascript"></script>  
 <script src=">script/TableSort/jquery.tablesorter.widgets.js" type="text/javascript"></script>  
* Also make sure the to add references to JQuery too.

4. Now the table sorter can applied as per below from the relevant page related JS file.
 $(document).ready(function () {  
 var $table = $('#grdMyGrid').tablesorter({  
       theme: 'blue', //The theme to be applied  
       widgets: ["zebra", "filter"],  
       widgetOptions: {  
         filter_hideFilters: false,          
         filter_external: '.search',  
         filter_placeholder: { search: 'Search...' }, //The Search field mask text  
         filter_saveFilters: false,  
         filter_reset: '.reset'  
       },  
       headers: {  
         5: { sorter: false, filter: false }, //Disable sorting and filtering  
         6: { sorter: false, filter: false } //Disable sorting and filtering  
       }  
     });  
 });  

5. The final result looks like below;


Read the documentation here:
http://tablesorter.com/docs/

Happy coding :)

C# Data Access Layer - Easy way

When it comes to data access in C#, generalizing common methods to a class is what we always do. A bit of OOP with C# can ease so much work.
So here is a sample of a Data Access Layer that we can use in the data access components in the project.

 public abstract class DataAccessBase  
   {  
     #region Exec SQL  
     protected void ExecuteNonQuery(string storedProcedure, params SqlParam[] parameters)  
     {  
       try  
       {  
         using (SqlConnection cnx = GetConnection())  
         {  
           using (SqlCommand cmd = new SqlCommand(storedProcedure, cnx) { CommandType = CommandType.StoredProcedure })  
           {  
             FillParameters(cmd, parameters);  
             cnx.Open();  
             cmd.ExecuteNonQuery();  
           }  
         }  
       }  
       catch (SqlException ex)  
       {  
         throw new TechnicalException(ex.Message, ex);  
       }  
     }  
     protected object ExecuteScalar(string storedProcedure, params SqlParam[] parameters)  
     {  
       try  
       {  
         object toReturn = null;  
         using (SqlConnection cnx = GetConnection())  
         {  
           using (SqlCommand cmd = new SqlCommand(storedProcedure, cnx) { CommandType = CommandType.StoredProcedure })  
           {  
             FillParameters(cmd, parameters);  
             cnx.Open();  
             toReturn = cmd.ExecuteScalar();  
           }  
         }  
         return toReturn;  
       }  
       catch (SqlException ex)  
       {  
         throw new TechnicalException(ex.Message, ex);  
       }  
     }  
     protected DataSet ExecuteDataSet(string storedProcedure, params SqlParam[] parameters)  
     {  
       try  
       {  
         DataSet ds = new DataSet();  
         using (SqlConnection cnx = GetConnection())  
         {  
           using (SqlCommand cmd = new SqlCommand(storedProcedure, cnx) { CommandType = CommandType.StoredProcedure })  
           {  
             FillParameters(cmd, parameters);  
             cnx.Open();  
             SqlDataAdapter sda = new SqlDataAdapter(cmd);  
             sda.Fill(ds);  
           }  
         }  
         return ds;  
       }  
       catch (SqlException ex)  
       {  
         throw new TechnicalException(ex.Message, ex);  
       }  
     }  
     protected SqlDataReader ExecuteDataReader(string storedProcedure, params SqlParam[] parameters)  
     {  
       SqlConnection cnx = GetConnection();  
       try  
       {  
         SqlDataReader rtnReader;  
         using (SqlCommand cmd = new SqlCommand(storedProcedure, cnx) { CommandType = CommandType.StoredProcedure })  
         {  
           FillParameters(cmd, parameters);  
           cnx.Open();  
           rtnReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);  
         }  
         return rtnReader;  
       }  
       catch (SqlException ex)  
       {  
         throw new TechnicalException(ex.Message, ex);  
       }  
     }  
     protected DataTable ExecuteDataTable(string storedProcedure, params SqlParam[] parameters)  
     {  
       try  
       {  
         DataTable dt = new DataTable();  
         using (SqlConnection cnx = GetConnection())  
         {  
           using (SqlCommand cmd = new SqlCommand(storedProcedure, cnx) { CommandType = CommandType.StoredProcedure })  
           {  
             FillParameters(cmd, parameters);  
             cnx.Open();  
             SqlDataAdapter sda = new SqlDataAdapter(cmd);  
             sda.Fill(dt);  
           }  
         }  
         return dt;  
       }  
       catch (SqlException ex)  
       {  
         throw new TechnicalException(ex.Message, ex);  
       }  
     }  
     protected object GetValue(DataRow row, string fieldName)  
     {  
       if (row[fieldName] != DBNull.Value)  
       {  
         return row[fieldName];  
       }  
       return null;  
     }  
     protected string GetValueToString(DataRow row, string fieldName)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         string s = (o as string);  
         if (!string.IsNullOrEmpty(s))  
         {  
           s = s.Trim();  
         }  
         return s;  
       }  
       return string.Empty;  
     }  
     protected int GetValueToInt(DataRow row, string fieldName, int defaultValue)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         return o as int? ?? defaultValue;  
       }  
       return defaultValue;  
     }  
     protected int? GetValueToIntNull(DataRow row, string fieldName, int? defaultValue = null)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         return o as int? ?? defaultValue;  
       }  
       return defaultValue;  
     }  
     protected decimal GetValueToDecimal(DataRow row, string fieldName, decimal defaultValue)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         return o as decimal? ?? defaultValue;  
       }  
       return defaultValue;  
     }  
     protected decimal? GetValueToDecimalNull(DataRow row, string fieldName, decimal? defaultValue = null)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         return o as decimal? ?? defaultValue;  
       }  
       return defaultValue;  
     }  
     protected bool GetValueToBool(DataRow row, string fieldName, bool defaultValue)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         return o as bool? ?? defaultValue;  
       }  
       return defaultValue;  
     }  
     protected bool? GetValueToBoolNull(DataRow row, string fieldName, bool? defaultValue = null)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         return o as bool? ?? defaultValue;  
       }  
       return defaultValue;  
     }  
     protected DateTime GetValueToDateTime(DataRow row, string fieldName, DateTime defaultValue)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         return o as DateTime? ?? defaultValue;  
       }  
       return defaultValue;  
     }  
     protected DateTime? GetValueToDateTimeNull(DataRow row, string fieldName, DateTime? defaultValue = null)  
     {  
       object o = GetValue(row, fieldName);  
       if (o != null)  
       {  
         return o as DateTime? ?? defaultValue;  
       }  
       return defaultValue;  
     }  
     protected object ToDbNullValue(string str)  
     {  
       return string.IsNullOrEmpty(str) ? (object)DBNull.Value : str;  
     }  
     protected object ToDbNullValue(int? val)  
     {  
       return val.HasValue ? val.Value : (object)DBNull.Value;  
     }  
     protected object ToDbNullValue(bool? val)  
     {  
       return val.HasValue ? val.Value : (object)DBNull.Value;  
     }  
     protected object ToDbNullValue(DateTime? val)  
     {  
       return val.HasValue ? val.Value : (object)DBNull.Value;  
     }  
     protected object ToDbNullValue(decimal? val)  
     {  
       return val.HasValue ? val.Value : (object)DBNull.Value;  
     }  
     protected object ToDbNullValue(float? val)  
     {  
       return val.HasValue ? val.Value : (object)DBNull.Value;  
     }  
     private void FillParameters(SqlCommand cmd, SqlParam[] parameters)  
     {  
       foreach (SqlParam param in parameters)  
       {  
         SqlParameter sqlParam = new SqlParameter(param.ParamName, param.ParamType.DbType);  
         if (param.ParamType.Size.HasValue)  
         {  
           sqlParam.Size = param.ParamType.Size.Value;  
         }  
         sqlParam.Direction = (ParameterDirection)((int)param.Direction);  
         if (param.Value != null)  
         {  
           sqlParam.Value = param.Value;  
         }  
         else  
         {  
           sqlParam.Value = DBNull.Value;  
         }  
         cmd.Parameters.Add(sqlParam);  
       }  
     }  
     protected void ReadSingleRow(IDataRecord record)  
     {  
       Console.WriteLine(String.Format("{0}, {1}", record[0], record[1]));  
     }  
     private SqlConnection GetConnection()  
     {  
       if (ConfigurationManager.ConnectionStrings.Count == 0)  
       {  
         throw new TechnicalException("No connection to the database is defined.");  
       }  
       return new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);  
     }  
     #endregion  
 }  

 public class SqlParam  
   {  
     public SqlParam()  
     {  
       Direction = ParameterDirection.Input;  
     }  
     public string ParamName { get; set; }  
     public SqlParamType ParamType { get; set; }  
     public object Value { get; set; }  
     public ParameterDirection Direction { get; set; }  
   }  

 public class SqlParamType  
   {  
     public SqlParamType(SqlDbType dbType)  
     {  
       this.DbType = dbType;  
     }  
     public SqlParamType(SqlDbType dbType, int size)  
     {  
       this.DbType = dbType;  
       this.Size = size;  
     }  
     public SqlDbType DbType { get; set; }  
     public int? Size { get; set; }  
   }  

 public static class DataReaderExtensions  
   {  
     public static string GetStringNullable(this IDataReader reader, int ordinal)  
     {  
       return reader.IsDBNull(ordinal) ? null : reader.GetString(ordinal);  
     }  
     public static int? GetInt32Nullable(this IDataReader reader, int ordinal)  
     {  
       return reader.IsDBNull(ordinal) ? (int?)null : reader.GetInt32(ordinal);  
     }  
     public static DateTime? GetDateTimeNullable(this IDataReader reader, int ordinal)  
     {  
       return reader.IsDBNull(ordinal) ? (DateTime?)null : reader.GetDateTime(ordinal);  
     }  
   }  


May be a namespace will provide you a better way to organize these classes and DataAccessBase which is an abstract class can be used in any of your data access classes such as below.
 public class PersonDAL : DataAccessBase  
 {  
 }  

Just post a comment if you need the sample project. :)


Tuesday, November 24, 2015

ASP.Net - Auto Close Message Box Control

There are dozen of ways for displaying messages in a web application developed in ASP.Net Web Forms. If Bootstrap is used, a generic bootstrap message template can be used. But what if we need a bit more enhanced message that could be terminated by itself after a given set of seconds.

The below way is practically easy for implementation and the control can be called, and message can be shown from code behind too.

1. First create the control ( Remember to reference JQuery in your project.)

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MessageBox.ascx.cs" Inherits="TRD.HealthCareWebsite.Controls.MessageBox" %>  
 <div id="<%= WrapperElementID %>" class="MessageBoxWrapper">  
   <asp:Panel ID="MessageBoxInterface" runat="server" CssClass="MessageBoxInterface" Visible="false" EnableViewState="false">  
     <script type="text/javascript">  
       $(document).ready(function() {  
         if(<%= AutoCloseTimeout %> > 0)  
             $('#<%= MessageBoxInterface.ClientID %>').delay(<%= AutoCloseTimeout %>).slideUp(300);  
         });  
     </script>  
     <asp:HyperLink ID="CloseButton" runat="server" Visible="false">  
       <asp:Image ID="CloseImage" Visible="false" runat="server" AlternateText="Hide Alert Message" ImageUrl="~/Images/MessageBox_close.png" />  
     </asp:HyperLink>  
     <p>  
       <asp:Literal ID="AlertMessage" runat="server"></asp:Literal>  
     </p>  
   </asp:Panel>  
 </div> 

2. The code behind
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 using System.Web.UI;  
 using System.Web.UI.WebControls;  
 namespace TRD.HealthCareWebsite.Controls  
 {  
   public partial class MessageBox : System.Web.UI.UserControl  
   {  
     public bool ShowCloseButton { get; set; }  
     private int _AutoCloseTimeout;  
     public int AutoCloseTimeout  
     {  
       get  
       {  
         if (_AutoCloseTimeout <= 0)  
           _AutoCloseTimeout = 5000;  
         return _AutoCloseTimeout;  
       }  
       set { _AutoCloseTimeout = value; }  
     }  
     public string WrapperElementID { get; set; }  
     protected void Page_Load(object sender, EventArgs e)  
     {  
       if (String.IsNullOrEmpty(WrapperElementID))  
         WrapperElementID = "MessageBoxWrapper";  
       if (ShowCloseButton)  
         CloseButton.Attributes.Add("onclick",  
                       "document.getElementById('" + MessageBoxInterface.ClientID +  
                       "').style.display = 'none'");  
     }  
     public void ShowError(string message)  
     {  
       ShowError(message, AutoCloseTimeout);  
     }  
     public void ShowError(string message, int timeout)  
     {  
       Show(MessageType.Error, message, timeout);  
     }  
     public void ShowInfo(string message)  
     {  
       ShowInfo(message, AutoCloseTimeout);  
     }  
     public void ShowInfo(string message, int timeout)  
     {  
       Show(MessageType.Info, message, timeout);  
     }  
     public void ShowSuccess(string message)  
     {  
       ShowSuccess(message, AutoCloseTimeout);  
     }  
     public void ShowSuccess(string message, int timeout)  
     {  
       Show(MessageType.Success, message, timeout);  
     }  
     public void ShowWarning(string message)  
     {  
       ShowWarning(message, AutoCloseTimeout);  
     }  
     public void ShowWarning(string message, int timeout)  
     {  
       Show(MessageType.Warning, message, timeout);  
     }  
     private void Show(MessageType messageType, string message, int timeout)  
     {  
       AutoCloseTimeout = timeout;  
       CloseImage.Visible = ShowCloseButton;  
       CloseButton.Visible = ShowCloseButton;  
       AlertMessage.Text = message;  
       MessageBoxInterface.CssClass = MessageBoxInterface.CssClass + " " + messageType.ToString().ToLower() + "Msg";  
       MessageBoxInterface.Visible = true;  
     }  
     private enum MessageType  
     {  
       Error = 1,  
       Info = 2,  
       Success = 3,  
       Warning = 4  
     }  
   }  
 }  


3. Register the control to the page
 <%@ Register Src="~/Controls/MessageBox.ascx" TagPrefix="uc1" TagName="MessageBox" %>  

 <uc1:MessageBox runat="server" ID="mbLoginError" />  

4. Call it from code behind
 catch(FunctionalException ex)  
       {  
         mbLoginError.ShowError(GetLocalResourceObject(ex.Message).ToString());  
       }  

Note that the class "FunctionalException" is a custom error handling class.

Download the control here.

Stored Procedures in MSSQL

Since we need to manage create first and then update on procedure alterations, its better to test whether the SP is already exists at first and if so, drop it and create it again.

For example we can follow the below way that will drop the SP each time its being run and create again instead of writing new update procedures.

 if exists (select * from dbo.sysobjects where id=object_id(N'[dbo].[procName]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)  
      drop procedure [dbo].[procName]  
 GO  
 /************************************************************************  
      Stored Procedure Name:     dbo.procName  
      Creation Date:               2015-10-15   
      Copyright:                    http://techndj.blogspot.com/  
      Written by:                    http://techndj.blogspot.com/  
      Purpose:                    Why you write it  
      Input Parameters:          @paraOne  
                                    @paraTwo  
                                    @paraThree  
      Output Parameters:  
      Return Status:               0  
      Usage:  
                                    exec procName 11, 'ABC','DETAILS'  
      Local Variables:  
      Called By:  
      Calls:  
      Data Modifications:  
      Updates:  
      Date               Version          Author     Purpose  
      ---------------     ---------     ------     -------------------------  
 ************************************************************************/  
 CREATE PROCEDURE [dbo].[procName]  
      @paraOne int,  
      @paraTwo     varchar(100) = NULL,  
      @paraThree     varchar(255) = NULL  
 AS SET NOCOUNT ON  
 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED  
 /*  
 YOUR PROCEDURE HERE  
 */  
 RETURN 0  
 GO  
 --GRANTING PERMISSION   
 GRANT EXECUTE ON dbo.procName TO EXECGroupName  
 GO  

Applying this format, its been always easy to manage alterations and maintain the version too.

Monday, November 23, 2015

PHP Generator for MySQL

Most of the time, its a headache to code from the scratch when it comes to PHP if you are not using any CMS. PHP Generator for MySQL is a good freeware solution that will provide a rich set of content to generate codes for your database.


It is possible to use even image up-loaders too. and a free version will provide a hardcoded authentication which is Ok for a small scale admin control panel.



A list of records will be available to see if you configured it correctly and can insert new records, update or even delete. To set up such control panel, it won't take more than a day. 

Download Setup Here


Understanding bootstrap rows and columns

Bootstrap is popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web. The design is very simple and one can work on a page that will rendered based on the size of the window.
Bootstrap is responsive and NOT adaptive. Understanding the page to be going to work on is important to make it successful. To have a general idea; Bootstrap uses rows and columns that the page can be divided into.

1. Single Column
 <div class="row">   
 <div class="col-lg-12">Single column </div>  
 </div>  

2. Two Columns
 <div class="row">   
 <div class="col-lg-6">Left column </div>  
 <div class="col-lg-6">Right column </div>  
 </div>  

Likewise you can go for balanced columns or you can choose how to divide the page in to. The following code from bootstrap.css will explain how you can choose it to be divided into. Simple math will let you have a good design.

 .col-lg-12 {  
   width: 100%;  
  }  
  .col-lg-11 {  
   width: 91.66666667%;  
  }  
  .col-lg-10 {  
   width: 83.33333333%;  
  }  
  .col-lg-9 {  
   width: 75%;  
  }  
  .col-lg-8 {  
   width: 66.66666667%;  
  }  
  .col-lg-7 {  
   width: 58.33333333%;  
  }  
  .col-lg-6 {  
   width: 50%;  
  }  
  .col-lg-5 {  
   width: 41.66666667%;  
  }  
  .col-lg-4 {  
   width: 33.33333333%;  
  }  
  .col-lg-3 {  
   width: 25%;  
  }  
  .col-lg-2 {  
   width: 16.66666667%;  
  }  
  .col-lg-1 {  
   width: 8.33333333%;  
  }  

Start designing your own pages. No more designers LOL.

Download it here:
http://getbootstrap.com


Sunday, November 22, 2015

Jquery toastmessage plugin - make it easy

Respect the developer here

The toastmessage gives you a best jquery messages integrated with your website. It looks nice and has many features.
Simplified zip file is attached and Click here to download.

How to use?

1. Add references to the files
 <link href="Responsive/js/toastmessage/resources/css/jquery.toastmessage.css"  
     rel="stylesheet" type="text/css" />  
 <script src="Responsive/js/toastmessage/javascript/jquery.toastmessage.js"  
     type="text/javascript"></script>  
 <script src="Responsive/js/toastmessage/javascript/ToastMessage.js"  
     type="text/javascript"></script>  

2. From your code behind, add this line
 - Success;
 ScriptManager.RegisterStartupScript(this, this.GetType(), "showSuccessToast", "showSuccessToast('Successfully Updated');", true);  

- Error
 ScriptManager.RegisterStartupScript(this, this.GetType(), "showErrorToast", "showErrorToast('Update Error');", true);  

Inspect the ToastMessage.js for other message types.
 function showErrorToast(msg) {  
   $().toastmessage('showToast', {  
     text: msg,  
     sticky: false,  
     position: 'middle-center',  
     type: 'error',  
     closeText: '',  
     close: function () {  
       //console.log("toast is closed ...");  
     }  
   });  
 }  
 function showInfoToast(msg) {  
   $().toastmessage('showToast', {  
     text: msg,  
     sticky: false,  
     position: 'middle-center',  
     type: 'notice',  
     closeText: '',  
     close: function () {  
       //console.log("toast is closed ...");  
     }  
   });  
 }  
 function showSuccessToast(msg) {  
   $().toastmessage('showToast', {  
     text: msg,  
     sticky: false,  
     position: 'middle-center',  
     type: 'success',  
     closeText: '',  
     close: function () {  
       //console.log("toast is closed ...");  
     }  
   });  
 }  
 function showWarningToast(msg) {  
   $().toastmessage('showToast', {  
     text: msg,  
     sticky: false,  
     position: 'middle-center',  
     type: 'warning',  
     closeText: '',  
     close: function () {  
       //console.log("toast is closed ...");  
     }  
   });  
 }  

It looks like below;











You can change the "sticky: false," to true if you need the message to be stick until you close it. Otherwise you can make it close automatically after a given duration of milliseconds. 

ASP.NET - Get Postback Control

Sometimes we need to detect which control caused the postback and following method can be used to get the control in ASP.Net


     public static string GetPostBackControlId(this Page page)  
     {  
       if (!page.IsPostBack)  
         return string.Empty;  
       Control control = null;          
       string controlName = page.Request.Params["__EVENTTARGET"];  
       if (!String.IsNullOrEmpty(controlName))  
       {  
         control = page.FindControl(controlName);  
       }  
       else  
       {           
         string controlId;  
         Control foundControl;           
         foreach (string ctl in page.Request.Form)  
         {             
           if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))  
           {  
             controlId = ctl.Substring(0, ctl.Length - 2);  
             foundControl = page.FindControl(controlId);  
           }  
           else  
           {  
             foundControl = page.FindControl(ctl);  
           }  
           if (!(foundControl is Button || foundControl is ImageButton)) continue;  
           control = foundControl;  
           break;  
         }  
       }  
       return control == null ? String.Empty : control.ID;  
     }