【问题标题】:DrawItem event gets called too many times when adding items添加项目时,DrawItem 事件被调用太多次
【发布时间】:2011-11-04 14:01:11
【问题描述】:

在我的 WinForms 应用程序中,我有一个每秒“滴答”一次的计时器。在这个计时器的刻度方法中,我做了很多事情,包括将项目添加到列表框(称为lbxLogText)。

我需要选择为某些项目的文本着色(颜色是在添加项目之前决定的)。因此,我将 DrawMode 属性设置为 OwnerDrawVariable,lbxLogText_DrawItem 方法如下所示:

private void lbxLogText_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();
    e.DrawFocusRectangle();
    e.Graphics.DrawString(logStringToAdd, 
        new Font(FontFamily.GenericSansSerif, 8),
        new SolidBrush(logStringToAddColor), e.Bounds);

    testCounter++;
    label29.Text = testCounter.ToString();
}

logStringToAdd:一个全局的string

logStringToAddColor:全局Color - 红色或黑色。

testCounter:一个全局的int,初始化为0。

我有一个名为Log() 的方法。这在上面提到的计时器的tick-method中被调用。

看起来是这样的:

private void Log(string status)
{
    // |red, |black
    if (status != null)
    {
        if (status.Contains("|red"))
        {
            status = status.Replace("|red", "");
            logStringToAddColor = Color.Red;
        }
        else if (status.Contains("|black"))
        {
            status = status.Replace("|black", "");
            logStringToAddColor = Color.Black;
        }
        logStringToAdd = status;
        lbxLogText.Items.Add(new object());
    }

    // scroll to bottom
    lbxLogText.SetSelected(lbxLogText.Items.Count - 1, true);
    lbxLogText.SetSelected(lbxLogText.Items.Count - 1, false);
}

status: 可能是“系统工作正常。|黑色”,或“系统工作不正常。|红色”(例如)。此参数在 Log-call 之前更新(当然)。

在某种程度上,这段代码可以正常工作。我有以下问题:

  • 运行程序时,我可以在label29 上看到testCounter 变量不只是每秒递增,就像它从 1 开始,然后变成 3,然后是 6、10、15、21 , 28, 36(我想你现在已经掌握了模式)。这意味着 DrawItem 事件的调用次数更多,而不仅仅是每秒。

  • 假设status 从“asd123|black”变为“qwe456|red”。这意味着添加到列表框中的下一个项目应该是红色的。好吧,它确实变成了红色,但是列表框中的所有项变成了红色。并且所有项目的文本也都更改为最新的。

  • 在调试的时候,可以看到SetSelected方法被调用的时候,直接下到了DrawItem事件方法。但我不知道如何避免这种情况,因为添加新项目时我需要列表框滚动到底部,所以最新的项目是可见的。

【问题讨论】:

    标签: c# winforms listbox


    【解决方案1】:

    DrawItem 不会在您添加新项目时仅调用一次,而是会为 ListBox 中已经存在的每个项目触发。这就是为什么在您的情况下,它每秒被调用一次以上。

    这也解释了label29 模式(“1,然后变成 3,然后是 6、10、15、21、28、36”),因为每次你都会重新绘制所有项目添加一个新项目。

    当然,由于您使用全局变量来设置项目的颜色,因此每个项目都使用该变量的值重新绘制 - 解释了为什么所有项目都变为红色。

    【讨论】:

      【解决方案2】:

      正如 Otiel 所说,只要需要重绘任何项目,就会调用 DrawItem,并且您正在使用全局状态来存储所有项目的文本和颜色。

      要使其特定于每个项目,您可以添加一个以 .ToString() 形式返回文本的对象/类型实例,但您可以在 DrawItem 事件中查询颜色:

      struct LogItem {
        public string Text;
        public Colour ItemColour
      }
      
      private void Log(string status) { 
        LogItem item = new LogItem();
        item.Text = "Wibble";
        item.ItemColour = Colours.Red;
        lbxLogText.Items.Add(item); 
      }
      
      private void lbxLogText_DrawItem(object sender, DrawItemEventArgs e) {   
        LogItem item = lbxLogText.Items[e.Index];
        e.DrawBackground();   
        e.DrawFocusRectangle();   
        e.Graphics.DrawString(item.Text,    
          new Font(FontFamily.GenericSansSerif, 8),   
          new SolidBrush(item.Color), e.Bounds);   
      }  
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多