在所有者绘制列表框中使用控件的正确方法是什么?

时间:2009-08-31 04:50:30

标签: c# .net-2.0 listbox controls ownerdrawn

我正在尝试使用所有者绘制的列表框。我正在向列表框中的特定项添加一个文本框。但是,当我开始滚动时,文本框不会显示在正确的位置。这样做的正确方法是什么? 这是我正在使用的代码。

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace ListBoxControlScrollIssue
{
    public partial class Form1 : Form
    {
        private const Int32         cellHeight = 40;
        private ListBox             listBox1;
        private Font                displayFont =  new Font(FontFamily.GenericSerif, 8, FontStyle.Regular);
        private Brush               displayBrush = Brushes.Black;
        private Pen                 displayPen = Pens.Black;
        private Button              separateDebug;
        private TextBox             item3Text;            
        public Form1()
        {
            SetupListBox();
        }

        private void SetupListBox()
        {
            this.listBox1 = new System.Windows.Forms.ListBox();
            this.SuspendLayout();

            // 
            // listBox1
            // 
            this.listBox1.FormattingEnabled = true;
            this.listBox1.Location = new System.Drawing.Point(40, 40);
            this.listBox1.Name = "listBox1";
            this.listBox1.Size = new System.Drawing.Size(300, 100);
            this.listBox1.TabIndex = 0;
            this.listBox1.DrawMode = DrawMode.OwnerDrawVariable;
            this.listBox1.MeasureItem += new MeasureItemEventHandler(listBox1_MeasureItem);
            this.listBox1.DrawItem += new DrawItemEventHandler(listBox1_DrawItem);

            //
            // Add items to list box.
            //
            this.listBox1.Items.Add("Item0");
            this.listBox1.Items.Add("Item1");
            this.listBox1.Items.Add("Item2");
            this.listBox1.Items.Add("Item3");
            this.listBox1.Items.Add("Item4");

            //
            // Add button.
            //
            separateDebug = new Button();
            separateDebug.Name = "SeperateDebug";
            separateDebug.Text = "Seperator";
            separateDebug.Location = new Point(400, 100);
            separateDebug.Click += new EventHandler(separateDebug_Click);

            //
            // Create the text box. However, don't add it to anything.
            //
            item3Text = new TextBox();
            item3Text.Name = "item3Text";
            item3Text.Multiline = false;

            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(525, 421);
            this.Controls.Add(this.listBox1);
            this.Controls.Add(this.separateDebug);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
        }

        void separateDebug_Click(object sender, EventArgs e)
        {
            Debug.Print("\n=========================\n");
        }

        void listBox1_DrawItem(object sender, DrawItemEventArgs e)
        {
            PointF      displayLocation = new PointF(20, e.Index * cellHeight + 3);

            //
            // Display text names of the items here.
            //
            //
            Debug.Print("DrawItem:: Index = {0}, location = {1}", e.Index, displayLocation);
            e.Graphics.DrawString(this.listBox1.Items[e.Index].ToString(), displayFont, displayBrush, e.Bounds);
            //
            // Draw rectangle around the border to show boundary of cell.
            //
            e.Graphics.DrawRectangle(displayPen, e.Bounds);
        }

        void listBox1_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            e.ItemHeight = cellHeight;
            e.ItemWidth = this.listBox1.Width;
            if (e.Index == 3)
            {
                //
                // Set the location of item3Text to the location of bounds.
                //
                item3Text.Location = new Point(21, e.Index * cellHeight + 21);
                listBox1.Controls.Add(item3Text);
            }
        }

    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace ListBoxControlScrollIssue
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Form.Designer.cs

namespace ListBoxControlScrollIssue
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
        }

        #endregion

    }
}

1 个答案:

答案 0 :(得分:1)

编辑我重写了我的答案,以便更清楚。

下面的ListBox显示一个TextBox及其SelectedItem。

GetItemRectangle(int index) 

用于检索项目在ListBox中的当前位置。这似乎是你正在寻找的关键方法。

public class ListBoxEx : ListBox
{
    public ListBoxEx()
    {
        TextBox.Visible = false;
        Controls.Add(TextBox);
    }

    private readonly Size TextBoxOffset = new Size(16, 16);
    private const Int32 CellHeight = 40;
    private readonly TextBox TextBox = new TextBox();

    protected override void OnSelectedIndexChanged(EventArgs e)
    {
        base.OnSelectedIndexChanged(e);
        TextBox.Visible = SelectedIndex != -1;
    }

    protected override void OnDrawItem(DrawItemEventArgs e)
    {
        base.OnDrawItem(e);

        // Somehow necessary
        e.Graphics.FillRectangle(new SolidBrush(BackColor), e.Bounds);
        // Drawing the item's text
        e.Graphics.DrawString(Items[e.Index].ToString(), Font, new SolidBrush(ForeColor), e.Bounds);
        // Drawing the item's borders
        e.Graphics.DrawRectangle(new Pen(ForeColor), e.Bounds);

        // Drawing updating the TextBox location 
        if (SelectedIndex != -1)
            TextBox.Location = Point.Add(GetItemRectangle(SelectedIndex).Location, TextBoxOffset);

        // Because clicking the scrollbar sometimes cause the ListBox to hide the TextBox
        TextBox.BringToFront();
        // Making sure the TextBox is redrawn ASAP
        TextBox.Invalidate();
    }

    protected override void OnMeasureItem(MeasureItemEventArgs e)
    {
        base.OnMeasureItem(e);
        e.ItemHeight = CellHeight;
    }
}