代码之家  ›  专栏  ›  技术社区  ›  Chetan

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

  •  0
  • Chetan  · 技术社区  · 15 年前

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

    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 回复  |  直到 13 年前
        1
  •  1
  •   Bryan Menard    15 年前

    编辑 为了更清楚起见,我重新写了我的答案。

    下面的列表框显示一个文本框及其SelectedItem。

    GetItemRectangle(int index) 
    

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

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