2011-07-03 34 views
14

Quiero cambiar la altura del artículo/fila en la vista de lista.C# Change ListView Item/Row's height

Busqué en todas partes y pensé que para cambiar la altura necesito usar LBS_OWNERDRAWFIXED o MeasureItem o algo así. El problema es que no sé exactamente qué hacer y cómo usarlo.
¿Alguien me puede ayudar con eso?

Editar:
no puedo utilizar el hack ImageList porque yo estoy usando el SmallImageList de verdad y necesito diferente altura de la línea del tamaño de las imágenes ImageList.

Gracias!

+0

Consulte http://stackoverflow.com/questions/1244090/how-to-set-wpf-listview-row-height. Solución simple. –

+0

La "solución simple" mencionada es para WPF, que de hecho es simple. Esta pregunta se refiere a WinForms, donde se decide que no es simple. – Grammarian

Respuesta

11

Se puede hacer usando el truco SmallImageList - sólo hay que tener cuidado. ObjectListView - un contenedor de código abierto alrededor de un estándar .NET ListView - usa ese truco para implementar con éxito una propiedad RowHeight.

Si desea 32 píxeles para cada fila, asigne un ImageList que sea 16x32 (ancho x alto), y luego coloque cada una de sus imágenes en el medio vertical de la altura de 32 píxeles.

Esta captura de pantalla muestra las filas de píxeles 32 y el ajuste de texto que es posible debido al espacio extra:

enter image description here

ObjectListView hace todo este trabajo para usted. De hecho, si está intentando hacer algo con un ListView, debería considerar seriamente usar un ObjectListView. Hace que muchas cosas difíciles (por ejemplo, ordenar por tipo de columna, información sobre herramientas personalizadas) sean triviales, y es posible que existan varias cosas imposibles (por ejemplo, superposiciones, grupos en listas virtuales).

+1

Bueno, solo quería cambiar el tamaño de la fila y 300kb porque eso es demasiado para el programa que planeo. de todos modos, esa es una buena solución en general. – Ron

+2

Creo que sugirió una solución tan compleja –

13

Tienes que usar un truco. El truco es usar una lista de imágenes en la propiedad StateImageList. ListView ajustará la altura de su artículo, en función de la altura de la propiedad ImageStyle ImageList. No es necesario que especifique una imagen para sus elementos, pero el uso de StateImageList obligará a ListView a ajustarse. En el ejemplo siguiente, establecí el tamaño de la lista de imágenes en 32x32, lo que dio como resultado una altura de 32 píxeles ListViewItem (s).

enter image description here

+1

Se me olvidó decir que estoy usando ImageList en el proyecto SmallImageList, así que no puedo usar ese truco. – Ron

+0

Luego tendrá que escribir su propio control, ya que por experiencia e investigación, esto no será posible con el ListView de WinForms existente. Esta también fue la misma respuesta de un desarrollador de soporte comunitario de MSFT que también investigó el problema para algunas personas y terminó sugiriendo escribir un control personalizado. –

+0

He probado esto en modo detalle. Este truco solo funciona para AUMENTAR la altura de la fila sobre la altura predeterminada. No puede hacer las filas más ajustadas de lo que define Windows. Tenga en cuenta que la altura de una fila de vista de lista depende del sistema operativo. Por ejemplo, en Windows 7, las filas son significativamente más altas que en XP. Lamentablemente, este truco no es útil para mí. – Elmue

1

La altura de línea predeterminada de un ListView (en modo de vista de informe) se calcula en función del tamaño de fuente del control.

Para seleccionar la altura de la línea, elija una fuente con la altura correcta en las propiedades de ListView. Por ejemplo, seleccione MS Sans Serif 18.

Luego puede cambiar la fuente utilizada por todos los elementos: cuando inserta un nuevo elemento, establezca su propiedad de fuente.

Para optimizar la asignación de fuente que debe declarar la fuente elemento como un miembro privado de la forma:

Private Font stdfont = new Font("Consolas", 9.0f, FontStyle.Regular); 

A continuación, al agregar elementos:

ListViewItem i = new ListViewItem("some text"); 
i.Font = stdfont; 
MyListView.Items.Add(i); 

este truco es el único sencillo que permite tener una altura de línea más pequeña;) iE establecer el tamaño de fuente del mando a 7 y establece el tamaño de fuente artículos a 10. (Probado con VS 2008)

11

Para las personas que aún están strugling con esto, aquí está el código que utilizo:

private void SetHeight(ListView listView, int height) 
{ 
    ImageList imgList = new ImageList(); 
    imgList.ImageSize = new Size(1, height); 
    listView.SmallImageList = imgList; 
} 

para utilizar este acaba de hacer:

SetHeight(lvConnections, 25); 
+0

