Step by Step – GridView with extras


This is a small tutorial on how to display your result in a gridview that supports the following:
1) Sorting
2) Paging
3) Single/Multiple selection using a check box, Select All Checkbox in header
4) An inline details view for each row (master-detail view)

(1) and (2) comes by default if you use a ObjectDataSource for Gridview binding and provide a DataTable/DataView as datasource for that. If your business layer returns a generic list of objects, read this post for ideas how to convert
it into DataTable/DataView for easy grid handling.

Since this is a tutorial lets go step by step:

Step 1:

Lets setup datasource for our sample, For quick setup, I used customer and order data from a sample xml file. Also, I added a class called GridViewData, this class will provide data for objectdatasource to bind to the grid.

Xml Data File:

Customer 1—->* Orders

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="customers">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="customers">
          <xs:complexType>
            <xs:attribute name="CustomerID" type="xs:string" use="required" />
            <xs:attribute name="ContactName" type="xs:string" use="required" />
            <xs:attribute name="CompanyName" type="xs:string" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
<?xml version="1.0" encoding="utf-8" ?>
<customers>
  <customers CustomerID="ALFKI"	ContactName="Maria Anders"	CompanyName="Alfreds Futterkiste" />
  <customers CustomerID="ANATR"	ContactName="Ana Trujillo"	CompanyName="Ana Trujillo Emparedados y helados" />
  <customers CustomerID="ANTON"	ContactName="Antonio Moreno"	CompanyName="Antonio Moreno Taquería"></customers>
  <customers CustomerID="AROUT"	ContactName="Thomas Hardy"	CompanyName="Around the Horn"></customers>
  <customers CustomerID="BERGS"	ContactName="Christina Berglund"	CompanyName="Berglunds snabbköp"></customers>

  <customers CustomerID="BLAUS"	ContactName="Hanna Moos"	CompanyName="Blauer See Delikatessen"></customers>
  <customers CustomerID="BLONP"	ContactName="Frédérique Citeaux"	CompanyName="Blondesddsl père et fils"></customers>
  <customers CustomerID="BOLID"	ContactName="Maria Anderss"	CompanyName="Alfreds Futterkiste 333"></customers>
  <customers CustomerID="BONAP"	ContactName="Martín Sommer"	CompanyName="Bólido Comidas preparadas"></customers>
  <customers CustomerID="BOTTM"	ContactName="Laurence Lebihan"	CompanyName="Bon app"></customers>
</customers>

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="orders">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="orders">
          <xs:complexType>
            <xs:attribute name="OrderID" type="xs:integer" use="required" />
            <xs:attribute name="CustomerID" type="xs:string" use="required" />
            <xs:attribute name="OrderDate" type="xs:string" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
<?xml version="1.0" encoding="utf-8" ?>
<orders>
  <orders OrderID="10643"	CustomerID="ALFKI"	OrderDate="25-08-1997"></orders>
  <orders OrderID="10692"	CustomerID="ALFKI"	OrderDate="03-10-1997"></orders>
  <orders OrderID="10715"	CustomerID="BONAP"	OrderDate="23-10-1997"></orders>
  <orders OrderID="10730"	CustomerID="BONAP"	OrderDate="05-11-1997"></orders>
  <orders OrderID="10732"	CustomerID="BONAP"	OrderDate="06-11-1997"></orders>
</orders>

GridViewData Class:

