C# 集合编辑器数据在设计时丢失

C# 集合编辑器数据在设计时丢失,c#,winforms,collectioneditor,C#,Winforms,Collectioneditor,我试图创建一个WinForms usercontrol,将集合作为属性(其中T代表一些自定义类)。我已经读了很多关于这个主题的书,但是我不能让它在设计时正常工作(在运行时一切正常)。更准确地说:当我单击属性窗口中的“…”按钮时,集合编辑器显示良好,我可以添加和删除项目。但是,当我单击OK按钮时,什么也没有发生,当我重新打开集合编辑器时,所有项目都会丢失。当我查看设计器文件时,我看到我的属性被指定为null,而不是组合的集合。我将向您展示最重要的代码: UserControl: [Browsabl

我试图创建一个WinForms usercontrol,将
集合作为属性(其中T代表一些自定义类)。我已经读了很多关于这个主题的书,但是我不能让它在设计时正常工作(在运行时一切正常)。更准确地说:当我单击属性窗口中的“…”按钮时,集合编辑器显示良好,我可以添加和删除项目。但是,当我单击OK按钮时,什么也没有发生,当我重新打开集合编辑器时,所有项目都会丢失。当我查看设计器文件时,我看到我的属性被指定为null,而不是组合的集合。我将向您展示最重要的代码:

UserControl:

[Browsable(true),
 Description("The different steps displayed in the control."),
 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
 Editor(typeof(CustomCollectionEditor), typeof(UITypeEditor))]
public StepCollection Steps
{
    get
    {
        return wizardSteps;
    }
    set
    {
        wizardSteps = value;
        UpdateView(true);
    }
}
public class StepCollection : System.Collections.CollectionBase
{
    public StepCollection() : base() { }
    public void Add(Step item) { List.Add(item); }
    public void Remove(int index) { List.RemoveAt(index); }
    public Step this[int index]
    {
        get { return (Step)List[index]; }
    }
}
[ToolboxItem(false),
DesignTimeVisible(false),
Serializable()]
public class Step : Component
{
    public Step(string name) : this(name, null, StepLayout.DEFAULT_LAYOUT){ }
    public Step(string name, Collection<Step> subSteps) : this(name, subSteps, StepLayout.DEFAULT_LAYOUT){ }
    public Step(string name, Collection<Step> subSteps, StepLayout stepLayout)
    {
        this.Name = name;
        this.SubSteps = subSteps;
        this.Layout = stepLayout;
    }
    // In order to provide design-time support, a default constructor without parameters is required:
    public static int NEW_ITEM_ID = 1;
    public Step()
        : this("Step" + NEW_ITEM_ID, null, StepLayout.DEFAULT_LAYOUT)
    {
        NEW_ITEM_ID++;
    }
    // Some more properties
}
class CustomCollectionEditor : CollectionEditor
{
    private ITypeDescriptorContext mContext;

    public CustomCollectionEditor(Type type) : base(type) { }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        mContext = context;
        return base.EditValue(context, provider, value);
    }
    protected override object CreateInstance(Type itemType)
    {
        if (itemType == typeof(Step))
        {
            Step s = (Step)base.CreateInstance(itemType);
            s.parentContext = mContext; // Each step needs a reference to its parentContext at design time
            return s;
        }
        return base.CreateInstance(itemType);
    }
}
StepCollection类:

[Browsable(true),
 Description("The different steps displayed in the control."),
 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
 Editor(typeof(CustomCollectionEditor), typeof(UITypeEditor))]
public StepCollection Steps
{
    get
    {
        return wizardSteps;
    }
    set
    {
        wizardSteps = value;
        UpdateView(true);
    }
}
public class StepCollection : System.Collections.CollectionBase
{
    public StepCollection() : base() { }
    public void Add(Step item) { List.Add(item); }
    public void Remove(int index) { List.RemoveAt(index); }
    public Step this[int index]
    {
        get { return (Step)List[index]; }
    }
}
[ToolboxItem(false),
DesignTimeVisible(false),
Serializable()]
public class Step : Component
{
    public Step(string name) : this(name, null, StepLayout.DEFAULT_LAYOUT){ }
    public Step(string name, Collection<Step> subSteps) : this(name, subSteps, StepLayout.DEFAULT_LAYOUT){ }
    public Step(string name, Collection<Step> subSteps, StepLayout stepLayout)
    {
        this.Name = name;
        this.SubSteps = subSteps;
        this.Layout = stepLayout;
    }
    // In order to provide design-time support, a default constructor without parameters is required:
    public static int NEW_ITEM_ID = 1;
    public Step()
        : this("Step" + NEW_ITEM_ID, null, StepLayout.DEFAULT_LAYOUT)
    {
        NEW_ITEM_ID++;
    }
    // Some more properties
}
class CustomCollectionEditor : CollectionEditor
{
    private ITypeDescriptorContext mContext;

    public CustomCollectionEditor(Type type) : base(type) { }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        mContext = context;
        return base.EditValue(context, provider, value);
    }
    protected override object CreateInstance(Type itemType)
    {
        if (itemType == typeof(Step))
        {
            Step s = (Step)base.CreateInstance(itemType);
            s.parentContext = mContext; // Each step needs a reference to its parentContext at design time
            return s;
        }
        return base.CreateInstance(itemType);
    }
}
步骤类:

