Uso de un control ComboBox para editar datos en un control ListView en Visual CSharp

En este artículo se muestra cómo usar un control ComboBox para editar los datos de un control ListView. Este método reemplaza el enfoque del cuadro de texto estándar de editar los datos en un control ListView.

Versión original del producto: Visual C#
Número de KB original: 320344

Descripción de la técnica

Mediante el uso de la LabelEdit propiedad del control ListView, puede permitir que el usuario edite el contenido del control ListView. Para editar los datos en el control ListView, puede usar un cuadro de texto estándar. En ocasiones, resulta útil tener otro control para editar el control. En este artículo se simula cómo usar un control ComboBox para editar los datos de un Control ListView cuando ListView está en la vista Detalles.

Cuando el usuario selecciona una fila en ListView, se realiza un cálculo para localizar el rectángulo delimitador de la primera columna de la fila en la que se hace clic. Ese cálculo tiene en cuenta que es posible que la columna no esté visible o que no esté totalmente visible cuando se haga clic en la fila y cuando el ComboBox tenga el tamaño y se muestre correctamente.

Además de colocar y ajustar el tamaño del ComboBox, este ejemplo también busca dos mensajes en el control ListView: WM_VSCROLL y WM_HSCROLL. Estos mensajes se producen cada vez que el usuario se desplaza por el control ListView vertical u horizontalmente. Dado que ComboBox no forma parte físicamente del control ListView, el ComboBox no se desplaza automáticamente con ListView. Por lo tanto, cada vez que se produzca cualquiera de estos dos mensajes, el ComboBox debe estar oculto. Para watch para estos mensajes, cree una clase personalizada UserControl que herede de la clase ListView. En este control personalizado, el WndProc método se invalida para permitir que se compruebe el desplazamiento de todos los mensajes.

Creación del control ListView heredado

  1. Inicie Microsoft Visual Studio .NET.

  2. En el menú Archivo, elija Nuevo y, a continuación, haga clic en Proyecto.

  3. En el cuadro de diálogo Nuevo proyecto , haga clic en Proyectos de Visual C# en Tipos de proyectoy, a continuación, haga clic en Biblioteca de controles de Windows en Plantillas.

  4. Reemplace todo el código de la UserControl clase por el código siguiente:

    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Windows.Forms;
    
    namespace InheritedListView
    {
        /// <summary>
        /// Summary description for UserControl1.
        /// </summary>
        public class MyListView : System.Windows.Forms.ListView
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.Container components = null;
    
            public MyListView()
            {
                // This call is required by the Windows.Forms Form Designer.
                InitializeComponent();
                // TODO: Add any initialization after the InitForm call
            }
    
            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    if (components != null)
                        components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Component Designer generated code
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                components = new System.ComponentModel.Container();
            }
            #endregion
    
            private const int WM_HSCROLL = 0x114;
            private const int WM_VSCROLL = 0x115;
    
            protected override void WndProc(ref 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 to cause ComboBox to lose focus.
                    this.Focus();
                }
    
                // Pass message to default handler.
                base.WndProc(ref msg);
            }
        }
    }
    
  5. Guarde y genere el proyecto.

