Рисование вне области столбца в заголовке столбца списка

StackOverflow https://stackoverflow.com/questions/1433292

Вопрос

Можно ли вывести владельца из заголовка столбца всего списка? (включая регион справа от заголовков столбцов)? ListView находится в подробном представлении.

Ответ здесь указывает, что оставшееся пространство может быть нарисовано вместе с последним заголовком столбца: http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.windowsforms/topic32927.aspx

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

Предлагаемое решение основано на рисовании вне пропущенных границ:

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

Свойство ClipBounds доступного экземпляра Graphics указывает несвязанную область (от больших отрицательных чисел до больших положительных). Но за пределами области верхнего колонтитула последнего столбца ничего не рисуется.

У кого-нибудь есть решение для этого?

Это было полезно?

Решение

Я удивлен ответом Джеффри Тана в этом посте. Его решение не может работать, так как код пытается нарисовать за пределами клиентской области управления заголовком. hDC , используемый в пользовательском чертеже (и, следовательно, в чертеже владельца), предназначен для клиентской области элемента управления и поэтому не может использоваться для рисования в не клиентской области. Область справа от самого правого столбца в элементе управления заголовком находится за пределами клиентской области. Поэтому вам нужно другое решение.

Возможные решения

<Ол>
  • Высокие технологии и частичная эффективность
  • Вы можете включить рисование за пределами клиентской области с помощью вызова GetDC () WinAPI:

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

    В вашем обработчике события рисования столбца вам понадобится что-то вроде этого:

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

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

    1. Низкотехнологичный, но уродливый
    2. Добавьте дополнительный пустой столбец в свой элемент управления, владелец нарисуйте его так, как вы хотите, сделайте его очень широким и отключите горизонтальную прокрутку (необязательно).

      Я знаю, что это ужасно, но вы ищете предложения :)

      1. Наиболее эффективный, но все же не идеальный
      2. Используйте ObjectListView . Эта обертка вокруг .NET ListView позволяет добавлять наложения в ваш список - наложение может рисовать в любом месте ListView, включая заголовок. [Объявление: я являюсь автором ObjectListView, но я все еще думаю, что это лучшее решение]

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

        Это дает это: альтернативный текст

        [Читая этот ответ, я думаю, что это пример излишней попытки :) Надеюсь, вы найдете здесь что-то полезное.]

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top