C# 在不更改索引的情况下替换visual studio中imagelist中的图像

C# 在不更改索引的情况下替换visual studio中imagelist中的图像,c#,.net,visual-studio,winforms,windows-forms-designer,C#,.net,Visual Studio,Winforms,Windows Forms Designer,我正在使用一个带有大约100个不同图标的imagelist,在一个使用Winforms的C#项目的listview中使用 这些图像由listview通过其索引引用 现在有了一个图形化的大修,所有的图标都需要更换。 到目前为止,我所做的是在VisualStudio编辑器中打开imagelist,删除索引为5的图像x,然后添加新版本的图像x 该方法的问题在于,删除图像x时,索引大于5的所有其他图像都会移位。 在添加图标的新版本后,我必须单击向上箭头大约95次才能再次在索引5处获得我的新版本 有人知

我正在使用一个带有大约100个不同图标的imagelist,在一个使用Winforms的C#项目的listview中使用

这些图像由listview通过其索引引用

现在有了一个图形化的大修,所有的图标都需要更换。 到目前为止,我所做的是在VisualStudio编辑器中打开imagelist,删除索引为5的图像x,然后添加新版本的图像x

该方法的问题在于,删除图像x时,索引大于5的所有其他图像都会移位。 在添加图标的新版本后,我必须单击向上箭头大约95次才能再次在索引5处获得我的新版本

有人知道一种不那么痛苦、不那么容易出错的方法来达到同样的效果吗

编辑.designer.cs文件并没有真正的帮助,因为它只列出图标的名称及其索引

    // 
    // NavigatorImageList
    // 
    this.NavigatorImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("NavigatorImageList.ImageStream")));
    this.NavigatorImageList.TransparentColor = System.Drawing.Color.Transparent;
    this.NavigatorImageList.Images.SetKeyName(0, "dummy.png");
    this.NavigatorImageList.Images.SetKeyName(1, "Attribute.png");
    this.NavigatorImageList.Images.SetKeyName(2, "Operation.png");
    this.NavigatorImageList.Images.SetKeyName(3, "Element.png");
    this.NavigatorImageList.Images.SetKeyName(4, "Diagram.png");
    this.NavigatorImageList.Images.SetKeyName(5, "Package_element.png");
    // ...continues like this for all items ....
实际图像存储在.resx文件中,但它们是二进制格式的,因此也不能在那里编辑它们

  <data name="NavigatorImageList.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
    <value>
        AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
        LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
        ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAB2
        1gAAAk1TRnQBSQFMAgEBYwEAAYgBAgGIAQIBEAEAARABAAT/AREBAAj/AUIBTQE2BwABNgMAASgDAAFA
        AwABkAEBAgABAQEAARAGAAHIJgABeAEtAfABHAHwARwB8AEcAfABHAHwARwWAAG4ATUBMAElATABJQEw
... and many many more lines like this...

aaaaad/////aqaaaaaagaaaafdtexn0zw0uv2luzg93cy5gb3jtcywgvmvyc2lvbj00ljaumc4w
LCBDDWX0DXJLPW5LDXRYYWWIFB1YMXPY0TLEVA2VUPWI3N2E1YZU2MTKZNGUWODKFAQAAACZTEXN0
ZW0UV2LUZG93CY5GB3JTCY5JBWFNZUXPC3RTDHJLYW1CGEAAAERGF0YQCCAGAAAKDAADWMAAB2
1GAAAK1TRNQBSQFGMAGEBYWEAGBAGGIAQIBEAARABAAT/AREBAJ/AUIBTQE2BWANGMAASGDAAFA
Awabkaebagabaqaearagahijgabeaetafabhahwarwb8aecafabhahwarwwaag4atubmaelatabjqew
... 还有更多像这样的台词。。。
我知道根据他们的索引引用图片可能是一个错误,但现在改变这一点已经有点晚了

TL;博士
我正在寻找一种简单的方法来替换imagelist中的图像,而不必更改依赖于图像索引的现有工作代码。

图像列表编辑器也有一个默认不可浏览的图像属性。作为一个选项,您可以使该属性可见,然后可以在设计时轻松替换图像,而不会出现任何问题

查看下图并查看
图像
属性:

