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

In-place editing of ListView subitems

By , 19 Oct 2004
 

Introduction

While talking with one of our customers, he wanted an additional feature in one of our programs to let him drop a number of files onto our application and then modify certain properties of the resulting documents in a list.

Showing these documents in a ListView can be done easily, but editing of single properties requires a little work (since built-in ListView only allows plain editing of a ListViewItem's text). Because I didn't find anything pre-built, I decided to write my own in-place editing for ListViews, so here it is...

How it is done

In fact, in-place editing in a ListView isn't too much magic, but there are a few places where the plain .NET framework classes aren't sufficient, so I had to use a little Interop.

First, you have to have a control to perform the actual editing of the SubItem. Which control you use is (almost) completely up to you. TextBox, ComboBox or DateTimePicker works fine, for example. Since this control is used only when a SubItem has been clicked, it should be invisible in the beginning.

Then you have to find out which SubItem has been clicked. This part is quite straightforward, I've added a method GetSubItemAt() to my ListViewEx to make things a little easier.

A little twist comes from column reordering. Standard ListView allows you to rearrange its columns while in report view (AllowColumnReorder property). Unfortunately, there is no built-in way to find out the current order of your columns, so this is where Interop came in handy:

[DllImport("user32.dll", CharSet=CharSet.Ansi)]
private static extern IntPtr SendMessage(IntPtr hWnd, 
                        int msg, int len, ref int [] order);

// ListView messages
private const int LVM_FIRST = 0x1000;
private const int LVM_GETCOLUMNORDERARRAY = (LVM_FIRST + 59);

Using these declarations, you can use the LVM_GETCOLUMNORDERARRAY message to get the ListView's current column order.

The next step is to move the editor control in place and to make it visible. Once the actual editing is being performed, the user must be able to accept or reject any changes he makes, so there are a few events that have to be caught while editing.

Usually, a click outside the editor control accepts any changes made, as does the Return key. Pressing ESC while in in-place editing mode converts back to the original SubItem text.

Because the editor control actually is not part of the ListView, I also had to look for any action that might change the size or location of the editor control. This was done overriding WndProc:

protected override void WndProc(ref Message msg)
{
    switch (msg.Msg)
    {
        // Look for WM_VSCROLL, WM_HSCROLL or WM_SIZE messages.
        case WM_VSCROLL:
        case WM_HSCROLL:
        case WM_SIZE:
            EndEditing(false);
            break;
        case WM_NOTIFY:
        // Look for WM_NOTIFY of events that might also change the
        // editor's position/size: Column reordering or resizing
        NMHDR h = (NMHDR)Marshal.PtrToStructure(msg.LParam, typeof(NMHDR));
        if (h.code == HDN_BEGINDRAG ||
            h.code == HDN_ITEMCHANGINGA ||
            h.code == HDN_ITEMCHANGINGW)
            EndEditing(false);
        break;
    }

    base.WndProc(ref msg);
}

Here, scrolling and resizing of the ListView are monitored as well as changes to the ListView's column headers. If one of these messages is received, the input focus is transferred back to the ListView, thus ending in-place editing.

How to use ListViewEx for in-place editing

There are two ways to perform in-place editing with ListViewEx. First, you can use the new SubItemClicked event together with GetSubItemBounds() to position your editor control by yourself, or you can use StartEditing(), which performs all required calculations and control positioning by itself.

So, usually you would start by adding a ListViewEx and at least one control used as a cell editor to your Form. Don't forget to make your cell editor control invisible! Then wire up an event handler for SubItemClicked and actually start editing:

private void listViewEx1_SubItemClicked(object sender, 
                         ListViewEx.SubItemClickEventArgs e)
{
    // Here, I use a ComboBox (comboBox1) as a cell editor:
    listViewEx1.StartEditing(comboBox1, e.Item, e.SubItem);
}

That's it.

I've included a small sample application to show you how to use ListViewEx with several different cell editors. Feel free to use the control or the source to your heart's desire and have fun!

Additional features

Your comments gave me some hints on missing features, so meanwhile I've added an additional property DoubleClickActivation so that you can decide if the ListViewEx should enter editing mode when you click on a subitem or if a double click is required.

Another point was adding two new events (SubItemBeginEditing and SubItemEndEditing) to give the caller the possibility to control what's displayed in the editing control and what gets put back into the ListViewSubItem.
Now you're able to add a password field as a cell editor and transfer the plain password to and from the edit control without having it shown in the listview. Take a look at the sample project to see how it's done.

History

  • 09.04.2004:
    • Initial release.
  • 19.04.2004:
    • Update to account for editor control and ListViewEx not sharing the same parent (thanks Eric-Paul).
      Fixed code has been uploaded.

  • 19.10.2004:
    • Reviewed the whole project.
    • Fixed a few bugs.
    • Added new features (DoubleClickActivation, new events, higher level of control over the editing process,...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

mav.northwind
Software Developer (Senior) 4voice AG
Germany Germany
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionScrolling ProblemmemberAmir Sacic2 Aug '12 - 9:58 
Everything runs perfect except:
 
When i scroll down and edit something the program crashes
 
msg.Msg = 4143
Questionworks like a charm! great!membervelt_99118 Apr '12 - 22:16 
This is really what i needed. Thank you.
Questionselect itemmemberJanos01210 Feb '12 - 0:32 
Hello,
 
I also have a problem with select an item and the line of it. I am using C# .Net 2.0
 
Thank you for the controll and for the help!
QuestionEntire row selection is not working in .net 4.0memberO B Kiran7 Feb '12 - 19:58 
i have upgraded the control to .net 4.0 in vb language. when i click on combobox inside listview the control the entire row is not getting highlighted. it's behaviour is strange.
QuestionHow to get the value of editable textBoxes of listviewEx ?membersaraMughal9 Dec '11 - 0:58 
Any help would be highly appreciated..
GeneralMy vote of 5memberThandermax13 Nov '11 - 4:17 
Helpful ready to use control
QuestionTHANKSmemberThandermax13 Nov '11 - 4:17 
it was helpful.
BugDatetimepicker String was not recognised as a valid datetime [modified]memberMember 821449417 Oct '11 - 14:37 
EDIT:
my bad, for some reason the application is adopting the en-US date encoding, forcing the date via some formatting fixes this.
END EDIT
 

Firstly, wonderful extension of the list view! love it.
 
unfortunatly, I am having some issue using this control in a VB.net project.
 
I have a field in the listviewex, which is a date string, and is associated with "datetimepicker" control the LVI is defined as per your example program:
 
lvi.SubItems.Add(Amendment.Issued)
 
amendment.issued is part of a structure defined as:
 
Structure AmendDataType
    Dim No As String
    Dim Drawn As String
    Dim By As String
    Dim Check As String
    Dim App As String
    Dim Issued As String
    Dim Desc As String
End Structure
 
this value will cause the error above, though it has been defined and manipulated as a string.
 
if i hard code the string as:
lvi.SubItems.Add("01/01/2010")
this string works.
 
the most notable debug details as as follows:
 
system.FormatException: String was not recognized as a valid DateTime.
   at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
   at System.Windows.Forms.DateTimePicker.set_Text(String value)
   at ListViewEx.ListViewEx.StartEditing(Control c, ListViewItem Item, Int32 SubItem)
   at SSMExplorer.SSMExplorerDlg.lvRevisions_SubItemClicked(Object sender, SubItemEventArgs e) in c:\users\adam kalajzich\documents\visual studio 2010\Projects\SSMExplorer\SSMExplorer\SSMExplorerDlg.vb:line 1355
 
Any help would be greatly appreciated.

modified 23 Oct '11 - 18:05.

Questionhow to change SubItems Value in SubItemEndEditing?memberStehtimSchilf12 Oct '11 - 1:01 
Hi
 
I have a simple textbox in my ListViewEx. In the SubItemEndEditing event handler I check user's input. Now I simple like to replace all blanks to an empty string:
 
// trim
string input = this._editControls[1].Text;
input = input.Replace(" ", "");
 
// not working:
e.Item.SubItems[e.SubItem].Text = input;
 

// not working as well:
this._editControls[1].Text = input;
 
The problem is ListViewEx still displays the input as is, with all blanks, although I see during debugging input assignment has been done.
This can't be difficult, but how do I achieve it?
 
cheerioh & thx
SiS
GeneralMy vote of 5memberJeffreyNguyen26 Jun '11 - 18:02 
Thanks a lot, your program is AWESOME!!!
GeneralAdd Image On Subitem?memberMember 38926185 May '11 - 3:52 
you can add an image control and display it in a SubItem immediately without having to click?
GeneralHighlight selectionmembersathishraja3 May '11 - 21:35 
Great Work!.
 

I have problem with Highlight brush.
 
If I disable HideSelection=false property,
all the items highlighted with highlight brush.
 
Any fix for this!.
GeneralMy vote of 4membertangbin2006 Apr '11 - 19:08 
I'm trying to solve this problem,too. Thanks for the author
Questionhow can I save the edited values on list view?memberSandhya Yamarthi25 Mar '11 - 7:45 
Hi,
After I edited the subitems in this list view, I cant figure it out how to save / hold the values on to that listview?
Questionhow to set items in the 1st and subitems in the 2nd column are not to be edited?memberSandhya Yamarthi25 Mar '11 - 7:38 
Hi,
First of all, thank a lot for the code you provided.
I want to modify this listviewEX as my listview has its items in the first column and sub items in the second column are not editable. So I want to set a text box as an editor control for the subitem that exists in the third column and a combobox for the subitem in the fourth column and so on..
But when I tried your code, It just satrted implementing from the item in the first column it self.
 
So can you please suggest me how to set the editor controls from which ever column I want other than first column?
 
Thank you so much again!
AnswerRe: how to set items in the 1st and subitems in the 2nd column are not to be edited?memberSandhya Yamarthi25 Mar '11 - 8:40 
I just god the solution for this.
I tried editing the code as the following and it worked for me!!!!
 
private void listViewEx1_SubItemClicked(object sender, SubItemEventArgs e)
{
if (e.SubItem == 0 || e.SubItem == 1)
{
return;
}
listViewEx1.StartEditing(Editors[e.SubItem], e.Item, e.SubItem);
}
GeneralMy vote of 5memberbrotherbamboo2 Mar '11 - 12:44 
well done, thanks!
GeneralSuggestion: SubItemAfterEditingEventHandlermemberMember 403088927 Jan '11 - 4:29 
I found it useful to have an event fire after the value had been updated. (OnSubItemEndEditing event was not ideal)
You might want to extend your control to include:
 
EndEditing()
:
:
OnSubItemEndEditing(e);
 
if (!e.Cancel)
{
_editItem.SubItems[_editSubItem].Text = e.DisplayText;
 
SubItemAfterEditingEventArgs afterEvent = new SubItemAfterEditingEventArgs(
_editItem,
_editSubItem,
_editingControl.Text);
OnSubItemAfterEditing(afterEvent);

}
:
:

QuestionSendMessage causes ListViewEX to fire SubItemEndEditing event again [modified]memberXtErMiNaToR10226 Jan '11 - 4:10 
Hi,
 
First off, great control!
 
Now to business, the control fires the SubItemEndEditing event whenever I send a message to the control (I'm sending the control a message to scroll vertically).
 
I am firing this event from the SubItemEndEditing event listener.
 
Any idea as to why this is happening and how I can work around this?
 
Thanks!
 
Regards
Xtr
 

--Edit
 
Nevermind, the control checks specifically for those messages and cancels the edit, which in turn fires the event again.
I will just put my scrolling functionality in the control itself.
 
Thanks!
modified on Thursday, January 27, 2011 1:51 AM

GeneralVery good work!memberMember 403088925 Jan '11 - 3:11 
The "Additional Features" were essential to my project. Keep up the good work.
GeneralGroupsmemberJean-BA13 Oct '10 - 23:05 
Hi,
 
very nice work, but why is it impossible to use groups in this project ?
 
thank u
GeneralVertical scrolling not working with horizontal scrollbarmemberNick Barton9 Jul '10 - 1:33 
I have implemented a derived class from listviewex which has DatePicker, Combos and Textboxes embedded. The content happens to be wider than the viewable listview. When one of the embedded controls is only partially visible the listview won't vertically scroll at all. However, as soon as the horizontal is scrolled so that the straddled control becomes wholey visible the vertical scroll immediately jumps to the correct position.
 
I've tried to debug and it appears that the call to Item.GetBounds(ItemBoundsPortion.Entire) is returning the unscrolled position.
 
I've partially solved my problem by ensuring that the total of the column widths will fit in the listview width and implementing locked columns - see 'Locking ListView Column Size
By Chris Morgan | 20 Sep 2005' on codeproject.com.
 
Any ideas?
GeneralComboBox unwanted behaviour on arrow down in listmemberMember 235184319 Mar '10 - 3:58 
Hi
thx for a Cool control.
 
After implementing, I was testing, and discovered odd behaviour of the combobox.
Using "Alt"+"ArrowDown" opens the list correct, but trying to step down the list with "ArrowDown" close the list and update the combobox text property.
 
Anybody have an idea, how to avoid this behaviour, so it will be possible to use the "ArrowUp" and "ArrowDown" to step through the list?
 
Best regards
Kim
GeneralRe: ComboBox unwanted behaviour on arrow down in listmemberMember 235184319 Mar '10 - 4:22 
Hi
I was too fast. Just realized that control_SelectedValueChanged is called and end editing.
Best regards
Kim
GeneralCode snippet to make the SubItemEndEditingEventArgs.Cancel flag workmemberGabriel Bizzotto10 Feb '10 - 1:57 
When implementing the SubItemEndEditing event, the parameter SubItemEndEditingEventArgs has a field Cancel, supposedly to cancel the edition. It does not work.
Edit ListExView.cs, method EndEditing.
Instead of
_editItem.SubItems[_editSubItem].Text = e.DisplayText;
Put
if (e.Cancel == false)
    _editItem.SubItems[_editSubItem].Text = e.DisplayText;

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 20 Oct 2004
Article Copyright 2004 by mav.northwind
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid