Рисование в виде списка отключает перерисовку элементов списка

Asked
Viewd2905

0

В чем причина этого?

Я переопределяю OnPaintBackground и рисую строку.Он не отображается, пока я не вызову это в конструкторе:

 this.SetStyle ( ControlStyles.UserPaint, true );
 

Но тогда я не вижу элементов в списке.

Почему и как это решить?

ИЗМЕНИТЬ: код

     protected override void OnPaintBackground ( PaintEventArgs pevent )
    {
        base.OnPaintBackground ( pevent );

        // Create string to draw.
        String drawString = "76";

        // Create font and brush.
        Font drawFont = new Font ( "Arial", 36 );
        SolidBrush drawBrush = new SolidBrush ( Color.Blue );

        // Create point for upper-left corner of drawing.
        PointF drawPoint = new PointF ( 150.0F, 150.0F );

        // Draw string to screen.
        pevent.Graphics.DrawString ( drawString, drawFont, drawBrush, drawPoint );

        //pevent.Graphics.FillRectangle ( drawBrush, this.ClientRectangle );
    }`enter code here`
 
  • Вы вызываете base.OnPaintBackground ()?Можете ли вы опубликовать код своего переопределения?

    Chris Porter25 октября 2009, 14:39
  • Каковы значения следующих свойств и стилей?

    • ControlStyles.DoubleBuffer
    • ControlStyles.AllPaintingInWmPaint
    • ListView.OwnerDraw
    Sheng Jiang 蒋晟25 октября 2009, 14:57
  • @Sheng, больше ничего.Я только что добавил UserPaint, и все.

    Joan Venge25 октября 2009, 17:30

1 ответов

5

Как я уже говорил в прошлой беседе по этой теме, OnPaint() и UserPaint не работают со ListView. Картина обрабатывается нижележащим элементом управления и не может быть перехвачена таким образом. Это отличается от других элементов управления

Таким образом, когда ControlStyles.UserPaint равно true, базовый элемент управления не получает указание перерисовывать себя. Вместо этого весь рисунок направляется к методам OnPaintBackground() и OnPaint(), которые, как вы обнаружили, ничего не делают.

Есть два способа сделать то, о чем вы просили (второй лучше первого):

Первый способ: перехватить WM_PAINT, выполнить базовую обработку, а затем нарисовать в списке. Примерно так:

 public class MyListView : ListView
{
    protected override void WndProc(ref Message m) {
        switch (m.Msg) {
            case 0x0F: // WM_PAINT
                this.HandlePaint(ref m);
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }

    protected virtual void HandlePaint(ref Message m) {
        base.WndProc(ref m);

        using (Graphics g = this.CreateGraphics()) {
            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
            sf.Trimming = StringTrimming.EllipsisCharacter;
            g.DrawString("Some text", new Font("Tahoma", 13),
                SystemBrushes.ControlDark, this.ClientRectangle, sf);
        }
    }
}
 

Но это создает проблемы с перерисовкой, когда то, что вы рисуете, находится за пределами области, которая, по мнению списка, содержит содержимое элемента управления - это не вызывает событий рисования.

Второй способ: перехватить уведомление CustomDraw (это не то же самое, что и OwnerDraw) и прослушать этап CDDS_POSTPAINT. На этом этапе вы можете спокойно рисовать в виде списка. Вы можете посмотреть код ObjectListView , чтобы увидеть, как это делается.

Вы также можете избавить себя от лишних хлопот и напрямую использовать ObjectListView :)

  • Кстати, я только что переключился на ваш список, и это здорово.Но столкнулся с исключением приведения типов для тестирования нажатия мыши, хотя я не использую эти события в коде.

    Joan Venge25 октября 2009, 17:58
  • Спасибо, грамматик, я переключусь на ваш список.

    Joan Venge25 октября 2009, 17:50