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