[DataObject(true)]
public class GridViewData
{
    private DataSet customers;
    private DataSet orders;
    public GridViewData()
	{
        this.customers = HttpContext.Current.Session["Customers"] as DataSet;
        this.orders = HttpContext.Current.Session["Orders"] as DataSet;
        if (this.customers == null)
        {
            this.customers = new DataSet();
            this.customers.ReadXmlSchema(HttpContext.Current.Server.MapPath(@"App_Data\customer.xsd"));
            this.customers.ReadXml(HttpContext.Current.Server.MapPath(@"App_Data\customer.xml"));
            HttpContext.Current.Session["Customers"] = this.customers;
        }
        if (this.orders == null)
        {
            this.orders = new DataSet();
            this.orders.ReadXmlSchema(HttpContext.Current.Server.MapPath(@"App_Data\order.xsd"));
            this.orders.ReadXml(HttpContext.Current.Server.MapPath(@"App_Data\order.xml"));
            HttpContext.Current.Session["Orders"] = this.orders;
        }
	}
    [DataObjectMethod(DataObjectMethodType.Select)]
    public DataView GetCustomers()
    {
        this.customers.Tables[0].DefaultView.Sort = "CustomerID";
        return (this.customers.Tables[0].DefaultView);
    }
}

Step 2:

Add a new webform, GridView.aspx (or any name) to your project.
Add a GridView control into the webform from the ToolBox.
Add a ObjectDataSource control into the webform from the ToolBox
Select ObjectDataSource and set its properties and configure it to use GridViewData Class. (If you select the control Visual Studio will popup a menu where you can select “Configure DataSource”, select that, in the wizard screen that follows, select your GridViewData as your datasource, click next and select your select method from drop down list and click on finish)
Now click on grid, name it and select its datasource as your objectdatasource, use check box selections to enable Paging and Sorting..

Your HTML markup will looks something like this:

<body>
    <form id="form1" runat="server">
    <div>
    
        <asp:GridView ID="GridView1" runat="server" AllowPaging="True" 
            AllowSorting="True" DataSourceID="odsGrid">
        </asp:GridView>
    
    </div>
    <asp:ObjectDataSource ID="odsGrid" runat="server" 
        OldValuesParameterFormatString="original_{0}" SelectMethod="GetCustomers" 
        TypeName="GridViewData"></asp:ObjectDataSource>
    </form>
</body>

Run your project, gridview will display with data…

Step 3:

Now we can refine this gridview to add your pager, number of rows in a page, selection checkbox for each row, Header selection checkbox, etc..

If you set the PageSize attribute to your gridview, it will automatically add a pager. Since our datasource is providing a DataView, objectDataSource now automatically give you paging and sorting.

       <asp:GridView ID="GridView1" runat="server" AllowPaging="True" 
            AllowSorting="True" PageSize="5"  DataSourceID="odsGrid">
        </asp:GridView>

Now we change the GridView markup again to add Templated Columns, for checkbox,
and bound columns for all the other. Also we set AutoGenerateColumns property of grid to false.

Now Markup will look like this,

        <asp:GridView ID="GridView1" runat="server" AllowPaging="True" 
            AllowSorting="True" PageSize="5"  DataSourceID="odsGrid" 
            AutoGenerateColumns="False">
            
            <Columns>
                <asp:TemplateField>
                    <HeaderTemplate>
                        <asp:CheckBox runat="server" ID="chkSelectHeader"  />
                    </HeaderTemplate>
                    <ItemTemplate>
                        <asp:CheckBox runat="server" ID="chkSelect" />
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:BoundField HeaderText="Customer ID" DataField="CustomerID" SortExpression="CustomerID" />                                
                <asp:BoundField HeaderText="Customer Name" DataField="ContactName" SortExpression="ContactName" />
                <asp:BoundField HeaderText="Company" DataField="CompanyName" SortExpression="CompanyName" />
            </Columns>
        </asp:GridView>

Run your project now, gridview will show checkbox for each row and also in header…
Now we need to write some code to manage these selections…

[image]

Step 4:

For handling the selections,etc. we will use these grid events and add handlers for it
– RowCommand
– RowCreated
– RowDataBound

(Select gridview control in design mode, switch to properties, click events and add handlers for these events)

Add a new page level variable
Dictionary checkedItems;
and initialize it on Page_Load. This will be saved into Session for tracking the selections between postbacks on paging, sorting, etc.


    Dictionary<string, bool> checkedItems;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            checkedItems = new Dictionary<string, bool>();
            Session["CheckedItems"] = checkedItems;
        }
        else
        {
            checkedItems = (Dictionary<string, bool>)Session["CheckedItems"];
        }
    }

