65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 的可编辑多行列表框

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (40投票s)

2002 年 8 月 5 日

Ms-PL

3分钟阅读

viewsIcon

422647

downloadIcon

7893

一个支持多行自动换行文本以及就地编辑的自绘列表框。

概述

MultiLineListBox 是一个完全自绘的 ListBox 派生类,它支持多行项目以及项目的就地编辑。它已被封装到一个类库中,以便于部署。您在使用它时无需进行任何特殊操作。只需像使用普通列表框一样使用它。每当您添加的字符串对于单行来说太长时,MultiLineListBox 会将长字符串换成多行。编辑项目也很容易。只需右键单击任何项目或在选择项目时按 F2 键,这将在所选或单击的项目上精确地叠加一个编辑框。您可以进行更改,然后按 Enter 键,或者您可以单击列表框内的其他任何位置以使修改生效。如果您想取消更改并返回到原始文本,只需按 Escape 键。

该类不允许您将项目设置为 null,并且会弹出一个消息框警报,并且不允许您从该项目移开焦点,直到您通过按 Escape 键取消了修改,或者您输入了一些文本。

如果您在项目编辑文本框中输入大量文本,则叠加的文本框本身将允许您垂直滚动。

使用该类

只需将控件添加到您的工具箱。现在,像使用普通列表框一样使用它。尝试输入长字符串。并运行程序。尝试通过按 F2 键或右键单击某个项目来编辑字符串。请参阅当您尝试将项目字符串修改为 null 字符串时,警报消息框是如何弹出的。我添加此功能是因为在我将要使用它的项目中,严格禁止使用 null 字符串。也许您可能想要允许 null 字符串,如果是这样,请随意注释掉源代码中的相关代码。

技术细节

很明显,DrawMode 设置为 DrawMode.OwnerDrawVariable。我们需要确定每个项目所需的高度。这就是我们在 OnMeasureItem 重写中执行此操作的方式,

//...

string s = Items[e.Index].ToString();
SizeF sf = e.Graphics.MeasureString(s,Font,Width);
int htex = (e.Index==0) ? 15 : 10;
e.ItemHeight = (int)sf.Height + htex;			
e.ItemWidth = Width;

//...

现在我们需要实际绘制文本,因为这是一个自绘列表框。我们重写 OnDrawItem,如下所示。

protected override void OnDrawItem(DrawItemEventArgs e)
{
    //...

    /*chk if list box has any items*/
    if(e.Index > -1)
    {
        string s = Items[e.Index].ToString();                           

        /*Normal items*/
        if((e.State & DrawItemState.Focus)==0)
        {
            e.Graphics.FillRectangle(
                new SolidBrush(SystemColors.Window),
                e.Bounds);
            e.Graphics.DrawString(s,Font,
                new SolidBrush(SystemColors.WindowText),
                e.Bounds);              
            e.Graphics.DrawRectangle(
                new Pen(SystemColors.Highlight),e.Bounds);              
        }
        else /*Selected item, needs highlighting*/
        {
            e.Graphics.FillRectangle(
                new SolidBrush(SystemColors.Highlight),
                e.Bounds);
            e.Graphics.DrawString(s,Font,
                new SolidBrush(SystemColors.HighlightText),
                e.Bounds);
        }
    }
}

到目前为止还不错。现在进行就地编辑,我们要做的是从 TextBox 派生一个类并将其添加到我们的列表框中。并且我们处理 OnMouseUp 方法来检查用户是否右键单击了某个项目。

protected override void OnMouseUp(
    System.Windows.Forms.MouseEventArgs e)
{
    //...


        /* Is it a right mouse clk? */
        if(e.Button == MouseButtons.Right)
        {

            string s = Items[index].ToString();
            Rectangle rect = GetItemRectangle(index);

            //overlay the text box right over
            //the list box item to be edited
            tbox.Location = new Point(rect.X,rect.Y);
            tbox.Size = new Size(rect.Width,rect.Height);
            tbox.Text = s;              
            tbox.index = index;
            tbox.SelectAll();
            tbox.Show();
            tbox.Focus();
        }

    //...
}

类似地,我们处理 OnKeyDown 来检查用户是否按下了 F2 键。

protected override void OnKeyDown(KeyEventArgs e)
{
    if(e.KeyData == Keys.F2)
    {
        //...

            string s = Items[index].ToString();
            Rectangle rect = GetItemRectangle(index);

            tbox.Location = new Point(rect.X,rect.Y);
            tbox.Size = new Size(rect.Width,rect.Height);               
            
        //...
    }
    
    //...
}

TextBox 派生类中,我们重写 OnLostFocusOnKeyPress(检查 Enter 键)并进行检查以确保用户不会输入 null 字符串。可以检查源代码以了解更精细的细节,但基本上该类所做的就是这些,并且该类是 MultiLineListBox 类的私有内部类。我还检查 OnKeyPress 处理程序中的 Escape 键,以允许用户取消修改。

结论

我希望得到您的反馈 - 无论是好的还是坏的。我还想知道是否有人发现这足够有用,可以在应用程序中使用。或者该类是否可以在任何特定方面进行改进。至于我自己,我花了一整天的时间来处理我遇到的各种问题,主要是由于我在自定义控件编码方面的经验不足,而不是由于我尝试做的任何重大困难。

© . All rights reserved.