通过Dialog(s)将资源/导入映像添加到VS Designer中的自定义UserControl属性

时间:2016-07-28 13:39:04

标签: image visual-studio user-controls resources propertygrid

我的目标是创建一个显示一些图像的自定义控件,可以由该控件的用户添加/交换。因此,如果将其添加到表单中,GUI设计者应该能够更改控件提供的部分或全部图像,以编辑相应的属性。

在我的测试项目中,我有一个带有4个属性的简单控件:

 public Image MyImage { get; set; } = null;
 public List<int> MyListOfInt { get; set; } = new List<int>();
 public List<Image> MyListOfImages { get; set; } = new List<Image>();
 public ImageList MyImageList { get; set; } = new ImageList();

在Windows窗体项目中使用此控件,单击

  1. MyImage显示“选择资源”对话框。确定

  2. MyListOfInt打开“Int32集合编辑器”对话框。确定

  3. MyListOfImages显示“图像集编辑器”对话框,但使用“添加”按钮会显示消息:

      

    '无法创建System.Drawing.Image的实例,因为它是一个。{   抽象类。'

  4. MyImageList显示了一个无法编辑的emtpy列表。

  5. 我的问题是,如果有可能告诉VS Designer在点击“添加”按钮时使用“选择资源”对话框以及需要做什么?

2 个答案:

答案 0 :(得分:1)

从Marwie的评论开始,我能够解决问题。

  

为了使用CollectionEditor成功保存,集合应满足三个要求:

  1. 集合必须实现IList接口(继承自System.Collections.CollectionBase在大多数情况下是最佳选择)。
  2. 该集合必须具有Indexer属性。
  3. 集合类必须实现以下一种或两种方法:Add和/或AddRange
  4. 所以我创建了一个包含

    的类'ImageItem'
    • 图片

      [Category("ImageItem")]
      [DefaultValue(typeof(Image), null)]
      [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
      public Image Picture {
        get { return m_Picture; }
        set { m_Picture = value; }
      }
      
    • 名称(可选)

      [Category("ImageItem")]
      [DefaultValue(typeof(string), "")]
      [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
      public string Name {
        get { return m_Name; }
        set { m_Name = value; }
      }
      
    • 一个值(可选)

      [Category("ImageItem")]
      [DefaultValue(typeof(int), "-1")]
      [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
      public int Value {
        get { return m_Value; }
        set { m_Value = value; }
      }
      

    和一个集合'ImageCollection'根据上述条件保存此类的实例:

    1. public class ImageCollection : CollectionBase
    2. public ImageItem this[int i]
    3. public ImageItem Add(ImageItem item)
    4. 然后我创建了一个仅包含此集合的控件,用一个图像初始化:

      public partial class MyControl: UserControl
      {
          public MyControl() {
              InitializeComponent();
          }
      
          private ImageCollection   m_MyImageCollection = new ImageCollection()
          { new ImageItem(0, "Failure", Properties.Resources.Cross), new ImageItem(1, "OK", Properties.Resources.Tickmark) };
      
          [Browsable(true), Category("A Test"), DisplayName("Image Collection (ImageCollection)"), Description("Edit image collection")]
          [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
          [Editor(typeof(System.ComponentModel.Design.CollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
          public ImageCollection    MyImageCollection {
              get { return m_MyImageCollection; }
          }
      }
      

      编译此代码后,设计人员会显示该属性。现在可以使用常见的设计器GUI控件添加图像。

      MyControl

      Edit image collection

      Select Resource

      在我的表单上使用它时,我尝试更改编译到此控件中的默认图像,但我认识到,设计人员无法删除内容。它只存储“添加”操作。所以我修改了代码,在集合中搜索具有相同ID的另一个项目。如果有一个可用,则删除该实例并替换为新实例。因此,我也必须实施AddRange方法。

      public ImageItem Add(ImageItem item) {
          for(int i = 0; i < InnerList.Count; i++) {
              if(InnerList[i] is ImageItem) {
                  if(((ImageItem)InnerList[i]).Value == item.Value) {
                      InnerList.RemoveAt(i);
                  }
              }
          }
          this.InnerList.Add(item);
          return item;
      }
      
      public void AddRange(ImageItem[] array) {
          foreach(ImageItem item in array) {
              Add(item);
          }
      }
      

      所以我的最后课程是:

      My Classes

      public class ImageItem {
        private int               m_Value   = -1;
        private string            m_Name    = "ImageItem";
        private Image             m_Picture = null;
      
        [Category("ImageItem")]
        [DefaultValue(typeof(int), "-1")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int Value {
          get { return m_Value; }
          set { m_Value = value; }
        }
      
        [Category("ImageItem")]
        [DefaultValue(typeof(string), "")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string Name {
          get { return m_Name; }
          set { m_Name = value; }
        }
      
        [Category("ImageItem")]
        [DefaultValue(typeof(Image), null)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Image Picture {
          get { return m_Picture; }
          set { m_Picture = value; }
        }
      
        public ImageItem() { }
      
        public ImageItem(int value, string name, Image image) {
          this.m_Value   = value;
          this.m_Name    = name;
          this.m_Picture = image;
        }
      }
      

      ImageCollection

      public class ImageCollection : CollectionBase {
        public ImageCollection() {}
      
        public ImageItem this[int i]
        {
          get { return (ImageItem)this.InnerList[i]; }
          set { this.InnerList[i] = value; }
        }
      
        public ImageItem Add(ImageItem item) {
          for(int i = 0; i < InnerList.Count; i++) {
            if(InnerList[i] is ImageItem) {
              if(((ImageItem)InnerList[i]).Value == item.Value) {
                InnerList.RemoveAt(i);
              }
            }
          }
          this.InnerList.Add(item);
          return item;
        }
      
        public void AddRange(ImageItem[] array) {
          foreach(ImageItem item in array) {
            Add(item);
          }
        }
      
        public void Remove(ImageItem item) {
          this.InnerList.Remove(item);
        }
      
        public bool Contains(ImageItem item) {
          return this.InnerList.Contains(item);
        }
      
        public ImageItem[] GetValues() {
          ImageItem[] item= new ImageItem[this.InnerList.Count];
          this.InnerList.CopyTo(0, item, 0, this.InnerList.Count);
          return item;
        }
      
        protected override void OnInsert(int index, object value) {
          base.OnInsert(index, value);
        }
      }
      

答案 1 :(得分:1)

我从MSDN得到了另一个答案: How to edit UserControl attribute of type ImageList in Designer PropertyGrid (add/remove/exchange images)

我将简要介绍这个想法。首先使用ImageList属性创建一个新控件。

public partial class NewControl : UserControl {
    public NewControl() {
        InitializeComponent();
    }

    public ImageList MyImageList { get; set; } = null;
}
  1. 然后在任何表单上拖动此控件。
  2. 另外将ImageList控件从Toolbox拖到此处 表格 - 我称之为“MyImages&#39;。
  3. 使用设计师修改MyImages → Images
  4. 分配&#39; MyImages&#39;到属性网格中的NewControl的实例属性MyImageList
  5. Edit MyImages

    我在这里看到的唯一缺点是,如果控件已经具有初始化的ImageList属性,则设计器无法处理它。如果您在分配另一个列表之前尝试编辑MyImageList,则设计器会显示控件附带的控件默认列表。但是无法编辑该列表。

    这个解决方案比上面的第一个解决方案更容易处理并且更短,所以我更喜欢它。