Monday, November 9, 2009

Center Align Controls in Windows Forms in .NET

When you are creating the windows forms application, It is hard to center align the control or set of controls in the windows form. The workout for this is pretty simple. Add a TableLayoutPanel control. It should have only one row with height equal to 100% and one column with width equal to 100%. In the properties section change the Dock property to Fill. Now add the desired control to form or add a container control like FlowLayoutPanel,GroupBox, Panel, TableLayoutPanel, TabControl etc and add controls to it. Change the Anchor property to single control or container to None. This will display all the single control or all the controls added to that container aligned in the center of the form even when the form is resized.
I am sure that there may be other ways around to this problem but this is so far the simplest I discovered while playing with the code.

Thursday, October 15, 2009

Connecting Adobe Flex to SQL Server - Part 2 (Adobe Flex)

Create After creating .Net web services, they need to be integrated with Flex to show data.

  • Open IIS (Internet Information services) Manager and add crossdomain.xml to the root of the website. This file is required for flash to access the webserver content.

    1. <?xml version="1.0" ?>
    2. <cross-domain-policy>
    3.   <allow-access-from domain="*"/>
    4.   <site-control permitted-cross-domain-policies="all"/>
    5.   <allow-http-request-headers-from domain="*" headers="*"/>
    6. </cross-domain-policy>

  • Create a new Flex project in Adobe Flex Builder.
  • The main MXML file contains <mx:WebService> component. The layout contains <mx:ViewStack> with two <mx:VBox> containers, one with DataGrid and other with Form for new record insertion. <mx:WebService>contains reference to all its operations using <mx:Operation> tag with result event, handling the result for every operation. All these result handler events are essentially calling the  webservice’s GetDataSet method to refresh the databound ArrayCollection instance. There is an “itemEditEnd” event handler for dataGrid which fires webservice’s UpdateRecord method, when user ends editing for dataGrid item. When user clicks the “Delete” button, Actionscript code behind the MXML file gets the CONTACTID from the row selected by the user and calls the webservice’s DeleteRecord method. When user wants to insert a new record, view changes the selected child to Form for new record insertion, and on user submit, webservice’s InsertRecord method is called. Part of the code is adapted from Flex Builder “Create Application from Database” designer generated code.

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    3.     layout="vertical" pageTitle="Flex SQL Server Application"
    4.     creationComplete="initApp()">
    5.   <!-- Link to external Actionscript file -->
    6.   <mx:Script source="FlexDBAppScript.as" />
    7.  
    8.   <mx:WebService id="websvc"
    9.         wsdl="http://localhost/WebService/Contacts.asmx?wsdl"
    10.         showBusyCursor="true"
    11.         fault="faultHandler(event)">
    12.     <mx:operation name="GetDataSet"
    13.             result="GetDataSetHandler(event)"/>
    14.     <mx:operation name="InsertRecord"
    15.             result="InsertRecordhandler(event)"/>
    16.     <mx:operation name="DeleteRecord"
    17.             result="DeleteRecordHandler(event)"/>
    18.     <mx:operation name="UpdateRecord"
    19.             result="UpdateRecordHandler(event)"/>
    20.   </mx:WebService>
    21.  
    22.   <mx:ViewStack id="appView" width="100%" height="100%">
    23.     <mx:VBox id="displayGrid">
    24.       <mx:DataGrid id="dataGrid"
    25.                 dataProvider="{dataArray}" rowCount="10"
    26.                 editable="true" resizableColumns="true"
    27.                 itemEditEnd="ItemEditEnd(event)">
    28.         <mx:columns>
    29.           <mx:DataGridColumn headerText="Contact ID" dataField="CONTACTID" editable="false"/>
    30.           <mx:DataGridColumn headerText="First Name" dataField="FIRST_NAME" />
    31.           <mx:DataGridColumn headerText="Last Name" dataField="LAST_NAME" />
    32.           <mx:DataGridColumn headerText="City" dataField="CITY" />
    33.           <mx:DataGridColumn headerText="State" dataField="STATE" />
    34.         </mx:columns>
    35.       </mx:DataGrid>
    36.       <mx:HBox>
    37.         <mx:Button label="Add New" id="btnAddNew" click="GoToInsertForm()"/>
    38.         <mx:Button label="Delete" id="btnDelete" click="DeleteItem()"/>
    39.       </mx:HBox>
    40.     </mx:VBox>
    41.  
    42.     <mx:VBox id="insertForm">
    43.       <mx:Form id="ContactForm" label="Insert New Record">
    44.         <mx:FormHeading label="Insert New Record"/>
    45.         <mx:FormItem label="First Name:" id="First_Name_form">
    46.           <mx:TextInput id="tInp_First_Name" text=""/>
    47.         </mx:FormItem>
    48.         <mx:FormItem label="Last Name:" id="Last_Name_form">
    49.           <mx:TextInput id="tInp_Last_Name" text=""/>
    50.         </mx:FormItem>
    51.         <mx:FormItem label="City:" id="City_form">
    52.           <mx:TextInput id="tInp_City" text=""/>
    53.         </mx:FormItem>
    54.         <mx:FormItem label="State:" id="State_form">
    55.           <mx:TextInput id="tInp_State" text=""/>
    56.         </mx:FormItem>
    57.       </mx:Form>
    58.       <mx:HBox>
    59.         <mx:Button label="Save" id="btnSubmit" click="InsertItem()"/>
    60.         <mx:Button label="Cancel" id="btnCancel" click="GoToDisplayGrid()"/>
    61.       </mx:HBox>
    62.     </mx:VBox>
    63.   </mx:ViewStack>
    64. </mx:Application>
    65.  

  • The actionscript code for MXML file is contained in a separate .as file.

    1. // Actionscript file for FlexDBApp.mxml
    2. // Part of the code is adapted from Flex- Create Application from Database generated code.
    3. import mx.collections.ArrayCollection;
    4. import mx.controls.Alert;
    5. import mx.events.CloseEvent;
    6. import mx.events.DataGridEvent;
    7. import mx.rpc.AsyncToken;
    8. import mx.rpc.events.FaultEvent;
    9. import mx.rpc.events.ResultEvent;
    10.  
    11. [Bindable]
    12. public var dataArray:ArrayCollection = new ArrayCollection();
    13.  
    14. private function initApp():void
    15. {
    16.     // Initialize and load the web service
    17.     websvc.loadWSDL();
    18.     websvc.GetDataSet();
    19. }
    20.  
    21. /**
    22. * Result event handler for websvc GetDataSetHandler call
    23. */
    24. private function GetDataSetHandler(e:ResultEvent):void
    25. {
    26.     // Populate dataArray with dataset table
    27.     dataArray = e.result.Tables.Contacts.Rows;
    28. }
    29.  
    30. /**
    31. * Event handler for Add New Button Click event
    32. */
    33. public function GoToInsertForm():void
    34. {
    35.     // Change te view's selected child to insert form
    36.     appView.selectedChild = insertForm;
    37. }
    38.  
    39. /**
    40. * Event handlet for Save Button Click event
    41. */
    42. public function InsertItem():void
    43. {
    44.     websvc.InsertRecord(tInp_First_Name.text, tInp_Last_Name.text, tInp_City.text, tInp_State.text);
    45.     GoToDisplayGrid();
    46. }
    47.  
    48. /**
    49. * Event handler for Delete Button Click event
    50. */
    51. public function GoToDisplayGrid():void
    52. {
    53.     // Change te view's selected child to display Grid
    54.     appView.selectedChild = displayGrid;
    55. }
    56.  
    57. /**
    58. * Result event handler for websvc InsertRecordhandler call
    59. */
    60. private function InsertRecordhandler(e:ResultEvent):void
    61. {
    62.     // Replopulate the dataArray after transaction
    63.     websvc.GetDataSet();
    64. }
    65.  
    66. /**
    67. * Event handler triggered when the user finishes editing an entry
    68. * triggers an "update" server command
    69. */
    70. private function ItemEditEnd(e:DataGridEvent):void
    71. {
    72.     // Get row number of the edited row
    73.     var dgRowIndex:int = e.rowIndex;
    74.     // Get name of DataField being edited
    75.     var dgFieldName:String = e.dataField;
    76.     // Get Column Index being edited
    77.     var dgColIndex:int = e.columnIndex;
    78.     
    79.     var vo:* = dataArray[dgRowIndex];
    80.     var col:DataGridColumn = dataGrid.columns[dgColIndex];
    81.     var newvalue:String = dataGrid.itemEditorInstance[col.editorDataField];
    82.     vo[dgFieldName] = newvalue;
    83.     websvc.UpdateRecord(vo.CONTACTID, vo.FIRST_NAME, vo.LAST_NAME, vo.CITY, vo.STATE);
    84. }
    85.  
    86. /**
    87. * Result event handler for websvc UpdateRecordHandler call
    88. */
    89. private function UpdateRecordHandler(e:ResultEvent):void
    90. {
    91.     // Replopulate the dataArray after transaction
    92.     websvc.GetDataSet();
    93. }
    94.  
    95. /**
    96. * Event handler for Delete Button Click event
    97. */
    98. public function DeleteItem():void
    99. {
    100.     if (dataGrid.selectedItem)
    101.     {
    102.         Alert.show("Are you sure you want to delete the selected record?",
    103.         "Confirm Delete", 3, this, DeleteClickHandler);
    104.     }
    105. }
    106.  
    107. /**
    108. * Event handler function for the Confirm dialog raises when the Delete Button is pressed.
    109. * If the pressed button was Yes, then the product is deleted.
    110. * @param object event
    111. * @return nothing
    112. */
    113. private function DeleteClickHandler(event:CloseEvent):void
    114. {
    115.     var indexForDelete:int = dataGrid.selectedIndex;
    116.     if (indexForDelete == -1)
    117.     {
    118.         return;
    119.        }
    120.         
    121.     if (event.detail == Alert.YES)
    122.     {
    123.         var vo:* = dataArray[indexForDelete];
    124.         websvc.DeleteRecord(vo.CONTACTID);
    125.     }
    126. }
    127.  
    128. /**
    129. * Result event handler for websvc DeleteRecordHandler call
    130. */
    131. private function DeleteRecordHandler(e:ResultEvent):void
    132. {
    133.     // Replopulate the dataArray after transaction
    134.     websvc.GetDataSet();
    135. }
    136.  
    137. /**
    138. *Fault event handler for websvc WebService call
    139. */
    140. private function faultHandler(event:FaultEvent):void
    141. {
    142.     Alert.show(event.fault.message, "Application Error");
    143. }