Creación de la aplicación de ejemplo

  1. Siga estos pasos para crear una nueva aplicación Windows en Visual C# .NET:

    1. En el menú Archivo, elija Nuevo y, a continuación, haga clic en Proyecto.
    2. En el cuadro de diálogo Nuevo proyecto , haga clic en Proyectos de Visual C# en Tipos de proyectoy, a continuación, haga clic en Aplicación de Windows en Plantillas. De forma predeterminada, se crea Form1.
  2. Siga estos pasos para agregar el control que creó en la sección Crear el control ListView heredado a la aplicación Windows:

    1. En el menú Herramientas , haga clic en Personalizar cuadro de herramientas.
    2. En la pestaña Componentes de .NET Framework , haga clic en Examinar.
    3. En el cuadro de diálogo Abrir , busque el control que creó en la sección Crear el control ListView heredado y, a continuación, haga clic en Abrir. Agrega este control al cuadro de herramientas para que pueda usar el control de forma similar a cualquier otro control.
    4. Arrastre MyListView desde la sección General del cuadro de herramientas a Form1.
  3. Arrastre un control ComboBox desde la sección Windows Forms del cuadro de herramientas a Form1.

  4. En la ventana Propiedades de ComboBox, cambie la propiedad Name a cbListViewCombo y, a continuación, establezca la propiedad Visible en False.

  5. Agregue el código siguiente a la clase de Form1 encima del constructor:

    private ListViewItem lvItem;
    
  6. Agregue el código siguiente al Load evento de Form1:

    // Add a few items to the combo box list.
    this.cbListViewCombo.Items.Add("NC");
    this.cbListViewCombo.Items.Add("WA");
    
    // Set view of ListView to Details.
    this.myListView1.View = View.Details;
    
    // Turn on full row select.
    this.myListView1.FullRowSelect = true;
    
    // Add data to the ListView.
    ColumnHeader columnheader;
    ListViewItem listviewitem;
    
    // Create sample ListView data.
    listviewitem = new ListViewItem("NC");
    listviewitem.SubItems.Add("North Carolina");
    this.myListView1.Items.Add(listviewitem);
    
    listviewitem = new ListViewItem("WA");
    listviewitem.SubItems.Add("Washington");
    this.myListView1.Items.Add(listviewitem);
    
    // Create column headers for the data.
    columnheader = new ColumnHeader();
    columnheader.Text = "State Abbr.";
    this.myListView1.Columns.Add(columnheader);
    
    columnheader = new ColumnHeader();
    columnheader.Text = "State";
    this.myListView1.Columns.Add(columnheader);
    
    // Loop through and size each column header to fit the column header text.
    foreach (ColumnHeader ch in this.myListView1.Columns)
    {
       ch.Width = -2;
    }
    
  7. Agregue el código siguiente al SelectedValueChanged evento de ComboBox:

    // Set text of ListView item to match the ComboBox.
    lvItem.Text = this.cbListViewCombo.Text;
    
    // Hide the ComboBox.
    this.cbListViewCombo.Visible = false;
    
  8. Agregue el código siguiente al Leave evento de ComboBox:

    // Set text of ListView item to match the ComboBox.
    lvItem.Text = this.cbListViewCombo.Text;
    
    // Hide the ComboBox.
    this.cbListViewCombo.Visible = false;
    
  9. Agregue el código siguiente al KeyPress evento de ComboBox:

    // Verify that the user presses ESC.
    switch (e.KeyChar)
    {
       case (char)(int)Keys.Escape:
       {
          // Reset the original text value, and then hide the ComboBox.
          this.cbListViewCombo.Text = lvItem.Text;
          this.cbListViewCombo.Visible = false;
          break;
       }
    
       case (char)(int)Keys.Enter:
       {
          // Hide the ComboBox.
          this.cbListViewCombo.Visible = false;
          break;
       }
    }
    
  10. Agregue el código siguiente al MouseUp evento de myListView1:

    // Get the item on the row that is clicked.
    lvItem = this.myListView1.GetItemAt(e.X, e.Y);
    
    // Make sure that an item is clicked.
    if (lvItem != null)
    {
        // Get the bounds of the item that is clicked.
        Rectangle ClickedItem = lvItem.Bounds;
    
        // Verify that the column is completely scrolled off to the left.
        if ((ClickedItem.Left + this.myListView1.Columns[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 column extends beyond right side of ListView.
            if ((ClickedItem.Left + this.myListView1.Columns[0].Width) > this.myListView1.Width)
            {
                // Set width of column to match width of ListView.
                ClickedItem.Width = this.myListView1.Width;
                ClickedItem.X = 0;
            }
            else
            {
                // Right side of cell is in view.
                ClickedItem.Width = this.myListView1.Columns[0].Width + ClickedItem.Left;
                ClickedItem.X = 2;
            }
        }
        else if (this.myListView1.Columns[0].Width > this.myListView1.Width)
        {
            ClickedItem.Width = this.myListView1.Width;
        }
        else
        {
            ClickedItem.Width = this.myListView1.Columns[0].Width;
            ClickedItem.X = 2;
        }
    
        // Adjust the top to account for the location of the ListView.
        ClickedItem.Y += this.myListView1.Top;
        ClickedItem.X += this.myListView1.Left;
    
        // Assign calculated bounds to the ComboBox.
        this.cbListViewCombo.Bounds = ClickedItem;
    
        // Set default text for ComboBox to match the item that is clicked.
        this.cbListViewCombo.Text = lvItem.Text;
    
        // Display the ComboBox, and make sure that it is on top with focus.
        this.cbListViewCombo.Visible = true;
        this.cbListViewCombo.BringToFront();
        this.cbListViewCombo.Focus();
    }
    

Comprobar que funciona

  1. Guarde y ejecute el ejemplo.

  2. Haga clic en una fila en ListView.

    Nota:

    Aparece un cuadro combinado sobre la ubicación de la primera columna de la fila actual.

  3. Para ocultar el cuadro combinado, haga clic en un elemento del cuadro combinado, presione ESC y, a continuación, desplácese por ListView o haga clic en otro control.

    Nota:

    El valor en el que hizo clic en el cuadro combinado se coloca en la primera columna de la fila en la que se ha hecho clic en ListView.