Now we need to add code for all the events that we are handling,
RowCommand is used to collect the selections and keep track of it…

    protected void gv_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        GetCheckBoxValues((GridView)sender, "chkSelect", checkedItems);
    }
    protected void GetCheckBoxValues(GridView gv, string checkID, Dictionary<string, bool> chkItems)
    {
        Dictionary<string, bool> checkedItems = chkItems;
        foreach (GridViewRow gvr in gv.Rows)
        {
            CheckBox cb = (CheckBox)gvr.FindControl(checkID);
            if (cb != null)
            {
                string id = gvr.Cells[1].Text; // uses Customer ID
                if (cb.Checked)
                    checkedItems[id] = cb.Checked;
                else
                {
                    if (checkedItems != null)
                    {
                        if (checkedItems.ContainsKey(id))
                            checkedItems.Remove(id);
                    }
                }
            }
        }
        //Save to session
        Session["CheckedItems"] = checkedItems;
    
    }

With this code in, Run your project, select couple of items , page to next, you can see (if you debug), that Session[“CheckedItems”] varible holds the selections…

GridView - Select All

GridView - Select All

This collects the selections when Paging happens, but we need to have these selections saved when each row selected too… we will use JavaScript and some AJAX calls to handle this. We will add the required javascript function handlers in gv_RowCreated event for this..

    protected void gv_RowCreated(object sender, GridViewRowEventArgs e)
    {
        GridRowCreated(sender, e, "chkSelectHeader", "chkSelect");
    }
    private void GridRowCreated(object sender, GridViewRowEventArgs e, string gridHeaderCheckName, string gridCheckName)
    {
        if (e.Row.RowType == DataControlRowType.Header)
        {
            CheckBox chkAll = (CheckBox)e.Row.FindControl(gridHeaderCheckName);
            if (chkAll != null)
            {
                //For Header Checkbox click
                chkAll.Attributes.Add("onclick", "SelectAllRows('" + gridHeaderCheckName + "')");
            }
        }
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            CheckBox chk = (CheckBox)e.Row.FindControl(gridCheckName);
            if (chk != null)
            {
                //For Check Box Click
                chk.Attributes.Add("onclick", "SelectRow('" + gridCheckName + "')");
            }
            //For Row Click
            e.Row.Attributes.Add("onclick", "SelectRow('" + gridCheckName + "')");
            e.Row.Attributes.Add("title", "Click to toggle the selection of this row");


        }
    }

And we will add some Javascript code to handle the Row selection and Header Click for select…

   function SelectRow(gridCheckName)
    {
        var key = "";
        var obj = window.event.srcElement;
        if(obj.tagName=="INPUT") //this is a checkbox
        {
            key = obj.parentNode.parentNode.cells[1].innerText;
            if (obj.checked)
            {
                obj.parentNode.parentNode.style.backgroundColor = "#ffffcc";
            }
            else
            {
                obj.parentNode.parentNode.style.backgroundColor = "#ffffff";
            }
        }
        else if (obj.tagName=="TD") //this a table cell
        {
            //get a pointer to the tablerow
            var row = obj.parentNode;
            var chk = row.cells[0].firstChild;
            chk.checked = !chk.checked;
            key = row.cells[1].innerText;
            if (chk.checked)
            {
               row.style.backgroundColor = "#ffffcc";
            }
            else
            {
               row.style.backgroundColor = "#ffffff";
            }
        }
    }
    function SelectAllRows(gridHeaderName)
    {
       var chkAll = window.event.srcElement; 
       var tbl = chkAll.parentNode.parentNode.parentNode.parentNode;
       
       if (chkAll)
       {
            for(var i=1;i<=tbl.rows.length-1;i++)
            {
                if (tbl.rows[i].className == "pager") break;
                var chk = tbl.rows[i].cells[0].firstChild;
                chk.checked=chkAll.checked;
                if (chk.checked)
                    chk.parentNode.parentNode.style.backgroundColor = "#ffffcc";
                else
                    chk.parentNode.parentNode.style.backgroundColor = "#ffffff";
            }
       }
    
    }

