1

我有一个包含一组 PathItems 的列表框。根据用户的喜好,我用几种不同的情况覆盖了 ToString 方法。

它基本上是自定义对象中包含的文件名列表。

class PathItem
{
    public static bool show_ext { get; set; }
    public static bool use_full_path { get; set; }
    public string filepath { get; set; }

    public override string ToString()
    {
        if (use_full_path)
            return filepath;
        else if (show_ext)
            return Path.GetFileName(filepath);
        else
            return Path.GetFileNameWithoutExtension(filepath);
    }
}

GUI 有两个复选框。一个复选框将显示文件扩展名,另一个复选框将显示文件的绝对路径。检查其中任何一个都将更新上面定义的静态变量。

每当我选择一个复选框时,我都希望更新列表框以反映用户的选择。

我相信解决方案是让列表框通过再次调用 ToString 方法来刷新其所有项目以获取每个项目的新值,但我不确定如何做到这一点。

我也不确定这是否属实,但如果我说

PathItem.show_ext = true;

这适用于所有现有PathItem对象吗?

更新:

按照建议尝试该Refresh方法后,即使选中了复选框(它们在 ClickChanged 上触发 Refresh 调用),列表框中的字符串也没有更新。在方法内部写了一条打印语句ToString,但是刷新后没有打印出任何消息。

不确定这是否是因为我在列表框中使用了自定义对象。

这就是我向列表框中添加项目的方式

foreach (string filename in files)
    listBox1.Items.Add(new PathItem { filepath = filename });
4

2 回答 2

4

有趣的是,打电话

myListBox.Refresh()

不会导致 ListBox包含的对象重新评估 ToString()。大概这些值被缓存在某处。

您可以使用以下方法强制 ListBox 重新计算 ToString()。我在我的 ListBox 中使用超过 100 个项目(在一台快速计算机上)对其进行了测试,并且没有看到任何视觉伪影或延迟。

    private void UpdateToString(ListBox listBox)
    {
        int count = listBox.Items.Count;
        listBox.SuspendLayout();
        for (int i = 0; i < count; i++)
        {
            listBox.Items[i] = listBox.Items[i];
        }
        listBox.ResumeLayout();
    }

还,

PathItem.show_ext = true;

会立即影响从该点开始引用 *show_ext* 的每个 PathItem 实例,因为 *show_ext* 是一个静态变量。它在任何时间点都只有一个值,该值在该类的所有实例之间共享。

于 2012-08-09T04:30:22.977 回答
0

我为ComboBox找到了一个解决方案,但它也适用于ListBox:强制控件重新创建它的句柄,如果失败,只需将DrawMode更改为其他内容并将其改回。

让它成为广泛的方法,以便您可以轻松地从任何地方调用它:

/// <summary>
/// <see cref="ListBox"/> helper methods
/// </summary>
public static class ListBoxHelper
{
    /// <summary>
    /// Forces the control to refresh it's items drawing
    /// </summary>
    public static void Redraw(this ListBox control)
    {
        // Check input parameter
        if (control != null)
        {
            // Try get handle recreate method, may fail in some scenarios
            MethodInfo recreate = typeof(Control).GetMethod("RecreateHandle", BindingFlags.Instance | BindingFlags.NonPublic);
            if (recreate != null)
            {
                // Just force control do recreate it's handle
                recreate.Invoke(control, null);
            }

            // Fail to get recreate handle method
            // Let's do it manually
            else
            {
                // Render is normal?
                DrawMode original = control.DrawMode;
                if (original == DrawMode.Normal)
                {
                    // Change it to owner and then back in normal
                    control.DrawMode = DrawMode.OwnerDrawFixed;
                    control.DrawMode = DrawMode.Normal;
                }
                else
                {
                    // Change it to normal and them back to original
                    control.DrawMode = DrawMode.Normal;
                    control.DrawMode = original;
                }
            }
        }
    }
}

并使用它:

this.MyList.Redraw();
于 2021-10-05T14:53:11.497 回答