Http://www.codeproject.com/cs/miscctrl/ListViewCellEditors.asp
In-Place editing of listview subitems
Download source files (including Demo Application)-31.2 KB
Introduction
While talking with one of our MERs, 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 inListView
Can be done easily, but editing of single properties requires a little work (since built-inListView
Only allows plain editing ofListViewItem
'S text). Because I didn't find anything pre-built, I decided to write my own in-place editingListView
S, so here it is...
How it is done
In fact, in-place editing inListView
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.
Only the General. NET Framework class does not work. Some internal operations must be performed.
First, you have to have a control to perform the actual editing ofSubItem
. Which control you use is (almost) completely up to you.TextBox
,ComboBox
OrDateTimePicker
Works fine, for example. Since this control is used only whenSubItem
Has been clicked, it shoshould be invisible in the beginning.
First, we must have a control to actually edit the subitem. We usually use Textbox,ComboBox
OrDateTimePicker
.
These controls are invisible at first and can be used only when subitem is clicked.
Then you have to find out whichSubItem
Has been clicked. This part is quite straightforward, I 've added a methodGetSubItemAt()
To myListViewEx
To make things a little easier.
You must find that the subitem has been clicked. This part is quite understandable. I have added getsubitemat () to my listviewex to simplify the operation.
A little twist comes from column reordering. StandardListView
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:
Another problem is that columns are re-sorted. The standard listview control allows you to re-sort the columns in the report view. unfortunately, there is no built-in method to find the current rule, so there must be an internal operation.
[DllImport(<span class="cpp-string">"user32.dll"</span>, CharSet=CharSet.Ansi)]<span class="cs-keyword">private</span> <span class="cs-keyword">static</span> <span class="cs-keyword">extern</span> IntPtr SendMessage(IntPtr hWnd, <span class="cs-keyword">int</span> msg, <span class="cs-keyword">int</span> len, <span class="cs-keyword">ref</span> <span class="cs-keyword">int</span> [] order); <span class="cs-comment">// ListView messages</span><span class="cs-keyword">private</span> <span class="cs-keyword">const</span> <span class="cs-keyword">int</span> LVM_FIRST = <span class="cs-literal">0x1000</span>;<span class="cs-keyword">private</span> <span class="cs-keyword">const</span> <span class="cs-keyword">int</span> LVM_GETCOLUMNORDERARRAY = (LVM_FIRST + <span class="cs-literal">59</span>); |
Using these declarations, you can useLVM_GETCOLUMNORDERARRAY
Message to getListView
'S current column order.
By using the preceding statement, you can use lvm_getcolumnorderarray to obtain the sorting rules of the current listview column.
The next step is to move the editor control in place and to make it visible. once the actual editing is being stored med, 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.
The next step is to move the editing control to a proper position and make it visible. once the actual editing operation is performed, the user must immediately accept or reject any operations by the user. Therefore, some events must be captured during editing.
Usually, a click outside the editor control accepts any changes made, as does the return key. Pressing ESC while in-place editing mode converts back to the originalSubItem
Text.
Generally, when you click the button outside the editing control to accept the operation, press the enter button, and then press the ESC button inside the control to return to the original text.
Because the editor control actually is not part ofListView
, I also had to look for any action that might change the size or location of the editor control. This was done overridingWndProc
:
Because the editing control is not part of the listview, I have to find any action to change the size and position of the editing control. It is implemented by overwriting wndproc:
<span class="cs-keyword">protected</span> <span class="cs-keyword">override</span> <span class="cs-keyword">void</span> WndProc(<span class="cs-keyword">ref</span> Message msg){ <span class="cs-keyword">switch</span> (msg.Msg) { <span class="cs-comment">// Look for WM_VSCROLL, WM_HSCROLL or WM_SIZE messages.</span> <span class="cs-keyword">case</span> WM_VSCROLL: <span class="cs-keyword">case</span> WM_HSCROLL: <span class="cs-keyword">case</span> WM_SIZE: EndEditing(<span class="cs-keyword">false</span>); <span class="cs-keyword">break</span>; <span class="cs-keyword">case</span> WM_NOTIFY: <span class="cs-comment">// Look for WM_NOTIFY of events that might also change the</span> <span class="cs-comment">// editor's position/size: Column reordering or resizing</span> NMHDR h = (NMHDR)Marshal.PtrToStructure(msg.LParam, <span class="cs-keyword">typeof</span>(NMHDR)); <span class="cs-keyword">if</span> (h.code == HDN_BEGINDRAG || h.code == HDN_ITEMCHANGINGA || h.code == HDN_ITEMCHANGINGW) EndEditing(<span class="cs-keyword">false</span>); <span class="cs-keyword">break</span>; } <span class="cs-keyword">base</span>.WndProc(<span class="cs-keyword">ref</span> msg);} |
Here, scrolling and resizing ofListView
Are monitored as well as changes toListView
'S column headers. If one of these messages is wrongly Ed, the input focus is transferred back toListView
, Thus ending in-place editing.
If one of the messages is received, the input focus is returned to listview to end the editing.
How to Use listviewex for in-place editing
There are two ways to perform in-place editingListViewEx
. First, you can use the newSubItemClicked
Event togetherGetSubItemBounds()
To position your editor control by yourself, or you can useStartEditing()
, Which performs all required calculations and Control Positioning by itself.
You can use the new subitemclicked and getsubitembounds () to locate the new edit control. You can also use startediting () to execute all the calculations and control positioning.
So, usually you wocould start by addingListViewEx
And at least one control used as a cell editor to yourForm
. Don't forget to make your cell editor control invisible! Then wire up an event handlerSubItemClicked
And actually start editing:
Generally, you should first add a listviewex and use at least one control as a cell editor. Do not forget to make your cell editor invisible. Then bind an event handle to subitemclicked.
<span class="cs-keyword">private</span> <span class="cs-keyword">void</span> listViewEx1_SubItemClicked(<span class="cs-keyword">object</span> sender, ListViewEx.SubItemClickEventArgs e){ <span class="cs-comment">// Here, I use a ComboBox (comboBox1) as a cell editor:</span> listViewEx1.StartEditing(comboBox1, e.Item, e.SubItem);} |
That's it.
'I ve got ded a small sample application to show you how to useListViewEx
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 PropertyDoubleClickActivation
So that you can decide if the listviewex shocould enter editing mode when you click on a subitem or if a double click is required.
Another point was adding two new events (SubItemBeginEditing
AndSubItemEndEditing
) To give the caller the possibility to control what's displayed in the editing control and what gets put back intoListViewSubItem
.
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.
Translation is too annoying. Check the source code.