He probado esto en modo de detalle. Este truco solo funciona para AUMENTAR la altura de la fila sobre la altura predeterminada. No puede hacer las filas más ajustadas de lo que define Windows. Tenga en cuenta que la altura de una fila de vista de lista depende del sistema operativo. Por ejemplo, en Windows 7, las filas son significativamente más altas que en XP. Lamentablemente, este truco no es útil para mí. – Elmue

0

Plasmabubble tiene la idea correcta. Esto se amplía y es lo que uso para usar un ancho de línea estrecho para los artículos.

El trazado de líneas en un ListView depende de la fuente de ListView y no puede modificarse. Sin embargo, puede establecer la fuente de los elementos en el ListView a algo más grande que la fuente de ListView.

Si desea que sea proporcional, cree una fuente en función de la fuente del elemento. Quiero que la altura del artículo sea el 90% de lo normal, cualquiera que sea la fuente elegida.

Cuando llené la lista utilicé una fuente almacenada en la configuración pero también podría usar una fuente literal como "Consolas".

lvResults.Font = 
    new Font(Properties.Settings.Default.usrHookFont.FontFamily, 
     (float)(Properties.Settings.Default.usrHookFont.Size * .9)); 

foreach (HookSet item in resultSet) 
    { 
     ListViewItem lvi = new ListViewItem(); 
     lvi.Font = Properties.Settings.Default.usrHookFont; 
     <dot><dot><dot> 
} 
0

Lamentablemente nadie respondió a su pregunta original de cómo utilizar LBS_OWNERDRAWFIXED en todos estos años.

La respuesta que ha aceptado es la integración de un gran proyecto (con demos y documentación de 3,3MB). Pero solo para configurar la altura de la línea de un ListView esto está sobrerrellenado.

La otra solución sugerida aquí (agregar una ImageList) solo funciona en aumentar la altura de la fila. Pero no permite establecer realmente el RowHeight independiente de la altura de la imagen. Además, la altura de fila predeterminada depende del sistema operativo. Por ejemplo, en Windows 7 las filas son mucho más altas que en XP. No puedes elegir hacerlos más estrictos, solo que más altos.

Pero con muy pocas líneas puede hacer lo que quiera. Simplemente copia y pega el siguiente clase:

using System; 
using System.Drawing; 
using System.Diagnostics; 
using System.ComponentModel; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 

namespace ExtendedControls 
{ 

public class ListViewEx : ListView 
{ 
    #region Windows API 

    /* 
    struct MEASUREITEMSTRUCT 
    { 
     public int CtlType;  // Offset = 0 
     public int CtlID;  // Offset = 1 
     public int itemID;  // Offset = 2 
     public int itemWidth; // Offset = 3 
     public int itemHeight; // Offset = 4 
     public IntPtr itemData; 
    } 
    */ 

    [StructLayout(LayoutKind.Sequential)] 
    struct DRAWITEMSTRUCT 
    { 
     public int ctlType; 
     public int ctlID; 
     public int itemID; 
     public int itemAction; 
     public int itemState; 
     public IntPtr hWndItem; 
     public IntPtr hDC; 
     public int rcLeft; 
     public int rcTop; 
     public int rcRight; 
     public int rcBottom; 
     public IntPtr itemData; 
    } 

    // LVS_OWNERDRAWFIXED: The owner window can paint ListView items in report view. 
    // The ListView control sends a WM_DRAWITEM message to paint each item. It does not send separate messages for each subitem. 
    const int LVS_OWNERDRAWFIXED = 0x0400; 
    const int WM_SHOWWINDOW  = 0x0018; 
    const int WM_DRAWITEM  = 0x002B; 
    const int WM_MEASUREITEM  = 0x002C; 
    const int WM_REFLECT   = 0x2000; 

    #endregion 

    bool mb_Measured = false; 
    int ms32_RowHeight = 14; 

    /// <summary> 
    /// Constructor 
    /// </summary> 
    public ListViewEx() 
    { 
     SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); 
    } 

    /// <summary> 
    /// Sets the row height in Details view 
    /// This property appears in the Visual Studio Form Designer 
    /// </summary> 
    [Category("Appearance")] 
    [Description("Sets the height of the ListView rows in Details view in pixels.")] 
    public int RowHeight 
    { 
     get { return ms32_RowHeight; } 
     set 
     { 
      if (!DesignMode) Debug.Assert(mb_Measured == false, "RowHeight must be set before ListViewEx is created."); 
      ms32_RowHeight = value; 
     } 
    } 

    protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams k_Params = base.CreateParams; 
      k_Params.Style |= LVS_OWNERDRAWFIXED; 
      return k_Params; 
     } 
    } 

    /// <summary> 
    /// The messages WM_MEASUREITEM and WM_DRAWITEM are sent to the parent control rather than to the ListView itself. 
    /// They come here as WM_REFLECT + WM_MEASUREITEM and WM_REFLECT + WM_DRAWITEM 
    /// They are sent from Control.WmOwnerDraw() --> Control.ReflectMessageInternal() 
    /// </summary> 
    protected override void WndProc(ref Message k_Msg) 
    { 
     base.WndProc(ref k_Msg); // FIRST 

     switch (k_Msg.Msg) 
     { 
      case WM_SHOWWINDOW: // called when the ListView becomes visible 
      { 
       Debug.Assert(View == View.Details, "ListViewEx supports only Details view"); 
       Debug.Assert(OwnerDraw == false, "In ListViewEx do not set OwnerDraw = true"); 
       break; 
      } 
      case WM_REFLECT + WM_MEASUREITEM: // called once when the ListView is created, but only in Details view 
      { 
       mb_Measured = true; 

       // Overwrite itemHeight, which is the fifth integer in MEASUREITEMSTRUCT 
       Marshal.WriteInt32(k_Msg.LParam + 4 * sizeof(int), ms32_RowHeight); 
       k_Msg.Result = (IntPtr)1; 
       break; 
      } 
      case WM_REFLECT + WM_DRAWITEM: // called for each ListViewItem to be drawn 
      { 
       DRAWITEMSTRUCT k_Draw = (DRAWITEMSTRUCT) k_Msg.GetLParam(typeof(DRAWITEMSTRUCT)); 
       using (Graphics i_Graph = Graphics.FromHdc(k_Draw.hDC)) 
       { 
        ListViewItem i_Item = Items[k_Draw.itemID]; 

        Color c_BackColor = i_Item.BackColor; 
        if (i_Item.Selected) c_BackColor = SystemColors.Highlight; 
        if (!Enabled)  c_BackColor = SystemColors.Control; 

        using (SolidBrush i_BackBrush = new SolidBrush(c_BackColor)) 
        { 
         // Erase the background of the entire row 
         i_Graph.FillRectangle(i_BackBrush, i_Item.Bounds); 
        } 

        for (int S=0; S<i_Item.SubItems.Count; S++) 
        { 
         ListViewItem.ListViewSubItem i_SubItem = i_Item.SubItems[S]; 

         // i_Item.SubItems[0].Bounds contains the entire row, rather than the first column only. 
         Rectangle k_Bounds = (S>0) ? i_SubItem.Bounds : i_Item.GetBounds(ItemBoundsPortion.Label); 

         // You can use i_Item.ForeColor instead of i_SubItem.ForeColor to get the same behaviour as without OwnerDraw 
         Color c_ForeColor = i_SubItem.ForeColor; 
         if (i_Item.Selected) c_ForeColor = SystemColors.HighlightText; 
         if (!Enabled)  c_ForeColor = SystemColors.ControlText; 

         TextFormatFlags e_Flags = TextFormatFlags.NoPrefix | TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine; 
         switch (Columns[S].TextAlign) 
         { 
          case HorizontalAlignment.Center: e_Flags |= TextFormatFlags.HorizontalCenter; break; 
          case HorizontalAlignment.Right: e_Flags |= TextFormatFlags.Right; break; 
         } 

         TextRenderer.DrawText(i_Graph, i_SubItem.Text, i_SubItem.Font, k_Bounds, c_ForeColor, e_Flags); 
        } 
       } 
       break; 
      } 
     } 
    } 
} // class 
} // namespace 

Después de la adición de un ListViewEx a su Formulario verá una nueva propiedad en el estudio de las formas diseñador visual que permite ajustar la altura de la fila en píxeles:

Setting RowHeight in a C# ListView

El valor que introduzca allí será el alto de la fila en píxeles y se respetará casi en todos los sistemas operativos.Lo he comprobado en Windows XP, 7 y 10:

ListViewEx.RowHeight sample

Además mi clase tiene dos ventajas más sobre el ListView originales: Se basa sin parpadeos y respeta la ForeColor y Fuente establecido en ListViewSubItem que es ignorado por el Microsoft ListView original. Entonces puedes dibujar cada celda con un color y fuente diferente.

IMPORTANTE: A medida que el MSDN dice LBS_OWNERDRAWFIXED ha sido diseñado solamente para la vista Detalles (Ver informe). Mi código funciona solo para este modo y esto es porque Microsoft lo ha diseñado así.

Además tenga en cuenta que la configuración ListView.OwnerDraw = true es algo completamente diferente que usar LVS_OWNERDRAWFIXED.

No implementé el dibujo íconos, porque no lo necesito. Pero puedes agregar esto fácilmente.

+0

La anulación de CreateParams hace que el texto del subitem no se muestre ... – user1932634

+0

No tengo ni idea de lo que está hablando. Uso este código en mi aplicación. ¡Funciona perfectamente! En las capturas de pantalla de arriba, verá que todos los subelementos se dibujan correctamente, incluso en color. – Elmue