【问题标题】:Listbox character limit per line每行列表框字符限制
【发布时间】:2013-12-25 09:00:51
【问题描述】:

我的 Windows 窗体应用程序中有一个列表框,它显示了很长的文本。由于文本很长,用户必须使用水平滑块来检查文本的其余部分。

所以,我想限制每行的列表框字符。对于每 50 个字符,它应该转到下一行,因此用户不必使用 glider。

由于文本源是 Sql 数据库,我不能输入“新行”。

我的代码基本上是这样的:

listbox1.items.add(dbRead["LongText"]); // dbRead = SqlDataReader

所以我必须编辑列表框本身。我查了一下,但没找到。我还尝试找到一个事件,例如文本更改时,每 50 个字符 listbox.items.add("") 等。我仍然对语法不熟悉。

有什么建议吗?

【问题讨论】:

  • 您是否尝试过使用 dbread 加载字符串对象,如果超过 50 个字符则将其拆分并将每个部分添加到列表框中?
  • 我没试过。很好,但是如果我有太多数据会发生什么。从性能方面讲?
  • 唯一的额外开销应该是字符串太长。由于您不必遍历整个列表框,因此实际上可以节省性能。
  • 我不知道如何分割和修剪等。因为我最多编程一个星期,所以这种语法让我死了。当我习惯语法时,我也会尝试你的方式。谢谢。

标签: c# listbox limit


【解决方案1】:

你可以像下面这样写一个扩展方法(SplitByLength)

var input = "I have a listbox in my windows form application that shows quite long texts. Since texts are so long, user have to use the horizontal slider for check the rest of text.\nSo, I want to limit listbox character per line. For every 50 char it should go to next row, so user won't have to use glider.";
var lines = input.SplitByLength(50).ToArray();
listBox1.Items.AddRange(lines);

public static partial class MyExtensions
{
    public static  IEnumerable<string> SplitByLength(this string input, int maxLen)
    {
        return Regex.Split(input, @"(.{1," + maxLen + @"})(?:\s|$)")
                    .Where(x => x.Length > 0)
                    .Select(x => x.Trim());
    }
}

---------编辑---------

在 tinstaafl 发表评论后,编辑似乎是必须

var input = "I have a listbox in my windows form application that shows quite long texts. Since texts are so long, user have to use the horizontal slider for check the rest of text.\nSo, I want to limit listbox character per line. For every 50 char it should go to next row, so user won't have to use glider.";
input = String.Join(" ", Enumerable.Repeat(input, 100));

var t1 = Measure(10, () =>
{
    var lines = input.SplitByLength_LB(50).ToArray();
});

var t2 = Measure(10, ()=>
{
    var lines = input.SplitByLength_tinstaafl(50).ToArray();
});

long Measure(int n,Action action)
{
    action(); //JIT???
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < n; i++)
    {
        action();
    }
    return sw.ElapsedMilliseconds;
}

public static partial class MyExtensions
{
    public static  IEnumerable<string> SplitByLength_LB(this string input, int maxLen)
    {
        return Regex.Split(input, @"(.{1," + maxLen + @"})(?:\s|$)")
                    .Where(x => x.Length > 0)
                    .Select(x => x.Trim());
    }

    public static IEnumerable<string> SplitByLength_tinstaafl(this string input, int maxLen)
    {
        List<string> output = new List<string>();
        while (input.Length > 0)
        {
            output.Add(new string(input.Take(maxLen).ToArray()));
            input = new string(input.Skip(maxLen).ToArray());
        }
        return output;
    }
}

我的结果与你的不同:11 毫秒。与 3384 毫秒相比。 :)

【讨论】:

  • 我试图实现它,但您已经更新了解决方案来解决问题 :) 它运行良好。谢谢。
  • @OzanAyten 既然您问的是性能,您应该知道,这种简单的正则表达式的开销会对性能产生巨大影响。在我的测试中,它是 30 多倍。我添加了替代代码和测试结果。
  • 11 毫秒是正则表达式的方式吗?
  • @OzanAyten 是的,我的测试是这样说的(顺便说一句:我并不是说正则表达式是最快的方法。它只是最简单的方法(至少在我看来))
  • @tinstaafl 如果您认为此答案比您删除的答案更好,请随时投票 :)
【解决方案2】:

重新编写代码以考虑空格。可变长度的行有些短一些,有些长于 50 个字符,并且换行符针对空格进行了调整,我发现性能非常接近。它们在 1000 个字符串上都在 15 到 25 毫秒之间。尽管正则表达式确实执行得更快。这是我使用的代码:

public static partial class MyExtensions
{
    public static IEnumerable<string> SplitByLength_LB(this string input, int maxLen)
    {
        return Regex.Split(input, @"(.{1," + maxLen + @"})(?:\s|$)")
                    .Where(x => x.Length > 0)
                    .Select(x => x.Trim());
    }
    public static IEnumerable<string> SplitByLength_tinstaafl(this string input, int maxLen)
    {
        List<string> output = new List<string>{""};

        string[] temp = input.Split("\n ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
        for(int i = 0; i < temp.Count(); i++)
        {
            if((output.Last() + " " + temp[i]).Length > 50)
            {
                output.Add(temp[i]);
            }
            else
                output[output.Count() - 1] += " " + temp[i];
        }
        return output;
    }
        return output;
    }

测试是这样的:

        Stopwatch s1 = new Stopwatch();
        List<string> source = new List<string>();
        Random rnd = new Random();
        for(int i = 0; i < 1000; i++)
        {
            var input = "I have a listbox in my windows form application that shows quite long texts. Since texts are so long, user have to use the horizontal slider for check the rest of text. So, I want to limit listbox character per line.";
            int nextbreak = rnd.Next(20, input.Length);
            source.Add(new string(input.TakeWhile((x, y) => input.IndexOf(' ', y) <= nextbreak).ToArray()));
        }
        s1.Start();
        List<string> output = new List<string>(from s in source
                                               from p in s.SplitByLength_LB(50)
                                               select p);
        s1.Stop();
        Console.WriteLine("SplitByLength_LB\t" + s1.ElapsedMilliseconds.ToString());
        s1.Reset();
        s1.Start();
        List<string> output2 = new List<string>(from s in source
                                                from p in s.SplitByLength_tinstaafl(50)
                                                select p);
        s1.Stop();
        Console.WriteLine("SplitByLength_tinstaafl\t" + s1.ElapsedMilliseconds.ToString());

【讨论】:

  • I found that the performance is very close to the same 我不能这么说。我将您的新代码复制到我的测试用例中,发现正则表达式解决方案的速度提高了 10 倍以上。
  • 你测试的不是同一个东西。 OP 获得的可变长度字符串有些长于 50,有些则短于 50。您的测试只使用一个长度超过 50 的字符串。
  • 不,我使用了从问题中提取的随机文本。我只是重复了 100 次以获得 long 字符串。
  • 完全正确,您只使用一个超长字符串进行测试,而不是更接近 OP 期望接收的字符串。
  • 让我们说清楚。只需发一个文本(正如OP所说的应该很长(dbRead["LongText"])),以便我们进行客观比较?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-14
相关资源
最近更新 更多