SUMMARY
This step-by-step article describes how to use a
ComboBox control to edit the data in a
ListView control. This method replaces the standard text box approach of
editing the data in a
ListView control.
back to the
topLearn about the technique
By using the
LabelEdit property of the
ListView control, you can allow the user to edit the contents of the
ListView control. To edit the data in the
ListView control, you can use a standard text box. Occasionally, you may want another control to edit the control. This article describes how
to use a
ComboBox control to edit the data in a
ListView control when the
ListView control is in Details view.
When the user selects a row in the
ListView control, a calculation is performed to locate the bounding rectangle for
the first column of the row that the user clicked. That calculation considers that the column may not be visible or may not be fully visible when the user click the row and when the
ComboBox control is sized and is displayed appropriately.
In addition to
positioning and sizing the
ComboBox control, this sample application also watches for the following two messages on the
ListView control:
These messages occur whenever
the user scrolls through the
ListView control vertically or horizontally. Because the
ComboBox control is not physically part of the
ListView control, the
ComboBox control does not automatically scroll with the
ListView control. Therefore, whenever either one of these two messages occurs, the
ComboBox control must be hidden. To watch for these messages, you must create a custom
UserControl class that inherits from the
ListView class. In this custom control, the
WndProc method is overridden to allow all messages to be checked for
scrolling.
Note To override the
WndProc method, both your code and any code that calls it must have
unmanaged code permissions (
SecurityPermission with the
UnmanagedCode flag specified).
back to the
topCreate the inherited
ListView control
- Start Microsoft Visual Studio .NET 2003 or Microsoft Visual Studio 2005.
- On the File menu, point to
New, and then click Project.
- In the New Project dialog box, click
Visual C++ Projects under Project Types, and
then click Windows Control Library (.NET) under
Templates.
Note In Visual Studio 2005, click Visual C++ under Project Types, and then click Windows Forms Control Library under Templates. - In the Name box, type
MyListView. In the Location box, type
C:\Test, and then click OK.
- Replace all of the code in the UserControl class with the
following code:
#pragma once
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
namespace MyListView
{
/// <summary>
/// Summary for MyListViewControl
/// </summary>
///
/// WARNING: If you change the name of this class, you must change the
/// 'Resource File Name' property for the managed resource compiler tool
/// that is associated with all .resx files that this class depends on.
/// Otherwise, the designers cannot interact properly with localized
/// resources that are associated with this form.
public __gc class MyListViewControl : public System::Windows::Forms::ListView
{
public:
MyListViewControl(void)
{
InitializeComponent();
}
protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing);
}
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container* components;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
}
private:
static const int WM_HSCROLL = 0x114;
static const int WM_VSCROLL = 0x115;
protected:
void WndProc(Message *msg)
{
// Look for the WM_VSCROLL or the WM_HSCROLL messages.
if ((msg->Msg == WM_VSCROLL) || (msg->Msg == WM_HSCROLL))
{
// Move focus to the ListView control to cause the ComboBox control to lose focus.
this->Focus();
}
// Pass the message to default handler.
__super::WndProc(msg);
}
};
}
Note You must add the common language runtime support compiler option (/clr:oldSyntax) in Visual C++ 2005 to successfully compile the whole code sample.
To add the common language runtime support compiler option in Visual C++ 2005, follow these steps:
- Click Project, and then click <ProjectName> Properties.
Note <ProjectName> is a placeholder for the name of the project. - Expand Configuration Properties, and then click General.
- Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting in the right pane, click Apply, and then click OK.
For more information about the common language runtime support compiler option, visit the following Microsoft Web site: - Save and build the project.
back to the topCreate the sample application
- Follow these steps to create a new Windows Forms
Application in Microsoft Visual C++ .NET:
- On the File menu, point to
New, and then click Project.
- In the New Project dialog box, click
Visual C++ Projects under Project Types, and
then click Windows Forms Application (.NET) under
Templates.
Note In Visual Studio 2005, click Visual C++ under Project Types, and then click Windows Forms Application under Templates. - In the Name box, type
Q816188, and then click OK. By
default, a form that is named Form1 is created.
- Follow these steps to add the control that you created in
the "Create the inherited ListView
control" section of this article to your Windows application:
- On the Tools menu, click Add/Remove Toolbox
Items.
- In the Customize Toolbox dialog box,
click the .NET Framework Components tab, and then click
Browse.
- In the Open dialog box, locate the
control that you created in the "Create the
inherited ListView control" section, and then click
Open. This step adds this control to the Toolbox so that you
can use the control similarly to any other control.
- Add a MyListView control to
Form1.
- Add a ComboBox control to
Form1.
- In the Properties window of the ComboBox control,
set the value of the Name property to
cbListViewCombo, and then set the
Visible property to False.
- Add the following code to the class of Form1 above the
constructor:
private:
ListViewItem *lvItem;
- Add the following code to the Load event
of Form1:
// Add some items to the combo box list.
this->cbListViewCombo->Items->Add(S"NC");
this->cbListViewCombo->Items->Add(S"WA");
// Set the view of the ListView control to Details.
this->myListViewControl1->View = View::Details;
// Turn on full row select.
this->myListViewControl1->FullRowSelect = true;
// Add data to the ListView control.
ColumnHeader *columnheader;
ListViewItem *listviewitem;
// Create sample ListView data.
listviewitem = new ListViewItem(S"NC");
listviewitem->SubItems->Add(S"North Carolina");
this->myListViewControl1->Items->Add(listviewitem);
listviewitem = new ListViewItem(S"WA");
listviewitem->SubItems->Add(S"Washington");
this->myListViewControl1->Items->Add(listviewitem);
// Create column headers for the data.
columnheader = new ColumnHeader();
columnheader->Text = S"State Abbreviation";
this->myListViewControl1->Columns->Add(columnheader);
columnheader = new ColumnHeader();
columnheader->Text = S"State";
this->myListViewControl1->Columns->Add(columnheader);
// Loop through and size each column header to fit the column header text.
ColumnHeader *ch;
IEnumerator *ie = this->myListViewControl1->Columns->GetEnumerator();
while (ie->MoveNext())
{
ch = __try_cast<ColumnHeader *> (ie->Current);
ch->Width = -2;
}
- Add the following code to the
SelectedValueChanged event of the ComboBox control:
// Set the text of the ListView item to match the ComboBox control.
lvItem->Text = this->cbListViewCombo->Text;
// Hide the ComboBox control.
this->cbListViewCombo->Visible = false;
- Add the following code to the Leave event
of the ComboBox control:
// Set text of the ListView item to match the ComboBox control.
lvItem->Text = this->cbListViewCombo->Text;
// Hide the ComboBox control.
this->cbListViewCombo->Visible = false;
- Add the following code to the KeyPress
event of the ComboBox control:
// Verify that the user presses the ESC key.
switch (e->KeyChar)
{
case (char)(int)Keys::Escape:
{
// Reset the original text value, and then hide the ComboBox control.
this->cbListViewCombo->Text = lvItem->Text;
this->cbListViewCombo->Visible = false;
break;
}
case (char)(int)Keys::Enter:
{
// Hide the ComboBox control.
this->cbListViewCombo->Visible = false;
break;
}
}
- Add the following code to the MouseUp
event of the myListViewContro11 control:
// Get the item on the row that the user clicks.
lvItem = this->myListViewControl1->GetItemAt(e->get_X(), e->get_Y());
// Make sure that an item the user clicks.
if (lvItem != NULL)
{
// Get the bounds of the item that the user clicks.
Rectangle ClickedItem = lvItem->Bounds;
// Verify that the column is completely scrolled off to the left.
if ((ClickedItem.Left + this->myListViewControl1->Columns->get_Item(0)->Width) < 0)
{
// If the cell is out of view to the left, do nothing.
return;
}
// Verify that the column is partially scrolled off to the left.
else if (ClickedItem.Left < 0)
{
// Determine if the column extends beyond the right side of the ListView control.
if ((ClickedItem.Left + this->myListViewControl1->Columns->get_Item(0)->Width) > this->myListViewControl1->Width)
{
// Set the width of the column to match the width of the ListView control.
ClickedItem.Width = this->myListViewControl1->Width;
ClickedItem.X = 0;
}
else
{
// The right side of the cell is in view.
ClickedItem.Width = this->myListViewControl1->Columns->get_Item(0)->Width + ClickedItem.Left;
ClickedItem.X = 2;
}
}
else if (this->myListViewControl1->Columns->get_Item(0)->Width > this->myListViewControl1->Width)
{
ClickedItem.Width = this->myListViewControl1->Width;
}
else
{
ClickedItem.Width = this->myListViewControl1->Columns->get_Item(0)->Width;
ClickedItem.X = 2;
}
// Adjust the top to account for the location of the ListView control.
ClickedItem.Y += this->myListViewControl1->Top;
ClickedItem.X += this->myListViewControl1->Left;
// Assign calculated bounds to the ComboBox control.
this->cbListViewCombo->Bounds = ClickedItem;
// Set default text for the ComboBox control to match the item that the user clicks.
this->cbListViewCombo->Text = lvItem->Text;
// Display the ComboBox control, and then make sure that it is on top with focus.
this->cbListViewCombo->Visible = true;
this->cbListViewCombo->BringToFront();
this->cbListViewCombo->Focus();
}
back to the
topVerify that it works
- Save and then run the sample.
- Click a row in the ListView control.
Notice that a combo box appears over the location of the
first column of the current row. - To hide the combo box, click an item in the combo box,
press ESC, and then scroll through the ListView control or click another control.
Notice that the value that you
clicked in the combo box is placed in the first column of the clicked row of
the ListView control.
back to the
top