Question

Est-il possible de retirer par le propriétaire la totalité de la section d'en-tête de colonne d'une listview? (y compris la région à droite des en-têtes de colonne)? ListView est en mode Détails.

Ici, une réponse indique que l'espace restant peut être dessiné avec le dernier en-tête de colonne: http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.windowsforms/topic32927.aspx

Mais cela ne semble pas fonctionner du tout - rien n'est dessiné en dehors de la zone d'en-tête.

La solution proposée repose sur un dessin en dehors des limites passées:

if (e.ColumnIndex == 3) //last column index
{
    Rectangle rc = new Rectangle(e.Bounds.Right, //Right instead of Left - offsets the rectangle
            e.Bounds.Top, 
            e.Bounds.Width, 
            e.Bounds.Height);

    e.Graphics.FillRectangle(Brushes.Red, rc);
}

La propriété ClipBounds de l'instance Graphics disponible indique une zone non liée (allant de grands nombres négatifs à de grands positifs). Mais rien n'est dessiné en dehors de la zone d'en-tête de colonne de la dernière colonne.

Quelqu'un a-t-il une solution à cela?

Était-ce utile?

La solution

Je suis surpris par la réponse de Jeffery Tan dans cet article. Sa solution ne peut pas fonctionner, car le code tente de tirer en dehors de la zone cliente de contrôle d'en-tête. Le hDC utilisé dans le dessin personnalisé (et donc le dessin du propriétaire) est destiné à la zone client du contrôle et ne peut donc pas être utilisé pour peindre dans la zone non-client. La zone située à droite de la colonne la plus à droite d'un contrôle d'en-tête se trouve dans une zone non cliente. Vous avez donc besoin d’une solution différente.

Solutions possibles

  1. Salut tech et partiellement efficace

Vous pouvez activer le dessin en dehors de la zone client à l'aide de l'appel WinAPI GetDC () :

[System.Runtime.InteropServices.DllImport("user32")]
private static extern IntPtr GetDC(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("user32")]
private static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);

public static IntPtr GetHeaderControl(ListView list) {
    const int LVM_GETHEADER = 0x1000 + 31;
    return SendMessage(list.Handle, LVM_GETHEADER, 0, 0);
}

Dans votre gestionnaire d'événement de tirage de colonnes, vous aurez besoin de quelque chose comme ceci:

if (e.ColumnIndex == 3) //last column index
{
  ListView lv = e.Header.ListView;
  IntPtr headerControl = NativeMethods.GetHeaderControl(lv);
  IntPtr hdc = GetDC(headerControl);
  Graphics g = Graphics.FromHdc(hdc);

  // Do your extra drawing here
  Rectangle rc = new Rectangle(e.Bounds.Right, //Right instead of Left - offsets the rectangle
            e.Bounds.Top, 
            e.Bounds.Width, 
            e.Bounds.Height);

    e.Graphics.FillRectangle(Brushes.Red, rc);

  g.Dispose();
  ReleaseDC(headerControl, hdc);
}

Mais le problème est que, puisque votre dessin se trouve en dehors de la zone client, Windows ne sait pas toujours quand il doit être dessiné. Donc, il va parfois disparaître, puis être redessiné lorsque Windows pense que l'en-tête doit être repeint.

  1. Low tech mais laid

Ajoutez une colonne vide supplémentaire à votre contrôle, le propriétaire le dessinera comme vous le souhaitez, agrandissez-le et désactivez le défilement horizontal (facultatif).

Je sais que c'est horrible, mais vous cherchez des suggestions:)

  1. Plus efficace, mais toujours pas parfait

Utilisez ObjectListView . Ce wrapper autour d'un .NET ListView vous permet d'ajouter des superpositions à votre liste - une superposition peut dessiner n'importe où dans ListView, y compris l'en-tête. [Déclaration: je suis l'auteur de ObjectListView, mais je pense toujours que c'est la meilleure solution]

public class HeaderOverlay : AbstractOverlay
{
    public override void Draw(ObjectListView olv, Graphics g, Rectangle r) {
        if (olv.View != System.Windows.Forms.View.Details)
            return;

        Point sides = NativeMethods.GetColumnSides(olv, olv.Columns.Count-1);
        if (sides.X == -1)
            return;

        RectangleF headerBounds = new RectangleF(sides.Y, 0, r.Right - sides.Y, 20);
        g.FillRectangle(Brushes.Red, headerBounds);
        StringFormat sf = new StringFormat();
        sf.Alignment = StringAlignment.Center;
        sf.LineAlignment = StringAlignment.Center;
        g.DrawString("In non-client area!", new Font("Tahoma", 9), Brushes.Black, headerBounds, sf);
    }
}

Cela donne ceci: alt text

[En lisant cette réponse, je pense que c'est un exemple d'essayer trop fort :) J'espère que vous trouverez quelque chose d'utile ici.]

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top