We will use gv_RowDataBound event to handle some styling code and also we make the decision whether to show a [+] icon for details view…

    protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        CheckBox cb = (CheckBox)e.Row.FindControl("chkSelect");

        if (cb != null)
        {
            string id = e.Row.Cells[1].Text; //key
            if (checkedItems != null)
            {
                if (checkedItems.ContainsKey(id))
                {
                    cb.Checked = true;
                    e.Row.BackColor = System.Drawing.Color.FromArgb(255, 255, 204);
                }
            }
        }
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            //decide whether to show [+] icon for details
        }

    }

Run project now, and you will see that selections are now highlighted…
Still we save the selections when we page…

[image]

Now let us add a webservice named GridHelper.asmx. This service will enable us to make AJAX calls and
update selections, get details for master-detail view, etc.

This web service has two web methods, one to handle single row selection and other to handle select/deselect all using header checkbox.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Data;

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class GridViewHelper : System.Web.Services.WebService {

    public GridViewHelper () {
    }
    [WebMethod(EnableSession = true)]
    public string HandleSingleSelection(string key,string action) {
        Dictionary<string, bool> checkedItems = null;
        if (Session["CheckedItems"] == null)
            checkedItems = new Dictionary<string, bool>();
        else
            checkedItems = (Dictionary<string, bool>)Session["CheckedItems"];

        if (action == "add")
        {
            if (checkedItems.ContainsKey(key) == false)
                checkedItems[key] = true;
        }
        else
        {
            if (checkedItems.ContainsKey(key) == true)
                checkedItems.Remove(key);
        }
        Session["CheckedItems"] = DDACheckedItems;
    }
    [WebMethod(EnableSession = true)]
    public string HandleHeaderSelection(bool selectAll)
    {
       Session["CheckedItems"] = SetSelections((DataSet)Session["Customers"],selectAll);
    }
    private Dictionary<string, bool> SetSelections(DataSet ds, bool selectAll)
    {
        Dictionary<string, bool> checkedItems = new Dictionary<string, bool>();
        if (selectAll == false) return (checkedItems);
        foreach (DataRow dr in ds.Tables[0].Rows)
        {
            checkedItems[dr["CustomerID"].ToString()] = selectAll;
        }
        return (checkedItems);
    }
}

Now lets go back to our javascript code and add calls to this web service methods.

    function SelectRow(gridCheckName)
    {
        var key = "";
        var obj = window.event.srcElement;
        if(obj.tagName=="INPUT") //this is a checkbox
        {
            key = obj.parentNode.parentNode.cells[1].innerText;
            if (obj.checked)
            {
                obj.parentNode.parentNode.style.backgroundColor = "#ffffcc";
                GridViewHelper.HandleSingleSelection(key,"add",HandleSingleSelectionOnSuccess,AjaxCallOnError);
            }
            else
            {
                obj.parentNode.parentNode.style.backgroundColor = "#ffffff";
                GridViewHelper.HandleSingleSelection(key,"remove",HandleSingleSelectionOnSuccess,AjaxCallOnError);
            }
        }
        else if (obj.tagName=="TD") //this a table cell
        {
            //get a pointer to the tablerow
            var row = obj.parentNode;
            var chk = row.cells[0].firstChild;
            chk.checked = !chk.checked;
            key = row.cells[1].innerText;
            if (chk.checked)
            {
               row.style.backgroundColor = "#ffffcc";
            }
            else
            {
               row.style.backgroundColor = "#ffffff";
            }
        }
    }
    function HandleSingleSelectionOnSuccess(result)
    {    
    }
    function HandleHeaderSelectionOnSuccess(result)
    {    
    }
    function AjaxCallOnError(result)
    {
     alert ("Oops!! Something went wrong!");
    }
    function SelectAllRows(gridHeaderName)
    {
       var chkAll = window.event.srcElement; 
       var tbl = chkAll.parentNode.parentNode.parentNode.parentNode;
       
       if (chkAll)
       {
            for(var i=1;i<=tbl.rows.length-1;i++)
            {
                if (tbl.rows[i].className == "pager") break;
                var chk = tbl.rows[i].cells[0].firstChild;
                chk.checked=chkAll.checked;
                if (chk.checked)
                    chk.parentNode.parentNode.style.backgroundColor = "#ffffcc";
                else
                    chk.parentNode.parentNode.style.backgroundColor = "#ffffff";
            }
            GridViewHelper.HandleHeaderSelection(chk.checked,HandleHeaderSelectionOnSuccess,AjaxCallOnError); 
       }
        
    }

