Skip to main content
Email Password   helpLost your password?

Introduction

One of my favorite things to do in .NET is to work with XML. Many times, users are asking if they can modify ListView columns at run-time. I've seen solutions, saving client-side preferences into databases. It is not wrong but it is not practical, considering that this data is not really related to the business-model design.

Background

Working often with systems providing a lot of information causes a difficulty level for developers to find a way to design flexible and user-friendly applications. ListView controls with a large amount of columns are one of these things, for example.

Then, how to modify a ListView control at run-time?

Using the code

The source code under the download session was made in Microsoft Visual Studio .NET 2003 - Enterprise Architect. I experienced issues compiling it in previous .NET studio versions.

Now, we need to add the following items into our solution:

  1. A form hosting our ListView control.
  2. Another form allowing us to modify the ListView at run time.
  3. A DataSet.

In the following example, we create a DataSet and name it to ListviewColumns.xsd. In the Toolbox option, drag and drop an Element, and finally in this Element, add a row Columns of type string (see figures 1 and 2).

Figure 1

Figure 2

On the main form (ListviewFrm), drag and drop a ListView control and set the following properties to it:

I also added a button (mColumnsBtn). In the mColumnsBtn_Click event, I added the following code to make an instance of my second form:

private void mColumnsBtn_Click(object sender, System.EventArgs e)
{
    ListviewPropertiesFrm listviewProperties = new ListviewPropertiesFrm();
    listviewProperties.Show();
}

In ListviewFrm, under the ListviewApp_Load event, I call a method ReadXMLColumns:

private void ListviewApp_Load(object sender, System.EventArgs e)
{
    ReadXMLColumns();
}

ReadXMLColumns creates a ListviewColumns typed DataSet, and retrieves the data from ListviewColumns.xml file through the ReadXml method.

private void ReadXMLColumns()
{
    ListviewColumns sr;
    DataTable dt;
    DataColumn dc;

    sr = new ListviewColumns();
    dt = new DataTable("ListviewColumn");
    dc = new DataColumn();

    //Add the table into my typed DataSet

    sr.Tables.Add(dt);
    //Retrieve the type and set the name in the DataColumn

    dc.DataType = System.Type.GetType("System.String");
    dc.ColumnName = "CheckBoxName";
    dt.Columns.Add(dc);

    //Retrieve the path to "Application Data"

    //under my Documents and Settings folder.

    string xmlDocPath = 
      Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

    //Add "ListViewApp" folder into this path

    xmlDocPath = xmlDocPath + "/ListViewApp";

    if (!Directory.Exists(xmlDocPath))
    {
        //Create the directory if it does not exist

        Directory.CreateDirectory(xmlDocPath);
    }
    else
    {
        if (File.Exists(xmlDocPath + "/ListviewColumns.xml"))
        {
            //Read the XML file into my typed DataSet

            sr.ReadXml(xmlDocPath + "/ListviewColumns.xml");
            BuildColumnHeaders(sr);
        }
    }
}

BuildColumnHeaders goes through the DataSet, and finally adds the columns in our ListView by calling the BuildColumn method.

//BuildColumnHeaders

//BuildColumnHeaders goes through the DataSet and calls

//BuildColumn

private void BuildColumnHeaders(DataSet sr)
{
    int i = 0;

    foreach(DataRow dr in sr.Tables[0].Rows)
    {
        string checkBoxName = dr["CheckBoxName"].ToString();

        switch (checkBoxName)
        {
            case "First Column":
                i = BuildColumn("First Column", i);
                break;
            case "Second Column":
                i = BuildColumn("Second Column", i);
                break;
            case "Third Column":
                i = BuildColumn("Third Column", i);
                break;
        }
    }
}
//BuildColumn

//BuildColumn adds a column into mMainListviewLvw.

private int BuildColumn(string columnHeaderName, int i)
{

    ColumnHeader col = new ColumnHeader();
    col.Text = columnHeaderName;
    col.Width = 100;
    mMainListviewLvw.Columns.Add(col);
    i ++;

    return i;
}

ListviewFrm will now be able to read the XML file and display the columns. However, we need to add functionality in order to modify our XML file, therefore it is time to see what is going on in the ListviewPropertiesFrm.

On our second form (ListviewPropertiesFrm), add the following controls (see figure 3):

Figure 3

In the mOkBtn_Click event, I call the ColumnsToXML method:

private void mOkBtn_Click(object sender, System.EventArgs e)
{
    Cursor.Current = System.Windows.Forms.Cursors.WaitCursor;
    ListviewColumnsToXML();
    Cursor.Current = System.Windows.Forms.Cursors.Default;
    Close();
}

In ListviewColumnsToXML method, we create a typed DataSet, then loop through the form controls, and add the CheckBoxes into our DataSet. Finally, we export them into XML by using the WriteXml method.

private void ListviewColumnsToXML()
{
    ListviewColumns sr;
    DataRow dr;
    DataTable dt;
    DataColumn dc;

    sr = new ListviewColumns();
    dt = new DataTable("ListviewColumn");
    dc = new DataColumn();

    //Add the table into my typed dataset

    sr.Tables.Add(dt);
    dc.DataType = System.Type.GetType("System.String");
    //Retrieve the type and set the name in the DataColumn

    dc.ColumnName = "CheckBoxName";
    dt.Columns.Add(dc);

    //Loop through all controls in this form.

    foreach(Control mControl in this.Controls)
    {
        //If the control would be a CheckBox

        if (mControl.GetType().ToString() == "System.Windows.Forms.CheckBox")
        {
            //type cast of the mControl to a CheckBox

            CheckBox C;
            C = (CheckBox) mControl;
            if (C.Checked)
            {
                dr = dt.NewRow();
                dr["CheckBoxName"].ToString();
                //Add the checkbox name into my datarow

                dr["CheckBoxName"] = mControl.Text;
                dt.Rows.Add(dr);
            }
        }
    }
    //Retrieve the path to "Application Data"

    //under my Documents and Settings folder

    string xmlDocPath = Environment.GetFolderPath(
        Environment.SpecialFolder.ApplicationData);

    //Add "ListViewApp" folder into this path

    xmlDocPath = xmlDocPath + "/ListViewApp";
    if (!Directory.Exists(xmlDocPath))
    {
        //Create the directory if it does not exist

        Directory.CreateDirectory(xmlDocPath);
        //and write the XML file

        sr.WriteXml(xmlDocPath + "/ListviewColumns.xml");
    }
    else
    {
        //Write into the XML file

        sr.WriteXml(xmlDocPath + "/ListviewColumns.xml");
    }
}

We are almost done, but we need to add a few things on our ListviewPropertiesFrm_Load event. In order to have our check boxes be checked, or not checked each time we open this form, we need to retrieve the XML data. I use the two methods for that. The first method would do the same things like the ReadXMLColumns did in ListviewFrm, and the second method would set the CheckBoxes' Checked property to true.

Points of Interest

The best way of designing a special ListView for your needs, is to follow an object oriented design. In other words, inherit .NET ListView into a new class, write additional functionality into it, and then create a DLL where you can add it to your future solutions. This ListView could have additional functionality, such as column sorting, pop-up menu, export to Excel, etc.

You must Sign In to use this message board.
 
 
Per page   
  
-- There are no messages in this forum --


Last Updated 13 Oct 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2009