web-dev-qa-db-fra.com

C # Change ListView Item/Row height

Je veux changer la hauteur de Item/Row dans listview.

J'ai cherché partout et j'ai pensé que pour changer la hauteur, je devais utiliser LBS_OWNERDRAWFIXED ou MeasureItem ou quelque chose du genre.

Le problème est que je ne sais pas exactement quoi faire et comment l'utiliser.
Est-ce que quelqu'un peut m'aider?

Modifier:
Je ne peux pas utiliser le hack ImageList parce que j'utilise SmallImageList pour de vrai et j'ai besoin d'une hauteur de trait différente de celle des images ImageList.

Merci!

17
Ron

Cela peut être fait en utilisant l'astuce SmallImageList - vous devez juste faire attention. ObjectListView - un wrapper open source autour d'un .NET ListView standard - utilise cette astuce pour implémenter avec succès une propriété RowHeight.

Si vous souhaitez 32 pixels pour chaque ligne, affectez une ImageList de 16 x 32 (largeur x hauteur), puis positionnez chacune de vos images au centre vertical de la hauteur de 32 pixels.

Cette capture d'écran montre les lignes de 32 pixels et le retour à la ligne possible grâce à l'espace supplémentaire:

enter image description here

ObjectListView fait tout ce travail pour vous. En fait, si vous essayez de faire quoi que ce soit avec un ListView, vous devriez sérieusement envisager d'utiliser un ObjectListView à la place. Cela rend de nombreuses choses difficiles (par exemple, le tri par type de colonne, des info-bulles personnalisées) triviales et plusieurs choses impossibles (par exemple, les superpositions, les groupes sur des listes virtuelles).

13
Grammarian

Pour les personnes qui luttent encore avec cela, voici le code que j'utilise:

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

Pour l'utiliser, il suffit de faire:

SetHeight(lvConnections, 25);
20
Maarten Peels

Vous devez utiliser un peu de bidouille. L'astuce consiste à utiliser une liste d'images dans la propriété StateImageList. ListView ajustera la hauteur de son élément en fonction de la hauteur de la propriété ImageSize du ImageList. Il n'est pas nécessaire de spécifier une image pour vos éléments, mais l'utilisation de StateImageList oblige ListView à s'ajuster. Dans l'exemple ci-dessous, j'avais défini la taille de la liste d'images sur 32x32, ce qui donnait un ListViewItem d'une hauteur de 32px.

enter image description here

15
David Anderson

Malheureusement, personne n'a répondu à votre question initiale: comment utiliser LBS_OWNERDRAWFIXED pendant toutes ces années.

La réponse que vous avez acceptée est l’intégration d’un énorme projet (avec démos et documentation 3,3MB). Mais juste pour définir la hauteur de ligne d'un ListView, cela est trop volumineux.

L’autre solution de contournement suggérée ici (ajouter une ImageList) ne fonctionne que pour augmenter la hauteur de la ligne. Mais cela ne permet pas de définir réellement le RowHeight indépendamment de la hauteur de l'image. De plus, la hauteur de ligne par défaut dépend du système d'exploitation. Par exemple, sous Windows 7, les lignes sont beaucoup plus hautes que sous XP. Vous ne pouvez pas choisir de les resserrer, mais seulement plus haut.

Mais avec très peu de lignes, vous pouvez faire ce que vous voulez ... Il vous suffit de copier et coller la classe suivante:

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

Après avoir ajouté un ListViewEx à votre formulaire, vous verrez une nouvelle propriété dans le concepteur de formulaires Visual Studio qui permet de définir la hauteur de la ligne en pixels:

 Setting RowHeight in a C# ListView

La valeur que vous entrez ici correspondra à la hauteur de la ligne en pixels et sera respectée scrupuleusement sur tous les systèmes d'exploitation. Je l'ai testé sous Windows XP, 7 et 10:

 ListViewEx.RowHeight sample

De plus, ma classe a deux autres avantages par rapport à ListView d'origine: elle dessine sans scintillement et respecte les règles ForeColor et Font définies dans ListViewSubItem qui sont ignorées par Microsoft ListView d'origine. Ainsi, vous pouvez dessiner chaque cellule avec une couleur et une police différentes.

IMPORTANT: Comme le dit le MSDN, LBS_OWNERDRAWFIXED a été conçu uniquement pour la vue Détails (vue Rapport). Mon code ne fonctionne que pour ce mode et c'est parce que Microsoft l'a conçu comme ça.

De plus, veuillez noter que le réglage de ListView.OwnerDraw = true est complètement différent de celui utilisé avec LVS_OWNERDRAWFIXED.

Je n'ai pas implémenté dessin icons, car je n'en ai pas besoin. Mais vous pouvez facilement ajouter ceci.

4
Elmue

La hauteur de ligne par défaut d'un ListView (en mode d'affichage de rapport) est calculée en fonction de la taille de la police du contrôle.

Par conséquent, pour sélectionner la hauteur de ligne, choisissez une police de la bonne hauteur dans les propriétés ListView ..__ Par exemple, sélectionnez MS Sans Serif 18.

Vous pouvez ensuite modifier la police utilisée par tous les éléments: Lorsque vous insérez un nouvel élément, définissez sa propriété de police.

Pour optimiser l’affectation des polices, vous devez déclarer la police de l’élément en tant que membre privé du formulaire:

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

Ensuite, lors de l'ajout d'éléments:

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

Cette astuce est la seule solution facile permettant d’obtenir une hauteur de trait plus petite;) I.E. définissez la taille de police du contrôle sur 7 et définissez la taille de police des éléments sur 10 . (testé avec VS 2008)

3
Plasmabubble

Plasmabubble a la bonne idée. Ceci s’étend à cela et c’est ce que j’utilise pour utiliser une largeur de trait étroite pour les éléments.

L'espacement des lignes dans un ListView dépend de la police de ce dernier et ne peut pas être modifié. Toutefois, vous pouvez définir la police des éléments du ListView sur une taille supérieure à celle de la police ListView.

Si vous voulez qu'il soit proportionnel, créez une police basée sur la police de l'élément .. Je veux que la hauteur de l'élément soit égale à 90% de la normale, quelle que soit la police choisie.

Lorsque je remplis la liste, j'ai utilisé une police stockée dans les paramètres, mais vous pouvez également utiliser une police littérale telle que "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>
}
1
Dana Bell