With this change, if you run your project now, we will see that selections are working the way we wanted…
[image]

Step 5:

Now for the last piece, master-detail view, if customer has at least an order, we want to place a [+] icon
after row selector check box. For this we will first add an empty template column to our aspx markup…

            <Columns>
                <asp:TemplateField>
                    <HeaderTemplate>
                        <asp:CheckBox runat="server" ID="chkSelectHeader"  />
                    </HeaderTemplate>
                    <ItemTemplate>
                        <asp:CheckBox runat="server" ID="chkSelect" />
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField>
                    <ItemTemplate>
                    </ItemTemplate> 
                </asp:TemplateField>                 
                <asp:BoundField HeaderText="Customer ID" DataField="CustomerID" SortExpression="CustomerID" />                                
                <asp:BoundField HeaderText="Customer Name" DataField="ContactName" SortExpression="ContactName" />
                <asp:BoundField HeaderText="Company" DataField="CompanyName" SortExpression="CompanyName" />
            </Columns>

We use the DataBound event to check whether there is an order present for each customer and add icons accordingly

    protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        CheckBox cb = (CheckBox)e.Row.FindControl("chkSelect");
        string id = "";
        if (cb != null)
        {
            id = e.Row.Cells[2].Text; //key
            if (checkedItems != null)
            {
                if (checkedItems.ContainsKey(id))
                {
                    cb.Checked = true;
                    e.Row.BackColor = System.Drawing.Color.FromArgb(255, 255, 204);
                }
            }
        }
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            //decide whether to show [+] icon for details
            if (DetailExist(id))
            {
                e.Row.Cells[1].Text = "<img id=\"imgDetailShow\" src=\"Images/plus.png\" alt=\"View\" onclick=\"ShowDetail(this, '" + id + "');\" />";
            }
        }
    }
    private bool DetailExist(string id)
    {
        if (Session["Orders"] == null) return (false);
        DataSet ds = (DataSet)Session["Orders"];
        DataTable dt = ds.Tables[0];
        var query
                = from orders in dt.AsEnumerable()
                  where orders.Field<String>("CustomerID").ToLower().Contains(id.ToLower())
                  select orders;
        if (query.ToList().Count > 0 ) return (true);
        return (false);
    }

Now Add ShowDetail() Javascript function shell and run the project.
You can see that only for the records where there is a detail record present, [+] icon is presented.
Clicking on this [+] icon calls the ShowDetail Javascript function. We will use another AJAX call to get the order details..

GridView

GridView

Step 6:

This new web method returns a JSON string representing orders for the current customer.

    [WebMethod(EnableSession = true)]
    public string GetOrderDetails(string id)
    {
        try
        {
            if (Session["Orders"] == null) return ("[]");
            DataSet ds = (DataSet)Session["Orders"];
            DataTable dt = ds.Tables[0];
            var query
                    = from orders in dt.AsEnumerable()
                      where orders.Field<String>("CustomerID").ToLower() == id.ToLower()
                      select new Order
                      {
                          OrderId = orders.Field<Int64>("OrderID"),
                          OrderDate = orders.Field<String>("OrderDate")
                      };

            List<Order> orderList = query.ToList(); 

            DataContractJsonSerializer ser = new DataContractJsonSerializer(orderList.GetType());
            MemoryStream ms = new MemoryStream();
            ser.WriteObject(ms, orderList);
            string strJSON = Encoding.Default.GetString(ms.ToArray());
            return strJSON;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.Write(ex.Message);
            throw;
        }
    }

