Winforms ListView Выбор чертежа? - PullRequest
0 голосов
/ 04 августа 2009

Возможно ли переопределить отображение списка с выделенным цветом? Тот, который выглядит полупрозрачным синим цветом поверх элементов, как в окнах проводника.

Я хочу нарисовать контур вокруг выделения, чтобы указать выделение.

Есть ли способ сделать это? Примеры приветствуются.

Ответы [ 3 ]

3 голосов
/ 05 августа 2009

.NET ListView поддерживает рисование владельца гораздо более непосредственно, чем предлагают другие ответы. Вам даже не нужно создавать подклассы. Установите для OwnerDraw значение true, прослушивайте событие DrawSubItem, а затем в этом случае вы можете нарисовать то, что вам нравится.

Как всегда, ObjectListView облегчает этот процесс. эта страница документирует, как это сделать. Вы можете создавать такие вещи, если вы чувствуете себя обидными для своих пользователей: alt text

ОДНАКО, ни один из этих методов не сработает, если вы хотите нарисовать что-то за пределами самой ячейки. Таким образом, если вы надеялись нарисовать контур выделения вокруг всей строки, которая перекрывала предыдущие и последующие строки, вы не сможете сделать это с помощью чертежа владельца. Каждая ячейка рисуется индивидуально и «владеет» своей частью экрана, уничтожая все, что там уже было.

Чтобы сделать что-то, о чем вы просите, вам нужно перехватить этап посткраски пользовательского рисования (не рисование владельца. Майкл Данн написал отличное введение в пользовательский рисунок для CodeProject). Вы можете прочитать, что требуется здесь .

Мне неприятно это говорить, но самый простой ответ - использовать ObjectListView, создать украшение и установить его:

public void InitializeSelectionOverlay()
{
    this.olv1.HighlightForegroundColor = Color.Black;
    this.olv1.HighlightBackgroundColor = Color.White;
    this.olv1.AddDecoration(new SelectedRowDecoration());
}

public class SelectedRowDecoration : IOverlay
{
    public void Draw(ObjectListView olv, Graphics g, Rectangle r) {
        if (olv.SelectedIndices.Count != 1)
            return;

        Rectangle rowBounds = olv.GetItem(olv.SelectedIndices[0]).Bounds;
        rowBounds.Inflate(0, 2);
        GraphicsPath path = this.GetRoundedRect(rowBounds, 15);
        g.DrawPath(new Pen(Color.Red, 2.0f), path);
    }

    private GraphicsPath GetRoundedRect(RectangleF rect, float diameter) {
        GraphicsPath path = new GraphicsPath();

        RectangleF arc = new RectangleF(rect.X, rect.Y, diameter, diameter);
        path.AddArc(arc, 180, 90);
        arc.X = rect.Right - diameter;
        path.AddArc(arc, 270, 90);
        arc.Y = rect.Bottom - diameter;
        path.AddArc(arc, 0, 90);
        arc.X = rect.Left;
        path.AddArc(arc, 90, 90);
        path.CloseFigure();

        return path;
    }
}

Это дает что-то похожее на это: alt text

1 голос
/ 04 августа 2009

Вот быстрый рабочий пример, с которым я возился.

Первый помощник строит и перечисляет.

  [StructLayout(LayoutKind.Sequential)]
    public struct DRAWITEMSTRUCT
    {
        public int CtlType;
        public int CtlID;
        public int itemID;
        public int itemAction;
        public int itemState;
        public IntPtr hwndItem;
        public IntPtr hDC;
        public RECT rcItem;
        public IntPtr itemData;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
        public int Width
        {
            get { return right - left; }
        }
        public int Height
        {
            get { return bottom - top; }
        }
    }

    public enum ListViewDefaults
    {
        LVS_OWNERDRAWFIXED = 0x0400
    }

    public enum WMDefaults
    {
        WM_DRAWITEM = 0x002B,
        WM_REFLECT = 0x2000
    }

Теперь создайте собственный ListView и переопределите CreateParams и WndProc

public class CustomListView : ListView
    {
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                //add OwnerDraw style...i took this idea from Reflecting against ListView
                // bit OR is very important, otherwise you'll get an exception
                cp.Style |= (int)ListViewDefaults.LVS_OWNERDRAWFIXED; 

                return cp;
            }
        }

        protected override void WndProc(ref Message m)
        {

            base.WndProc(ref m);

            //if we are drawing an item then call our custom Draw.
            if (m.Msg == (int)(WMDefaults.WM_REFLECT | WMDefaults.WM_DRAWITEM))
                   ProcessDrawItem(ref m);
        }

Теперь для самой важной части .. рисунок. Я довольно любитель рисования, но это должно дать вам представление о том, что делать.

 private void ProcessDrawItem(ref Message m)
        {
            DRAWITEMSTRUCT dis = (DRAWITEMSTRUCT)Marshal.PtrToStructure(m.LParam, typeof(DRAWITEMSTRUCT));
            Graphics g = Graphics.FromHdc(dis.hDC);
            ListViewItem i = this.Items[dis.itemID];

            Rectangle rcItem = new Rectangle(dis.rcItem.left, dis.rcItem.top, this.ClientSize.Width, dis.rcItem.Height);
            //we have our rectangle.
            //draw whatever you want
            if (dis.itemState == 17)
            {
                //item is selected
                g.FillRectangle(new SolidBrush(Color.Red), rcItem);
                g.DrawString(i.Text, new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(rcItem.X, rcItem.Y+1));
            }
            else
            {
                //regular item
                g.FillRectangle(new SolidBrush(Color.White), rcItem);
                g.DrawString(i.Text, new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(rcItem.X, rcItem.Y+1));
            }

            //we have handled the message
            m.Result = (IntPtr)1;
        }

Это результат.

alt text

1 голос
/ 04 августа 2009

Моей первой мыслью было бы создать подкласс элемента управления ListView, установить для OwnerDraw значение true и выполнить все рисование самостоятельно, но это кажется излишним для такого небольшого изменения.

Однако в своих блужданиях по сети я обнаружил статью , которая может оказаться полезной, поскольку она очень похожа на вашу ситуацию и позволяет вам избегать рисования самостоятельно.

...