如何将集合(例如动态数组)作为自定义ASP.NET控件的属性添加?

3

我正在尝试为可放置在设计师面板上的复合控件添加动态可扩展属性。我已经尝试使用字符串数组、列表和数组列表来实现,但是都没有得到理想的结果。我感觉自己缺少了什么重要信息。以下是我认为相关的代码:

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
    NotifyParentProperty(true),
    PersistenceMode(PersistenceMode.InnerProperty)]
    public String[] AccessLevels
    {
        get
        {
            String[] s = (String[])ViewState["AccessLevels"];
            return s;
        }

        set
        {
            ViewState["AccessLevels"] = value;
        }
    }

控件编译正常,我可以将其拖放到设计师界面上。在Visual Studio 2008的“属性”窗口中,它给了我一个名为“+AccessLevels”的属性,值为“String[] Array”,旁边有一个省略号[...]。如果我点击省略号,它会打开一个编辑器,让我逐行插入属性。如果我点击“AccessLevels”属性旁边的加号符号,它会显示我输入的属性,并且每个属性旁边都有一个数字,表示数组的索引。太好了!但是,无论我输入什么值作为属性,设计师都会自动生成以下HTML代码。
    <cc2:HBAdmin ID="HBAdmin1" runat="server">
        <AccessLevels>
        <system.string></system.string>
        <system.string></system.string>
        <system.string></system.string>
        </AccessLevels>
    </cc2:HBAdmin>

HBAdmin是我的控件名称,cc2命名空间是正确的。问题在于标签中。里面应该有一个值,对吗?我还得到了<AccessLevels>标签的智能感知提示“元素'AccessLevels'的开放和闭合标记之间不允许内容”,以及<system.string>标签的验证错误,提示“不支持元素'System.String'”。然后,如果我尝试在浏览器中查看带有控件的页面(在编辑设计窗口中的属性导致上述标记),我会在控件的开放标记所在行上得到以下错误:

"数组创建必须具有数组大小或数组初始化程序"

只有当我尝试在设计器的属性窗口中编辑属性时才会出现此错误。我可以在构造函数中填充属性值,并且带有控件的页面将在浏览器中加载并正常工作,属性窗口中的值也显示正常,我可以在整个控件中使用这些值,但我无法在属性窗口中编辑它们。如果我尝试添加一个,我会得到与上述描述相同的症状。

我觉得我可能只是缺少某种属性或声明或其他东西。请帮忙解决?

2个回答

4
您可以使用Collection<string>代替string[]

1

尝试类似以下的内容:

用法:

<cc:SomeClass >
 <CustomLavel key="" value="" />
 <CustomLavel key="" value="" />
 <CustomLavel key="" value="" />
</cc:SomeClass>


public class SomeClass: Control, INamingContainer
{
           private Collection<CustomLabel> _customLabelList;

           protected override void AddParsedSubObject(object obj)
        {
            base.AddParsedSubObject(obj);

            if (obj is CustomLabel)
            {
                _customLabelList.Add((CustomLabel)obj);
                return;
            }
        }

[Category("Behavior")]
        [Description("The fields collection")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]    
        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        [DefaultValue(null), MergableProperty(false), Bindable(false)]
        public Collection<CustomLabel> CustomLabelList
        {
            get
            {
                return _customLabelList;
            }
        }
}

[TypeConverter(typeof(ExpandableObjectConverter))]
public class CustomLabel
{
    private string _key;
    private string _value;

    public CustomLabel()
        : this(string.Empty, string.Empty)
    {
    }

    public CustomLabel(string key, string value)
    {
        _key = key;
        _value = value;
    }


    [Category("Behavior")]
    [DefaultValue("")]
    [Description("Key")]
    [NotifyParentProperty(true)]
    public string Key
    {
        get
        {
            return _key;
        }
        set
        {
            _key = value;
        }
    }

    [Category("Behavior")]
    [DefaultValue("")]
    [Description("Value")]
    [NotifyParentProperty(true)]
    public string Value
    {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
        }
    }
}

我正在尝试使用这段代码,但我不理解重写的AddParsedSubObject方法。_customLabelList是什么,它在哪里定义?"SomeClass"是定义我的组合控件的类,还是定义保存我的数据的类型,还是只是作为示例使用,我需要用我的组合控件替换它? - Camenwolf
啊,抱歉 customLabelList 是一个私有字段,我会编辑回答。SomeClass 是你将要放在页面上的控件。你需要根据自己的需求替换我的代码。这是我在一个网站上使用的示例。 - skyfoot
当我在设计器中为属性分配值时,它们似乎有效,但是当我退出设计器时,它们不会显示在属性窗口中,也不会持久化。此外,我尝试在构造函数中添加一些默认值,例如this.AddParsedSubObject(new CustomLabel("thiskey", "thatvalue"));然后当我将ctrl拖放到设计器上时,我会收到“对象引用未设置为对象的实例”的错误。所以我尝试实例化对象并分配它,然后在调用AddParsedSubObject时使用该实例。同样的问题。 - Camenwolf
此外,在这里是否可能只使用动态字符串数组而不是自定义类型? - Camenwolf
我感觉我快要成功了。现在我可以在设计器中添加和删除属性,但是当我这样做后在浏览器中查看页面时,会出现以下错误:类型“SomeNamespace.SomeControl”没有名为“CustomLabel”的公共属性。我仍然会收到关于<CustomLabel value="somevalue></CustomLabel>标记的验证错误。 - Camenwolf
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接