Once we have the JSON string representing the order detial in client layer, we can inject HTML snippet into the grid table to show the details.

    function ShowDetail(e,id)
    {
        GridViewHelper.GetOrderDetails(id,GetOrderDetailsOnSuccess,AjaxCallOnError,e);
    }
    function GetOrderDetailsOnSuccess(result,e)
    {
        var obj = Sys.Serialization.JavaScriptSerializer.deserialize(result, true);
        if (obj.length == 0) return;
                //e represents the element that was clicked
        var row, index, table, clickedCell;
        var newRow,newCell,cellHTML;
        if (e.nameProp == "plus.png")
        {

            row = e.parentNode.parentNode;
            index = row.rowIndex;
            table = row.parentNode.parentNode;
            newRow = table.insertRow(index+1);
            newCell = newRow.insertCell(0);
            newCell.colSpan = 4;
            newCell.style.paddingLeft = "30px";
            
            newCell.appendChild(getResultTable(obj));
            
            clickedCell = e.parentNode;
            cellHTML = clickedCell.innerHTML;
            cellHTML = cellHTML.replace(/plus/, "minus");
            clickedCell.innerHTML = cellHTML;

        }
        else
        {
            row = e.parentNode.parentNode;
            index = row.rowIndex;
            table = row.parentNode.parentNode;
            table.deleteRow(index+1);
            clickedCell = e.parentNode;
            cellHTML = clickedCell.innerHTML;
            cellHTML = cellHTML.replace(/minus/, "plus");
            clickedCell.innerHTML = cellHTML;
        }


    }
    function getResultTable(obj)
    {
           var tbl = document.createElement("Table");
           tbl.setAttribute("width", "100%");

           for(i=0;i<obj.length;i++)
           {
                var  row = tbl.insertRow(i);
                var  cell = row.insertCell(0);      
                if (obj[i].OrderId.toString() == "")
                    cell.innerHTML = "&nbsp;";
                else
                    cell.innerHTML = obj[i].OrderId.toString();
                cell = row.insertCell(1);      
                if (obj[i].OrderDate.toString() == "")
                    cell.innerHTML = "&nbsp;";
                else
                    cell.innerHTML = obj[i].OrderDate.toString();
            }
            return (tbl);        
    }

With this change, we have now created a gridview with lots of nice features. Now by applying some nice
CSS classes for styling this grid can look great!

Run the project, you can now click on [+] to expand and view the details and [-] collapses the view.

GridView - Final

GridView - Final

Hope you guys enjoyed this tutorial. Send me a note using comments if you want sample project files in a zip.
[Update: Get Source Code from here:]

Disclaimer: No guarantee that sample code provided will work, use at your own risk!

Comments welcome!

Cheers!

6 comments

  1. RRaveen

    Dear Friends,

    I hope you are doing well. I have launched a web site http://www.codegain.com and it is basically aimed C#,JAVA,VB.NET,ASP.NET,AJAX,Sql Server,Oracle,WPF,WCF and etc resources, programming help, articles, code snippet, video demonstrations and problems solving support. I would like to invite you as an author and a supporter. Looking forward to hearing from you and hope you will join with us soon.

    Please forward this email to all of your friends who are related IT. Send to us your feed about site also.

    Thank you
    RRaveen
    Founder CodeGain.com

  2. Mr Capricorn

    hi ! this is really a nice job .
    I am working on a project that requires to save all selected items of a gridview in a string , please guide me for this ..
    please forward me this code too , probably this would help me
    thankyou !

  3. Pingback: 2010 in review « dotnet etc.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s