集合编辑器不会在 VS 2013 的设计视图中保留自定义 Web 控件标记中的条目?

Collections Editor is not persisting entries in custom web control markup in design view in VS 2013?

我正在尝试为 ASP.Net WebForms 开发一个简单的自定义 Web 控件,它有一个名为 Subscriptions.

的集合 属性

我可以成功编译控件项目并将其从工具箱添加到 aspx 页面,没有任何问题。

问题是当我在 Visual Studio 2013 中使用设计视图中的集合编辑器为 Subscriptions 属性 添加条目时。

我可以输入多个订阅,但是当我点击集合编辑器的确定按钮然后返回到设计视图中的订阅 属性 时,即使我刚才输入了一些条目,它还是空的。

aspx中自定义控件的标记

<cc1:WebControl1 ID="WebControl1" runat="server"></cc1:WebControl1>

问题:我的代码有什么不正确导致集合不显示在设计视图的控件标记中?

自定义网页控制代码

namespace WebControl1
{
    [ToolboxData("<{0}:WebControl1 runat=\"server\"> </{0}:WebControl1>")]
    [ParseChildren(true)]
    [PersistChildren(false)]
    public class WebControl1 : WebControl
    {
        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string Text
        {
            get
            {
                String s = (String)ViewState["Text"];
                return ((s == null) ? "[" + this.ID + "]" : s);
            }

            set
            {
                ViewState["Text"] = value;
            }
        }
        [
        Category("Behavior"),
        Description("The subscriptions collection"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        Editor(typeof(SubscriptionCollectionEditor), typeof(UITypeEditor)),
        PersistenceMode(PersistenceMode.InnerDefaultProperty)
        ]
        public List<Subscription> Subscriptions { get; set; }

        protected override void RenderContents(HtmlTextWriter output)
        {
            output.Write(Text);
        }
    }
}


[TypeConverter(typeof(ExpandableObjectConverter))]
public class Subscription
{
    private string name;
    private decimal amount;


    public Subscription()
        : this(String.Empty, 0.00m)
    {
    }

    public Subscription(string nm, decimal amt)
    {
        name = nm;
        amount = amt;
    }

    [
    Category("Behavior"),
    DefaultValue(""),
    Description("Name of subscription"),
    NotifyParentProperty(true),
    ]
    public String Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }

    [
    Category("Behavior"),
    DefaultValue("0.00"),
    Description("Amount for subscription"),
    NotifyParentProperty(true)
    ]
    public decimal Amount
    {
        get
        {
            return amount;
        }
        set
        {
            amount = value;
        }
    }
   }

public class SubscriptionCollectionEditor : System.ComponentModel.Design.CollectionEditor
{
    public SubscriptionCollectionEditor(Type type)
        : base(type)
    {
    }

    protected override bool CanSelectMultipleInstances()
    {
        return false;
    }

    protected override Type CreateCollectionItemType()
    {
        return typeof(Subscription);
    }
}

我通过进行以下 2 处更改解决了问题。

  1. 因为像List这样的集合,.Net框架会自动显示一个合适的编辑器,所以我们不需要指定编辑器,因为集合是List类型的。所以我们不需要这个属性 Editor(typeof(SubscriptionCollectionEditor), typeof(UITypeEditor)).
  2. Subscriptions 的 setter 需要删除,只有一个 get 应该在那里,如下面的代码所示。如果使用了 setter,那么它应该像在第二个代码片段中那样使用。 但自动获取和设置不应与自定义 Web 控件中的集合 属性 一起使用

集合 属性 的最终代码应如下所示,稍后在设计时 VS 2013 中添加一个 returns 时集合不会消失。

没有 setter

的代码
private List<Subscription> list = null;

[Category("Behavior"),
 Description("The subscriptions collection"),
 DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
 PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public List<Subscription> SubscriptionList 
{ 
    get
    {
        if (lists == null)
        {
            lists = new List<Subscription>();
        }
        return lists;
    }
}

适用于 setter

的代码
[Category("Behavior"),
 Description("The subscriptions collection"),            
 DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
 PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public List<Subscription> SubscriptionList 
{ 
    get
    {
        object s = ViewState["SubscriptionList"];
        if ( s == null)
        {
            ViewState["SubscriptionList"] = new List<Subscription>();
        }
        return (List<Subscription>) ViewState["SubscriptionList"];
    }
    set
    {
        ViewState["SubscriptionList"] = value;
    }
}