这是我的图像收集编辑器。它基本上是原始图像采集编辑器的代码,只需稍作更改,即可找到采集编辑器的
PropertyGrid
并重置其属性

public class MyImageListEditor : CollectionEditor
{
    Type ImageListImageType;
    public MyImageListEditor(Type type) : base(type)
    {
        ImageListImageType = typeof(ControlDesigner).Assembly
            .GetType("System.Windows.Forms.Design.ImageListImage");
    }
    protected override string GetDisplayText(object value)
    {
        if (value == null)
            return string.Empty;
        PropertyDescriptor property = TypeDescriptor.GetProperties(value)["Name"];
        if (property != null)
        {
            string str = (string)property.GetValue(value);
            if (str != null && str.Length > 0)
                return str;
        }
        if (value.GetType() == ImageListImageType)
            value = (object)((dynamic)value).Image;
        string name = TypeDescriptor.GetConverter(value).ConvertToString(value);
        if (name == null || name.Length == 0)
            name = value.GetType().Name;
        return name;
    }
    protected override object CreateInstance(Type type)
    {
        return ((UITypeEditor)TypeDescriptor.GetEditor(ImageListImageType,
            typeof(UITypeEditor))).EditValue(Context, null);
    }
    protected override CollectionEditor.CollectionForm CreateCollectionForm()
    {
        CollectionEditor.CollectionForm collectionForm = base.CreateCollectionForm();
        collectionForm.Text = "My Image Collection Editor";
        var overArchingTableLayoutPanel =  
            (TableLayoutPanel)collectionForm.Controls["overArchingTableLayoutPanel"];
        var propertyBrowser =  
            (PropertyGrid)overArchingTableLayoutPanel.Controls["propertyBrowser"];
        propertyBrowser.BrowsableAttributes = new AttributeCollection();

        return collectionForm;
    }
    protected override IList GetObjectsFromInstance(object instance)
    {
        return (IList)(instance as ArrayList) ?? (IList)null;
    }
}
要为图像列表注册此编辑器,最简单的解决方案是在基类的构造函数中注册它:

public partial class Form1 : MyBaseForm
{
    public Form1()
    {
        InitializeComponent();
    }
}

public class MyBaseForm : Form
{
    public MyBaseForm()
    {
        TypeDescriptor.AddAttributes(typeof(ImageList.ImageCollection),
            new Attribute[] { 
                new EditorAttribute(typeof(MyImageListEditor), typeof(UITypeEditor)) });
    }
}
然后关闭所有设计器,重建解决方案,关闭并重新打开VS


就这些

如果这是一个.NET项目,其中ImageList位于
*.resx
文件中,为什么不直接手工编辑
*.resx
文件呢?或者,如果是WinForms项目,请手动编辑
*designer.cs
文件。感谢您的输入。我已经在问题中添加了一些关于这些的细节。如果我处在您的位置,我会使用
XmlDocument
编写一个Linqpad程序,对resx文件进行大量更改(Linqpad是免费的,但您需要为有用的功能付费)。也就是说,我认为你可以让一个resx文件使用链接文件,而不是将它们直接存储在resx文件中,作为XML中的Base64。我只能选择一个图像文件,然后像这样将其添加到resx文件中。您不必在设计器中添加这些图像。制作一个
字典
,使用索引对->资源名,将所有图像作为资源添加到仅资源库(仅包含资源的dll和按名称或索引或索引范围返回位图的公共方法),并在运行时填充图像列表。如果您更改了资源库中的某些内容,您可能不必更改填充ImageList的方法中的任何内容,只要您使用索引来定义对象的图像源。哇,这看起来很有希望,很酷!我会尝试一下,然后回来报告……不用担心。应用该解决方案非常容易。花足够的时间来测试它;然而,我已经测试过了,并且工作得很好。如果您发现任何问题,请告诉我。我应用MyImageListEditor的方法不是唯一的方法,而是最简单的方法。它依赖于一个事实:Windows窗体设计器在设计窗体的基本窗体的构造函数中运行代码。这就是为什么我添加了一个虚拟的基本表单,并将注册码放在那里。要了解有关designer如何工作的更多信息,您可以查看一下。注册编辑器的另一个选项(您不需要使用)是在VS包中进行注册,例如更改
ColorEditor
以显示一些自定义颜色。谢谢,这非常有效!正是我要找的!