Pregunta

¿Es posible dibujar el propietario de la sección de encabezado de columna completa de una vista de lista? (incluida la región a la derecha de los encabezados de columna)? ListView está en Vista de detalles.

Una respuesta aquí indica que el espacio restante se puede dibujar junto con el último encabezado de columna: http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.windowsforms/topic32927.aspx

Pero no parece funcionar en absoluto: no se dibuja nada fuera del área del encabezado.

La solución propuesta se basa en dibujar fuera de los límites aprobados:

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 propiedad ClipBounds de la instancia de Graphics disponible indica un área independiente (desde números negativos grandes hasta positivos grandes). Pero no se dibuja nada fuera del área del encabezado de columna de la última columna.

¿Alguien tiene una solución para esto?

¿Fue útil?

Solución

Estoy sorprendido por la respuesta de Jeffery Tan en esa publicación. Su solución no puede funcionar, ya que el código intenta dibujar fuera del área del cliente de control de encabezado. El hDC utilizado en el dibujo personalizado (y, por lo tanto, en el dibujo del propietario) es para el área del cliente del control y, por lo tanto, no puede usarse para pintar en el área que no es del cliente. El área a la derecha de la columna más a la derecha en un control de encabezado está en el área que no es de cliente. Entonces necesita una solución diferente.

Soluciones posibles

  1. Hi tech y parcialmente efectivo

Puede habilitar el dibujo fuera del área del cliente utilizando la llamada Wincode de 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);
}

En su controlador de eventos de sorteo de columnas, necesitará algo como esto:

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);
}

Pero el problema con esto es que, dado que su dibujo está fuera del área del cliente, Windows no siempre sabe cuándo debe dibujarse. Por lo tanto, desaparecerá a veces y luego se volverá a dibujar cuando Windows piense que el encabezado necesita volver a pintarse.

  1. Baja tecnología pero fea

Agregue una columna vacía adicional a su control, el propietario dibuje la apariencia que desee, amplíela y desactive el desplazamiento horizontal (opcional).

Sé que esto es horrible, pero estás buscando sugerencias :)

  1. Más efectivo, pero aún no perfecto

Utilice ObjectListView . Este contenedor alrededor de un .View ListView le permite agregar superposiciones a su lista; una superposición puede dibujar en cualquier lugar dentro de ListView, incluido el encabezado. [Declaración: soy el autor de ObjectListView, pero sigo pensando que es la mejor solución]

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);
    }
}

Esto da esto: texto alternativo ??

[Leyendo esta respuesta, creo que este es un ejemplo de esforzarse demasiado :) Espero que encuentres algo útil aquí.]

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top