Click here to Skip to main content
Click here to Skip to main content

Persist ListView settings with serialization

, 8 Dec 2002
Rate this:
Please Sign up or sign in to vote.
Serialization is a powerful feature of .NET. Here I use it to add functionality to the ListView control.

Sample Image - SaveListView.jpg

Introduction

There are several limitations of the ListView control that comes with .NET. First, there is no way to query the order of the columns if you allow the user to reorder them (set AllowColumnReorder=true). Second, there are no events generated when the user moves a column or changes the width of a column. Somebody else might take the time to write a replacement for this control; I needed something quicker.

In this article, I'll show you how to persist the column order and width settings, by using serialization, binary serialization to be more specific. And you won't believe how easy it is.

You can use the demo source from this article to follow along. If you're using your own code, make sure the ListView control is in details mode (set View=Details) or you'll be confused all the way through. Also make sure you have AllowColumnReorder set to true.

The code

The class ListViewSettings is where all the work is done and there is some funky code going on here, so it's nice to encapsulate that in one place. Unfortunately, the ListView control provides no means of querying the column order once the user has reordered them. The columns are always returned in the order they were created. To get the column order, we have to send a message to the control and ask for them. And to set the order, we have to send another message.

bool ret = SendMessage(listView.Handle, LVM_GETCOLUMN, 
                                             column.Index, ref pcol);
bool ret = SendMessage(listView.Handle, LVM_SETCOLUMN, 
                                             column.Index, ref pcol);

We're also interested in saving and restoring the column widths, so we set up a class that contains all the necessary items:

[Serializable]
public class ListViewColumn
{
    public string header;
    public int width;
    public int order;

    public ListViewColumn( string colHeader, int colWidth, int colOrder )
    {
        header = colHeader;
        width = colWidth;
        order = colOrder;
    }
}

And we mark this class as Serializable with an attribute. That tells the compiler that we are interested in saving this object. You'll need to use the Serializable attribute on every class you plan on saving, even if objects from that class will only ever be created within another class marked as Serializable. In other words, the Serializable attribute is not inherited. So you'll notice that the class that contains all the ListViewColumns is also marked Serializable:

[Serializable]
public class ListViewSettings
{...}

When you serialize objects, you do have some say in how the objects get saved. And sometimes it is necessary to tell the compiler to save objects in a certain way. In this case, there is an ArrayList that contains all the ListViewColumn objects. We want those to be saved as elements, so we can control that through additional attribute tags:

[XmlElement("ListViewColumns", typeof(ListViewColumn))]
public ArrayList listViewCols = new ArrayList();

Now for the fun and easy part:

Since we set up our object to be Serializable, with just a few lines of code we can save it in a binary format:

ListViewSettings listViewSettings = new ListViewSettings( listView );

try
{
    IFormatter formatter = new BinaryFormatter();
    Stream stream = new FileStream("ListViewSettings.config", 
              FileMode.Create, FileAccess.Write, FileShare.None);
    formatter.Serialize(stream, listViewSettings);
    stream.Close();
}
catch {}

And reading it back in to reconstitute our object, is just as easy:

ListViewSettings listViewSettings = null;

try
{
    IFormatter formatter = new BinaryFormatter();
    Stream stream = new FileStream("ListViewSettings.config", 
                  FileMode.Open, FileAccess.Read, FileShare.Read);
    listViewSettings = (ListViewSettings) formatter.Deserialize(stream);
    stream.Close();
    listViewSettings.RestoreFormat( listView );
}
catch {}

Now there is still another limitation of the ListView control...it doesn't generate an event when the user drags or resizes its columns. In the demo application, you control the saving and restoring by clicking buttons. In your own applications, you'll need to place calls to SaveColumnData() and RestoreColumnData() in appropriate places in your code. The form's closing event is one good place for saving the data:

private void MainForm_Closing(object sender, 
                System.ComponentModel.CancelEventArgs e)
{
    try
    {
        if( listView.View == View.Details )
            SaveColumnData();
    }
    catch {}
}

Don't forget to change the connection string in the form_load event to point to a database on your network that has the Northwind database installed.

Conclusion

Serialization can be used for a lot of things, creating persistent objects is just one. But in this case, serialization is the perfect solution for saving and restoring column settings in a ListView. I hope you can make good use of this code in your own projects.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Dan Fontanesi
Web Developer
United States United States
I'm a software engineer and consultant working in San Diego, California. I began using .NET during the early alpha releases since I worked for a Microsoft subsidiary then, and now I've focused my career on .NET technologies.
 
There are a lot of .NET sites out there now, but The Code Project is still top of the heap.

Comments and Discussions

 
GeneralColumns must be sorted by order to restore correctly PinmemberGuido_d31-Aug-05 2:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 9 Dec 2002
Article Copyright 2002 by Dan Fontanesi
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid