Tuesday, June 23, 2009

Dynamic columns in datagrid in Adobe Flex

When we set the dataprovider property of the datagrid, it automatically renders the columns with the default values. For instance, the column title is set as the node name if the dataprovider is XMLListCollection. But we would like to have more control on each column so that we can set it's title, width, and other properties as per our need. For this, we need to create each column dynamically at the run time by taking a first record from the dataprovider. In my same project, as mentioned in the last post, I was using XML output from PHP module to bind with the datagrid. However, this XML is also very dynamic in nature that it has variable numbers of nodes with variable node name based on the parameters selected. Depending on the output, I would also require to set some of the columns as read only when the grid is rendered. The overall idea here is to get the first child node of the XML and generate the array of an Objects with the desired properties set. And then an array of DataGridColumn objects is created and set the property as in the Object created in the first step. Below is the code sample;

private function bindData():void
{
    myGrid.dataProvider = xmlListCollection;
    myGrid.columns = getColumns(getColumnDef(xmlListCollection));
}
        
//get the first item from the XML to define the columns
private function getColumnDef(xmlData:XMLListCollection):Array
{
    var arrColDef:Array = new Array();
    var node:XML = xmlData[0]//get the first node of the XMLListCollection
    var childNodes:XMLList = node.children()//get its child nodes as an XMLList
    var objColDef:Object;
            
    for each(var xmlColumn:XML in childNodes//loop over the XMLList
    {
        objColDef = new Object();
        objColDef.dataField = xmlColumn.localName();
                
        switch(objColDef.dataField)
        {
            case "name":
                objColDef.headerText = "Full Name";
                objColDef.width = 120;
                objColDef.editable = true;
                break;
                    
            case "address":
                objColDef.headerText = "Permanent Address";
                objColDef.width = 120;
                objColDef.editable = true;
                break;
                        
            case "hour":
                objColDef.headerText = "Hour";
                objColDef.width = 120;
                objColDef.editable = false;
                break;
                        
            case "min":
                objColDef.headerText = "Minute";
                objColDef.width = 120;
                objColDef.editable = false;
                break;
                
            default :
                objColDef.width = 120;
                objColDef.editable = true;
                break;
        }
                
        arrColDef.push(objColDef);
    }

    return arrColDef;                    
}

//Generate the actual datagrid columns
private function getColumns(colDef:Array):Array
{
    var dataGridColumn:DataGridColumn;
    var arrColumns:Array = new Array();
            
    for each (var objColDef:Object in colDef)
    {
        dataGridColumn = new DataGridColumn();
        dataGridColumn.dataField =  objColDef.dataField;
        dataGridColumn.headerText = objColDef.headerText;
        dataGridColumn.editable = objColDef.editable;
        dataGridColumn.width =  objColDef.width;
                
        arrColumns.push(dataGridColumn);                
    }
    
    return arrColumns;
}

Friday, June 19, 2009

Deleting multiple records in datagrid in Adobe Flex

Although it sound simple, I had a really hard time finding the solution to delete multiple records in datagrid in one of my projects. I was using XMLListCollection as a dataprovider and a single record could be deleted with removeItemAt(index) method. However, for the multiple selection, Flex stores the indices of the selected rows in an array. If I iterate through these indices and start removing item using the index, as soon as the first record is removed, XMLListCollection re-arrange itself and remaining items get the new index which is not valid against the existing indices in the array. Also, there is no way that we can find if the row is selected just by iterating through the collection of rows. The frustrating part was that Google was not able to provide any answer. So, after spending few hours with couple of failed attempts, something suddenly came to my mind. What-if I start removing item from the bottom of the collection, instead from the top. This will not change the indices of existing items. This worked for items selected in an order. However, if I select items in the datagrid randomly, it fails. Flex pushes the indices of the items to an array as they are selected. That means the indices are not in order. So, there is a method Array.sort() to sort an array. Also, this method accept sortOption to consider the values in the array as numeric. Finally it worked. Below is the sample code;

//get the selected indices in the array
var sIndices:Array = myGrid.selectedIndices; 
                
//since the indices are pushed as they selected, we need to sort them in ascending order
sIndices.sort(Array.NUMERIC)
                
//get the highest index first and remove the item
// i.e. start removing items from the bottom so that change in index won't give any problem
for(var index:int = sIndices.length-1; index>=0; index--
    xmlListCollection.removeItemAt(sIndices[index]);


What amazed me the most is that I didn't find a single discussion in any of the websites, forums, blogs about this. Is it only me who want to have this kind of feature in the datagrid or the solution was so simple that people easily implemented it? :-)

Tuesday, October 14, 2008

Excluding config file from version control

Every application has some kind of configuration file to load settings. For instance, ASP.NET applications make use of web.config file to get the connection string for database operations. Similarly, desktop applications use INI file. While developing the application, each developer use configuration file as per their need. If the source is maintained in source control system, developers have to take extra care not to commit such configuration files. If somebody does it by mistake, everybody's file will be altered while updating from the source control. There is a simple way to avoid such situation. Don't put the configuration file under source control. Instead, put a template of the file, something like "app.config.tmpl". Then, after the initial checkout, have the users do a normal OS copy of the template to the proper filename, like "app.config" and have users customize the copy. The file is unversioned, so it will never be committed.

Thursday, August 21, 2008

Retrieve full name from Active Directory using C#

Once upon a time, I was given a task to build a simple attendance system to replace the attendance register in our office. Starting from sourceforge.net, I tried to find open source application to fit our requirement. After spending few hours in the Internet, I could not convinced myself with the applications that I came across. Then I suddenly realized that we are using Active Directory to log in to domain and also thought that if I could get the user detail from AD somehow, I can build a system which does not require any user login. Finally, I was able to find the code to get the full name of the current Windows user and build a small prototype for attendance system. The logic behind this application is to get the user detail from Active Directory and simply log attendance detail to another database. This will reduce the overhead of loggin in to the system as well as user administration part. Below is the code to get the full name of Windows user;
using System.DirectoryServices;

public static string GetFullName(string strLogin)
    {
        string str = "";
        string strDomain;
        string strName;

        // Parse the string to check if domain name is present.
        int idx = strLogin.IndexOf('\\');
        if (idx == -1)
        {
            idx = strLogin.IndexOf('@');
        }

        if (idx != -1)
        {
            strDomain = strLogin.Substring(0, idx);
            strName = strLogin.Substring(idx + 1);
        }
        else
        {
            strDomain = Environment.MachineName;
            strName = strLogin;
        }

        DirectoryEntry obDirEntry = null;
        try
        {
            obDirEntry = new DirectoryEntry("WinNT://" + strDomain + "/" + strName);
            System.DirectoryServices.PropertyCollection coll = obDirEntry.Properties;
            object obVal = coll["FullName"].Value;
            str = obVal.ToString();
        }
        catch (Exception ex)
        {
            str = ex.Message;
        }
        return str;
    }

Wednesday, April 30, 2008

Some useful tools for Delphi developers

I was always fascinated by the tools that are available to .NET developers which help to increase the productivity, like unit testing framework (NUnit), documenation tool and automated build tool (NANT). So, I started looking for same for Delphi. Starting with the documentation tool, I tried few applications but not so promising. Lastly I found DelphiCodeToDoc and it worked well for me. Though there are few bugs, but the tool is great and it supports JavaDoc style documentation. Again, I found that the author of this application is offering a template for GExperts. Tried that and worked well. Next target was unit testing framework. The only one framework I found was DUnit. Also tried this tool and worked very well for me. Finally, I started searching for automated build tool for Delphi application. The one I tried was WANT. Due to the poor documentation, I was forced to learn the whole building process from ANT website and looking into WANT's own build script. In a few hours, I was able to write a script to build my first test application including unit test with DUnit. Super cool. Somebody said "Sky is the limit". Very true. Since my last unit test used GUIRunner, I wanted to try something with console. Could not find a clue how to do that. Well, after going through the build script of WANT again and again, I noticed that we need to create a DLL version of test application. Tried it and worked well. I will try explain this process in detail in my next post.