Tuesday, October 13, 2009

Connecting Adobe Flex to SQL Server - Part 1 (.Net WebService)

This blog is in transition to be moved to new URL. The new and updated version of this post is located at REST Web Services With ASP.Net Web API

Flex is really one of the cool coding languages with lot of flexibility and scope for development. It compiles into SWF file as an end product, which is a client side technology. Flex cannot connect to SQL server directly like ASP.Net or any other server side languages. It uses .net web services to connect to SQL server.
There can be different ways to connect Flex to SQL Server. The method described in this post requires following software:
  • Visual Studio 2008 any version or Visual Web Developer Express Edition
  • Flex Builder 3
  • SQL Server 2005 (Full Version or Express Edition)
  • IIS (Internet Information Services)
To get going
  • Open Visual Studio 2008. Click File –> New Website. Select ASP.NET Web Service as project template and rename webservice(.asmx) file as Contacts.asmx.newwebservice
  • For this example I have created a new database named “Sample” with a table called “Contacts”. The scheme of the table is shown below.image
  • After the new web service is created in VS, open web.config and add connection string for new SQL Sever database between appSettings and System.Web.
    1. <connectionStrings>
    2.     <add name="SampleDBConn" connectionString="Data Source=SERVER_NAME\SQLEXPRESS;Initial Catalog=SAMPLE;Integrated Security=True" providerName="System.Data.SqlClient" />
    3.   </connectionStrings>
  • Create a new database helper class in App_Code directory named “DBConn.cs". It contains various functions for creating  SqlDbConnection, opening & closing the connection, creating and filling a new DataSet from a given select query etc.  
    1. using System;
    2. using System.Configuration;
    3. using System.Data;
    4. using System.Data.SqlClient;
    5.  
    6. /// <summary>
    7. /// Helper class to provide access to database
    8. /// </summary>
    9. public class DBConn
    10. {
    11.     private string connString;
    12.     private SqlConnection sqlConn;
    13.  
    14.     public DBConn()
    15.     {
    16.         try
    17.         {
    18.             connString = ConfigurationManager.ConnectionStrings["SampleDBConn"].ConnectionString;
    19.         }
    20.         catch (Exception ex)
    21.         {
    22.             throw new ConfigurationErrorsException(
    23.                 "Required database isn't configured. Please add connection info to Web.config for 'AdventureWorks' database.", ex);
    24.         }
    25.         sqlConn = new SqlConnection(connString);
    26.     }
    27.  
    28.     /// <summary>
    29.     /// Open Connection for SQL transactions
    30.     /// </summary>
    31.     public void OpenSqlConnection()
    32.     {
    33.         if(sqlConn.State == ConnectionState.Closed)
    34.             sqlConn.Open();
    35.     }
    36.  
    37.     /// <summary>
    38.     /// Close connection after transactions
    39.     /// </summary>
    40.     public void CloseSqlConnection()
    41.     {
    42.         if (sqlConn.State == ConnectionState.Open)
    43.             sqlConn.Close();
    44.     }
    45.  
    46.     /// <summary>
    47.     /// Creates new SqlCommand for given query string
    48.     /// </summary>
    49.     /// <param name="queryString">Query String</param>
    50.     /// <returns>SqlCommand</returns>
    51.     public SqlCommand CreateSQLCommand(string queryString)
    52.     {
    53.         return new SqlCommand(queryString, sqlConn);
    54.     }
    55.  
    56.     /// <summary>
    57.     /// Creates and adds parameter to SqlCommand
    58.     /// </summary>
    59.     /// <param name="command">SqlCommand</param>
    60.     /// <param name="parameterName">Paramater Name</param>
    61.     /// <param name="value">Paramater Value</param>
    62.     public void CreateParameter(SqlCommand command, string parameterName, object value)
    63.     {
    64.         SqlParameter param = command.CreateParameter();
    65.         param.ParameterName = parameterName;
    66.         param.Value = value;
    67.         command.Parameters.Add(param);
    68.     }
    69.  
    70.     /// <summary>
    71.     /// Creates a new dataset and fills it with data for given query
    72.     /// </summary>
    73.     /// <param name="selectCmd">Select Query</param>
    74.     /// <param name="tabName">TableName</param>
    75.     /// <returns>DataSet</returns>
    76.     public DataSet ReturnDataSet(string selectCmd, string tabName)
    77.     {
    78.         sqlConn.Open();
    79.         DataSet dSet = new DataSet();
    80.         SqlDataAdapter sqlDBAdapter = new SqlDataAdapter(selectCmd, sqlConn);
    81.         sqlDBAdapter.Fill(dSet, tabName);
    82.         sqlConn.Close();
    83.         return dSet;
    84.     }
    85. }
  • In the code-behind webservice (asmx) file, create different WebMethods for retrieving, inserting, updating and deleting the data from the database. I have created a web method for data retrieval returning the C# DataSet. All these functions are using DBConn.cs, the database helper class created in previous step. The table used in this example is Conatcts table created in previous steps.
    1. using System;
    2. using System.Data;
    3. using System.Data.SqlClient;
    4. using System.Text;
    5. using System.Web.Services;
    6.  
    7. /// <summary>
    8. /// Summary description for Contact
    9. /// </summary>
    10. [WebService(Namespace = "http://tempuri.org/")]
    11. [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    12. public class Contacts : WebService
    13. {
    14.     private DBConn dbConnection;
    15.     private readonly string[] FieldNames = {"CONTACTID, FIRST_NAME, LAST_NAME, CITY, STATE"};
    16.     public Contacts()
    17.     {
    18.         dbConnection = new DBConn();
    19.     }
    20.  
    21.     /// <summary>
    22.     /// Get data as DataSet
    23.     /// </summary>
    24.     /// <returns>DataSet</returns>
    25.     [WebMethod]
    26.     public DataSet GetDataSet()
    27.     {
    28.         try
    29.         {
    30.             StringBuilder sql = new StringBuilder(128);
    31.  
    32.             sql.Append("SELECT ");
    33.             sql.Append(String.Join(",", FieldNames));
    34.             sql.Append(" FROM CONTACTS");
    35.             return dbConnection.ReturnDataSet(sql.ToString(), "Contacts");
    36.         }
    37.         catch (Exception ex)
    38.         {
    39.             throw new Exception("Data Rerieval Error", ex);
    40.         }
    41.     }
    42.  
    43.     /// <summary>
    44.     /// Inserts a new record
    45.     /// </summary>
    46.     [WebMethod]
    47.     public void InsertRecord(string First_Name, string Last_Name, string City, string State)
    48.     {
    49.         try
    50.         {
    51.             string qString = @"INSERT INTO CONTACTS (FIRST_NAME, LAST_NAME, CITY, STATE) VALUES (@FIRST_NAME, @LAST_NAME, @CITY, @STATE)";
    52.             dbConnection.OpenSqlConnection();
    53.             SqlCommand sqlCmd = dbConnection.CreateSQLCommand(qString);
    54.             dbConnection.CreateParameter(sqlCmd, "@FIRST_NAME", First_Name);
    55.             dbConnection.CreateParameter(sqlCmd, "@LAST_NAME", Last_Name);
    56.             dbConnection.CreateParameter(sqlCmd, "@CITY", City);
    57.             dbConnection.CreateParameter(sqlCmd, "@STATE", State);
    58.             sqlCmd.ExecuteNonQuery();
    59.             dbConnection.CloseSqlConnection();
    60.         }
    61.         catch (Exception ex)
    62.         {
    63.             throw new Exception("Data Rerieval Error", ex);
    64.         }
    65.     }
    66.  
    67.     /// <summary>
    68.     /// Updates the database record
    69.     /// </summary>
    70.     [WebMethod]
    71.     public void UpdateRecord(double ContactID, string First_Name, string Last_Name, string City, string State)
    72.     {
    73.         try
    74.         {
    75.             string qString = @"UPDATE CONTACTS SET FIRST_NAME = @FIRST_NAME, LAST_NAME = @LAST_NAME, CITY = @CITY, STATE = @STATE WHERE CONTACTID = @CONTACTID ";
    76.             dbConnection.OpenSqlConnection();
    77.             SqlCommand sqlCmd = dbConnection.CreateSQLCommand(qString);
    78.             dbConnection.CreateParameter(sqlCmd, "@CONTACTID", ContactID);
    79.             dbConnection.CreateParameter(sqlCmd, "@FIRST_NAME", First_Name);
    80.             dbConnection.CreateParameter(sqlCmd, "@LAST_NAME", Last_Name);
    81.             dbConnection.CreateParameter(sqlCmd, "@CITY", City);
    82.             dbConnection.CreateParameter(sqlCmd, "@STATE", State);
    83.             sqlCmd.ExecuteNonQuery();
    84.             dbConnection.CloseSqlConnection();
    85.         }
    86.         catch (Exception ex)
    87.         {
    88.             throw new Exception("Data Rerieval Error", ex);
    89.         }
    90.     }
    91.  
    92.     /// <summary>
    93.     /// Delete records from database
    94.     /// </summary>
    95.     [WebMethod]
    96.     public void DeleteRecord(double ContactID)
    97.     {
    98.         try
    99.         {
    100.             string qString = @"DELETE FROM    CONTACTS WHERE CONTACTID = @CONTACTID ";
    101.             dbConnection.OpenSqlConnection();
    102.             SqlCommand sqlCmd = dbConnection.CreateSQLCommand(qString);
    103.             dbConnection.CreateParameter(sqlCmd, "@CONTACTID", ContactID);
    104.             sqlCmd.ExecuteNonQuery();
    105.             dbConnection.CloseSqlConnection();
    106.         }
    107.         catch (Exception ex)
    108.         {
    109.             throw new Exception("Data Rerieval Error", ex);
    110.         }
    111.     }
    112. }
  • Set the Contacts.asmx file as start up page, and try invoking various webmethods to make sure that the new webservice is successfully running and retrieving the data.
  • This finishes the .net webservice part of the connection process.
Adobe Flex code is covered in Connecting Adobe Flex to SQL Server - Part 2 (Adobe flex)