【问题标题】:Overriding DrawItem for ListBox - unselected items are not redrawn覆盖 ListBox 的 DrawItem - 未重绘的项目
【发布时间】:2010-07-18 08:45:07
【问题描述】:

这是一个 C# 桌面应用程序。我的ListBoxDrawStyle 属性设置为OwnerDrawFixed

问题:我重写了 DrawItem 以绘制不同字体的文本,它可以工作。但是当我在运行时开始调整表单大小时,所选项目被正确绘制,但其余部分没有重新绘制,导致未选中项目的文本看起来损坏。

这是我的代码:

private void listDevices_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();

    string textDevice = ((ListBox)sender).Items[e.Index].ToString();

    e.Graphics.DrawString(textDevice,
        new Font("Ariel", 15, FontStyle.Bold), new SolidBrush(Color.Black), 
        e.Bounds, StringFormat.GenericDefault);


    // Figure out where to draw IP
    StringFormat copy = new StringFormat(
        StringFormatFlags.NoWrap |
        StringFormatFlags.MeasureTrailingSpaces
    );
    copy.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0, textDevice.Length)});

    Region[] regions = e.Graphics.MeasureCharacterRanges(
        textDevice, new Font("Ariel", 15, FontStyle.Bold), e.Bounds, copy);

    int width = (int)(regions[0].GetBounds(e.Graphics).Width);
    Rectangle rect = e.Bounds;
    rect.X += width;
    rect.Width -= width;

    // draw IP
    e.Graphics.DrawString(" 255.255.255.255",
        new Font("Courier New", 10), new SolidBrush(Color.DarkBlue),
        rect, copy);

    e.DrawFocusRectangle();
}

listDevices.Items.Add("Device001");
listDevices.Items.Add("Device002");

此外,正确绘制的项目(选定的项目)在调整表单大小时闪烁。没什么大不了,但如果有人知道为什么.... tnx

【问题讨论】:

    标签: c# winforms listbox ondrawitem


    【解决方案1】:

    将以下代码放入 Resize 事件中:

    private void listDevices_Resize(object sender, EventArgs e) {
        listDevices.Invalidate();
    }
    

    这应该会导致所有内容都被重绘。

    要停止闪烁,您需要双缓冲。

    为此,创建一个从 ListBox 派生的新类,并将以下内容放入构造函数中:

    this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
    

    或者只是将其粘贴到代码文件中:

    using System.Windows.Forms;
    
    namespace Whatever {
        public class DBListBox : ListBox {
            public DBListBox(): base() {
                this.DoubleBuffered = true;
                // OR
                // this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            }
        }
    }
    

    将“Whatever”替换为您的项目使用的命名空间,或者让它变得更有用。编译后,您应该可以在表单设计器中添加一个 DBListBox。

    【讨论】:

    • 感谢主要(重绘)问题提示 - 它有效。不过,双缓冲对闪烁没有帮助。
    【解决方案2】:

    我重现了这个问题。代码有几个错误,字体名称是“Arial”,你不应该调整rect.Width,你忘记在字体、画笔和区域上调用Dispose()。但他们没有解释这种行为。剪切区域出现问题,导致文本无法正确更新。我看不出发生在哪里,Graphics 对象状态还可以。

    Graphics.DrawString() 是一个很麻烦的方法,你真的应该避免它。所有 Windows 窗体控件(包括 ListBox)都使用 TextRenderer.DrawText()。这解决了我使用它时的问题。我知道测量更困难,您可以通过以固定偏移量显示 IP 地址来解决这个问题。看起来也更好,他们会这样排成一列。

    它闪烁是因为您使用了 e.DrawBackground()。这会擦除现有文本,您将文本重新绘制在其上。我不认为双缓冲会解决这个问题,你必须绘制整个项目,这样你就不必绘制背景。如果您无法获得大字体文本的确切大小,则很棘手,解决方法是先绘制位图。

    【讨论】:

    • 非常感谢你看到这个。我会解决你指出的问题。但我想我现在可以忍受闪烁 - 这是一个供个人使用的小工具。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 2010-11-21
    • 2021-03-19
    相关资源
    最近更新 更多