/// <summary> /// Displays the in-place edit control for a given list view subitem. /// It is assumed that the in-place edit control was previously created /// and assigned to the proper column, by means of the SetEditControl /// method. /// </summary> /// <param name="editedItem">The item to be edited.</param> /// <param name="editedSubItem">The subitem to be edited.</param> public void StartEditing(ListViewItem editedItem, ListViewItem.ListViewSubItem editedSubItem) { if (row < 0 || column < 0 || editedSubItem == null) { return; } // Check if event handler available and if positive, raise the event Control editControl; editControls.TryGetValue(column, out editControl); // Override the editable control in the custom subitem, if such an item is used. EditableListViewSubItem customSubItem = editedSubItem as EditableListViewSubItem; if (customSubItem != null) { if (customSubItem.ReadOnly) { // non-editable item return; } else { // override the edit control editControl = customSubItem.EditControl; } } ListViewSubItemEventArgs args = new ListViewSubItemEventArgs(editControl, editedItem, editedSubItem, column); if (SubItemEditing != null && editControl != null) { SubItemEditing(this, args); } // Check if the event was handled - thus the in-place edit controls // displayed. if (!args.Handled) { // Display edit control and also set text. DisplayEditControl(false, editControl, editedSubItem); } Form frm = FindForm(); if (frm != null && frm.KeyPreview) { frm.KeyPreview = false; _restoreKeyPreview = true; } }
/// <summary> /// End the in-place editing action. It results in "hiding" the /// in-place edit control. /// </summary> /// <param name="acceptChanges">Set to true to accept the new value, /// that is resulting after the editing action.</param> private void EndEditing(bool acceptChanges) { Form frm = FindForm(); if (frm != null && _restoreKeyPreview) { frm.KeyPreview = true; _restoreKeyPreview = false; } // Check the row bounds. if (row < 0 || row >= this.Items.Count) { return; } // Check the column bounds. if (column < 0 || column >= this.Columns.Count) { return; } if (!activeEditControl.Visible) { return; } ListViewItem editedItem = this.Items[row]; ListViewItem.ListViewSubItem editedSubItem = editedItem.SubItems[column]; if (acceptChanges) { // Editing results should be handled differently // for each type of supported in-place edit control. EditableListViewSubItem customSubItem = editedSubItem as EditableListViewSubItem; if (customSubItem != null) { customSubItem.Text = activeEditControl.Text; } else { editedSubItem.Text = activeEditControl.Text; } // Check if event handler available and if positive, raise the event if (SubItemEdited != null) { ListViewSubItemEventArgs args = new ListViewSubItemEventArgs(activeEditControl, editedItem, editedSubItem, column); SubItemEdited(this, args); // Check if the event was handled - thus the in-place edit controls // displayed. if (args.Handled) { return; } } } if (SubItemEndEditing != null) { ListViewSubItemEventArgs args = new ListViewSubItemEventArgs(activeEditControl, editedItem, editedSubItem, column); SubItemEndEditing(this, args); } // Nothing is edited right now. row = column = -1; // Disable the control and make it invisible ("hide" it). //>>>> FIXUP for nasty bug // for some strange reason (which we don't have time to investigate) // the SubItemEdited event f***s up the activeEditControl of the list. // So we put an extra protection here to prevent exceptions popping up if (activeEditControl != null) { activeEditControl.Hide(); activeEditControl.Enabled = false; activeEditControl.BringToFront(); // Unsubscribe for the event handlers. activeEditControl.Leave -= new EventHandler(OnEditorLeave); activeEditControl.KeyDown -= new KeyEventHandler(OnEditorKeyDown); // Set activeEditControl as null activeEditControl = null; } // Focus back to the list. Focus(); }
/// <summary> /// Window procedure. Legacy Win32 programming. /// Neither ListView nor its base classes do expose have an /// OnScroll event handler. If we want to catch these events, /// we must do it in Win32 style. However, the best way to /// scroll in-place controls together with the list view is /// to do via WM_PAINT. /// </summary> protected override void WndProc(ref Message m) { Color nonEditableColor = this.BackColor; switch (m.Msg) { case WM_PAINT: // Set distinctive background for editable fields and also reposition the // subitem being edited (if any) ListViewItem.ListViewSubItem editedSubItem = null; foreach (ListViewItem item in Items) { item.UseItemStyleForSubItems = false; item.BackColor = nonEditableColor; item.ForeColor = Color.FromKnownColor(KnownColor.ControlText); int subItemIndex = 0; foreach (ListViewItem.ListViewSubItem subItem in item.SubItems) { Control editControl = null; Color editableColor = Color.FromKnownColor(KnownColor.Wheat); EditableListViewSubItem editableSubItem = subItem as EditableListViewSubItem; if (editableSubItem != null) { if (!editableSubItem.ReadOnly) { // possibly editable (unless the developer forgot // to specify the control) editControl = editableSubItem.EditControl; if (!editableSubItem.IsValid) { editableColor = Color.Wheat; } } } else { // editable editControls.TryGetValue(subItemIndex, out editControl); } if (editControl != null) { // editable item // see if it's being edited right now subItem.BackColor = editableColor; if (item.Index == EditedRow && subItemIndex == EditedColumn) { editedSubItem = subItem; } } else { // non-editable item subItem.BackColor = nonEditableColor; } subItemIndex++; } } // Reposition edit control. if (editedSubItem != null && activeEditControl != null) { DisplayEditControl(true, activeEditControl, editedSubItem); } break; } base.WndProc(ref m); }