Click here to Skip to main content
15,174,684 members
Articles / Programming Languages / C#
Posted 8 Dec 2002


49 bookmarked

Persist ListView settings with serialization

Rate me:
Please Sign up or sign in to vote.
4.73/5 (29 votes)
8 Dec 20023 min read
Serialization is a powerful feature of .NET. Here I use it to add functionality to the ListView control.

Sample Image - SaveListView.jpg


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:

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:

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 );

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

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

ListViewSettings listViewSettings = null;

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

Now there is still another limitation of the ListView 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)
        if( listView.View == View.Details )
    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.


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.


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

QuestionSAve the items of my listview as XLM file Pin
alonetmr1-Jul-13 4:27
Memberalonetmr1-Jul-13 4:27 
GeneralMy vote of 5 Pin
Gun Gun Febrianza7-Aug-12 5:05
Member Gun Gun Febrianza7-Aug-12 5:05 
GeneralDeserialize not working Pin
Jayson Ragasa21-Jan-10 10:57
MemberJayson Ragasa21-Jan-10 10:57 
GeneralRe: Deserialize not working Pin
Jayson Ragasa21-Jan-10 11:26
MemberJayson Ragasa21-Jan-10 11:26 
Generala little contribution Pin
Jayson Ragasa21-Jan-10 11:36
MemberJayson Ragasa21-Jan-10 11:36 
General.NET 2.0 Note Pin
mb1819-Sep-08 13:18
Membermb1819-Sep-08 13:18 
GeneralFantasitic work Pin
Asghar Panahy4-Oct-07 3:31
MemberAsghar Panahy4-Oct-07 3:31 
GeneralRe: Fantasitic work Pin
john_mcp11-May-08 14:37
Memberjohn_mcp11-May-08 14:37 
GeneralChanging the serialized objects Pin
werbej8-Jan-07 12:22
Memberwerbej8-Jan-07 12:22 
GeneralDynamic Columns Pin
lakhanisa17-May-06 14:21
Memberlakhanisa17-May-06 14:21 
GeneralColumns must be sorted by order to restore correctly Pin
Guido_d31-Aug-05 3:35
MemberGuido_d31-Aug-05 3:35 

It seems that I need to sort the list of columnsettings by order before sending the message to the listview, in order to restore correctly.

I now use the following code:

(may need to be adapted before use)

public void RestoreFormat( ListView listView )<br />
		{<br />
			try<br />
			{<br />
				listView.Hide();<br />
				// sort array before restoring<br />
				ListViewColumn[] sorted = new ListViewColumn[listViewCols.Count];<br />
				for (int x=0;x<listViewCols.Count;x++)<br />
				{<br />
					ListViewColumn lc = (ListViewColumn)listViewCols[x];<br />
					sorted[lc.order]=lc;<br />
				}<br />
				<br />
				for( int i=0;i<sorted.Length; i++ )<br />
				{<br />
					foreach( ColumnHeader column in listView.Columns )<br />
					{<br />
						ListViewColumn lvc = sorted[i];<br />
						string headername = lvc.header;<br />
						//string colname = column.Text.Replace(" ", "");<br />
<br />
						if( column.Index.ToString() == headername )<br />
						{<br />
							LV_COLUMN pcol = new LV_COLUMN();<br />
							pcol.mask = LVCF_ORDER;<br />
							pcol.iOrder = lvc.order;<br />
							bool ret = SendMessage(listView.Handle, LVM_SETCOLUMN, column.Index, ref pcol);<br />
							column.Width = lvc.width;<br />
							break;<br />
						}<br />
					}<br />
				}<br />
				listView.Show();<br />
			}<br />
			catch(Exception e) {report(e);}<br />
		}<br />
		void report(Exception e)<br />
		{<br />
			Trace.WriteLine(e.Message);<br />
			Trace.WriteLine(e.StackTrace);<br />
		}	<br />

GeneralProblem with restoring layout Pin
Colin Parker14-Oct-04 6:05
MemberColin Parker14-Oct-04 6:05 
GeneralRe: Problem with restoring layout Pin
Colin Parker15-Oct-04 0:33
MemberColin Parker15-Oct-04 0:33 
GeneralRe: Problem with restoring layout Pin
Wolfgang Schardt19-Oct-04 1:00
MemberWolfgang Schardt19-Oct-04 1:00 
Generalthis code is not working for large number of columns Pin
mikica197224-May-04 21:37
Membermikica197224-May-04 21:37 
GeneralRe: this code is not working for large number of columns Pin
Chubby Arse15-Aug-05 2:08
MemberChubby Arse15-Aug-05 2:08 
GeneralExtending this schema to serialize more objects Pin
Josep L Colom18-Feb-03 4:43
MemberJosep L Colom18-Feb-03 4:43 
GeneralRe: Extending this schema to serialize more objects Pin
Alen Oblak14-Aug-06 10:34
MemberAlen Oblak14-Aug-06 10:34 
GeneralSome modificatins which you can insert into yours code Pin
Oleksandr Kucherenko15-Dec-02 22:39
MemberOleksandr Kucherenko15-Dec-02 22:39 

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

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