创建自定义多行列表框

时间:2013-09-07 23:08:22

标签: c# listbox multiline

在创建某些应用时,首选包含多行内容的列表框。由于列表框没有这样的功能,因此需要创建自定义控件。对于这种情况,我正在开发一个编译器应用程序,用户可以加载导入和导出C#预制件到程序中来操作数据。要查看此编译器的运行情况,您可以查看我之前的帖子here。对于这个例子,我想要将任何错误的调试日志输出到列表框中。由于某些错误包含多行,其中一些很长,我读了并生成了一个Textbox项目列表框。

最新版本的副本可以在pastebin找到。

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

namespace DataStripper
{
    public partial class MultiLineListView : System.Windows.Forms.ListBox
    {
        public MultiLineListView()
        {
            //InitializeComponent();
            this.DrawMode = DrawMode.OwnerDrawVariable;
            this.ScrollAlwaysVisible = true;
            tbox.Hide();
            tbox.mllb = this;
            Controls.Add(tbox);
        }

        protected override void OnMeasureItem(MeasureItemEventArgs e)
        {
            if (Site != null)
                return;
            if (e.Index > -1)
            {
                string s = Items[e.Index].ToString();
                float best = 0;
                foreach (string line in s.Split(new string[] { Environment.NewLine }, StringSplitOptions.None))
                {
                    float chk = e.Graphics.MeasureString(line, Font, Width).Width;
                    if (chk > best)
                        best = chk;
                }
                SizeF sf = e.Graphics.MeasureString(s, Font, Width);
                int htex = 1;//(e.Index == 0) ? 15 : 10;
                e.ItemHeight = (int)(sf.Height*Items.Count) + htex;
                e.ItemWidth = (int)best;
                /*NTextBox i = (NTextBox)Items[e.Index];
                e.ItemHeight = i.Height;
                e.ItemWidth = i.Width;*/
            }
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            if (Site != null)
                return;
            if (e.Index > -1)
            {
                string s = Items[e.Index].ToString();

                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
                {
                    e.Graphics.FillRectangle(new SolidBrush(SystemColors.Highlight), e.Bounds);
                    e.Graphics.DrawString(s, Font, new SolidBrush(SystemColors.HighlightText),
                        e.Bounds);
                }
            }
        }

        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
        {
            int index = IndexFromPoint(e.X, e.Y);

            if (index != ListBox.NoMatches &&
                index != 65535)
            {

                /*if (e.Button == MouseButtons.Right)
                {
                    SelectedIndex = index;
                    Focus();
                    //tbox.index = index;
                }*/
                /*if (e.Button == MouseButtons.Right)
                {

                    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);
                    tbox.Text = s;
                    tbox.index = index;
                    tbox.SelectAll();
                    tbox.Show();
                    tbox.Focus();
                }*/
            }

            base.OnMouseUp(e);
        }

        NTextBox tbox = new NTextBox();

        class NTextBox : TextBox
        {
            public MultiLineListView mllb;
            public int index = -1;

            bool errshown = false;
            bool brementer = false;

            public NTextBox()
            {
                Multiline = true;
                MaxLength = 2147483647;
                MaximumSize = new System.Drawing.Size(0, 0);
                WordWrap = false;
                ScrollBars = ScrollBars.Both;
                AcceptsReturn = true;
                AcceptsTab = true;
            }

            protected override void OnKeyUp(KeyEventArgs e)
            {
                if (brementer)
                {
                    Text = "";
                    brementer = false;
                }
                base.OnKeyUp(e);
            }

            protected override void OnKeyPress(KeyPressEventArgs e)
            {
                base.OnKeyPress(e);
            }

            protected override void OnLostFocus(System.EventArgs e)
            {

                if (Text.Trim() == "")
                {
                    if (!errshown)
                    {
                        MessageBox.Show(
                            "Cannot enter NULL string as item!",
                            "Fatal error!", MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                    }
                    errshown = false;
                }
                else
                {
                    errshown = false;
                    mllb.Items[index] = Text;
                    Hide();
                }
                base.OnLostFocus(e);
            }
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.KeyData == Keys.F2)
            {
                int index = SelectedIndex;
                if (index == ListBox.NoMatches ||
                    index == 65535)
                {
                    if (Items.Count > 0)
                        index = 0;
                }
                if (index != ListBox.NoMatches &&
                    index != 65535)
                {

                    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);
                    tbox.Text = s;
                    tbox.index = index;
                    tbox.SelectAll();
                    tbox.Show();
                    tbox.Focus();
                }
            }
            base.OnKeyDown(e);
        }
    }
}

我遇到的困难是,即使我已经设置了文本框,列表视图项似乎仍然限制TextWrap的内容,最多7.5行。

Image Reference http://imageshack.us/a/img819/9345/5nh4.png

在第32行foreach (string line in s.Split(new string[] { Environment.NewLine }, StringSplitOptions.None))我尝试在OnMeasureItem覆盖中找到要返回的字符串中最长文本行的长度,但它拒绝超出假定的限制。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

你应该看一下名为GlacialList的控件。你可以轻松地做这件事。最新版本不是免费的,但我曾经使用1.3版本。如果你到达它有一个属性,允许你将任何控件放在列表单元格中。只需添加多行文本框即可开始使用

答案 1 :(得分:0)

它可能不是您的选择,但如果您想要更多高级UI功能,为什么不切换到内置的WPF?