[Browsable(true),
 Description("The different steps displayed in the control."),
 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
 Editor(typeof(CustomCollectionEditor), typeof(UITypeEditor))]
public StepCollection Steps
{
    get
    {
        return wizardSteps;
    }
    set
    {
        wizardSteps = value;
        UpdateView(true);
    }
}
public class StepCollection : System.Collections.CollectionBase
{
    public StepCollection() : base() { }
    public void Add(Step item) { List.Add(item); }
    public void Remove(int index) { List.RemoveAt(index); }
    public Step this[int index]
    {
        get { return (Step)List[index]; }
    }
}
[ToolboxItem(false),
DesignTimeVisible(false),
Serializable()]
public class Step : Component
{
    public Step(string name) : this(name, null, StepLayout.DEFAULT_LAYOUT){ }
    public Step(string name, Collection<Step> subSteps) : this(name, subSteps, StepLayout.DEFAULT_LAYOUT){ }
    public Step(string name, Collection<Step> subSteps, StepLayout stepLayout)
    {
        this.Name = name;
        this.SubSteps = subSteps;
        this.Layout = stepLayout;
    }
    // In order to provide design-time support, a default constructor without parameters is required:
    public static int NEW_ITEM_ID = 1;
    public Step()
        : this("Step" + NEW_ITEM_ID, null, StepLayout.DEFAULT_LAYOUT)
    {
        NEW_ITEM_ID++;
    }
    // Some more properties
}
class CustomCollectionEditor : CollectionEditor
{
    private ITypeDescriptorContext mContext;

    public CustomCollectionEditor(Type type) : base(type) { }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        mContext = context;
        return base.EditValue(context, provider, value);
    }
    protected override object CreateInstance(Type itemType)
    {
        if (itemType == typeof(Step))
        {
            Step s = (Step)base.CreateInstance(itemType);
            s.parentContext = mContext; // Each step needs a reference to its parentContext at design time
            return s;
        }
        return base.CreateInstance(itemType);
    }
}
我已经尝试过的事情:

  • 将步骤设置为a类组件,如下所述:
  • Collection
    更改为自定义集合类
    StepCollection
    继承System.Collections.CollectionBase(也在前面的代码项目文章中介绍)
  • 按此处所述将DesignerSerializationVisibility设置为内容:当设置为Visible时,设计器将null指定给我的属性;设置为“内容”时,设计器不指定任何内容
  • 我也发现了这一点:但是CollectionBase类已经为我做了这一点
  • 调试很多,但由于没有例外,我真的不知道出了什么问题。当我将事件侦听器添加到collectionForm的关闭事件时,我可以看到(collectionForm的)EditValue属性仍然为null,即使我在集合编辑器中添加了一些步骤。但我也不知道为什么
当我读完这篇文章时,我发现了这个话题:
这与我遇到的问题完全相同,但是我不能使用建议的答案,因为我没有使用标准集合。

查看这篇关于CodeProject的伟大文章,我测试了这两篇文章,它们都有效

  • (你提到它不起作用,但我检查了一下,它起作用了)

我认为你没有申请的主要区别是:

  • 为您的收藏更改的支持属性
  • 为支持InstanceDescriptor的集合项类创建TypeConverter

    • Reza Aghaei提到的文章非常有趣。然而,我认为我即将找到一个更简单的解决问题的方法:

      正如我已经注意到的,collectionForm的EditValue属性保持为空,尽管向集合中添加了项。现在,我不确定集合编辑器的EditValue方法内部发生了什么,但我猜它捕获了一个异常,因为我的集合的初始值为null(未在构造函数中初始化),因此返回null而不是创建新集合。通过在自定义集合编辑器类中进行以下更改,我获得了非常有希望的结果:

      public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
      {
          mContext = context;
          if (value == null) value = new Collection<Step>();
          Collection<Step> result = (Collection<Step>)base.EditValue(context, provider, value);
          if (result != null && result.Count == 0) return null;
          return result;
      }
      
      此代码将出现异常,因为wizardStepsControl1.Steps从未初始化为集合。我想要的是这样的东西:

      this.wizardStepsControl1.Steps = new Collection<Step>();
      this.wizardStepsControl1.Steps.Add(step1);
      // ...
      
      通过使用DesignerSerializerAttribute将此序列化程序与我的自定义控件关联,在设计器文件中生成以下代码:

      // 
      // wizardStepsControl1
      // 
      // This is a custom comment added by a custom serializer on vrijdag 4 september 2015
      this.wizardStepsControl1.Steps = new System.Collections.ObjectModel.Collection<WizardUserControl.Step>();
      // ...
      this.wizardStepsControl1.Steps.Add(step1);
      // ...
      
      //
      //向导步骤控件1
      // 
      //这是由自定义序列化程序于2015年9月4日在vrijdag上添加的自定义注释
      this.wizardStepsControl1.Steps=new System.Collections.ObjectModel.Collection();
      // ...
      this.wizardStepsControl1.Steps.Add(步骤1);
      // ...
      
      这正是我想要的


      我从

      中获取了大部分代码,谢谢你的回答。我会看一看,看看我能做些什么。你好,我遇到了同样的问题,尽管你的回答我仍然做不到,你能提供一个解决方案吗?你在谈论哪个问题?不幸的是,我不再热衷于C#development,所以我不知道我是否能进一步帮助你