在Web用户控件中传递int数组作为参数

24
我有一个int数组作为Web用户控件的属性。如果可能的话,我想使用以下语法来内联设置该属性:

我有一个int数组作为Web用户控件的属性。如果可能的话,我想使用以下语法来内联设置该属性:

<uc1:mycontrol runat="server" myintarray="1,2,3" />

由于传递的是字符串而不是实际的整数数组,因此此代码将在运行时失败。我可以将myintarray转换为字符串并在setter中解析它,但我想知道是否有更优雅的解决方案。

11个回答

20

实现类型转换器,这里有一个示例,警告:快速且不完美,不能用于生产等:

public class IntArrayConverter : System.ComponentModel.TypeConverter
{
    public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string);
    }
    public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        string val = value as string;
        string[] vals = val.Split(',');
        System.Collections.Generic.List<int> ints = new System.Collections.Generic.List<int>();
        foreach (string s in vals)
            ints.Add(Convert.ToInt32(s));
        return ints.ToArray();
    }
}

并为您的控件打上标签:

private int[] ints;
[TypeConverter(typeof(IntsConverter))]
public int[] Ints
{
    get { return this.ints; }
    set { this.ints = value; }
}

我添加了一个编译的示例。谢谢! - ern

6

@mathieu,非常感谢您的代码。我稍微修改了一下以便进行编译:

public class IntArrayConverter : System.ComponentModel.TypeConverter
{
    public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string);
    }
    public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        string val = value as string;
        string[] vals = val.Split(',');
        System.Collections.Generic.List<int> ints = new System.Collections.Generic.List<int>();
        foreach (string s in vals)
            ints.Add(Convert.ToInt32(s));
        return ints.ToArray();
    }
}

1
我修复了原始答案,如果您愿意,可以删除这个答案。 - juan

5

我认为,从逻辑上来说——也更具扩展性——应该借鉴asp:列表控件的做法:

<uc1:mycontrol runat="server">
    <uc1:myintparam>1</uc1:myintparam>
    <uc1:myintparam>2</uc1:myintparam>
    <uc1:myintparam>3</uc1:myintparam>
</uc1:mycontrol>

1
谢谢。这可能有效,但需要很多额外的代码。我尽量保持尽可能简约。 - ern

4

很棒的代码片段@mathieu。我需要将长整型转换,但是我没有编写LongArrayConverter,而是编写了一个使用泛型的版本。

public class ArrayConverter<T> : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        string val = value as string;
        if (string.IsNullOrEmpty(val))
            return new T[0];

        string[] vals = val.Split(',');
        List<T> items = new List<T>();
        Type type = typeof(T);
        foreach (string s in vals)
        {
            T item = (T)Convert.ChangeType(s, type);
            items.Add(item);
        }
        return items.ToArray();
    }
}

这个版本应该适用于任何可以从字符串转换的类型。
[TypeConverter(typeof(ArrayConverter<int>))]
public int[] Ints { get; set; }

[TypeConverter(typeof(ArrayConverter<long>))]
public long[] Longs { get; set; }

[TypeConverter(typeof(ArrayConverter<DateTime))]
public DateTime[] DateTimes { get; set; }

2

2
您还可以像这样做:
namespace InternalArray
{
    /// <summary>
    /// Item for setting value specifically
    /// </summary>

    public class ArrayItem
    {
        public int Value { get; set; }
    }

    public class CustomUserControl : UserControl
    {

        private List<int> Ints {get {return this.ItemsToList();}
        /// <summary>
        /// set our values explicitly
        /// </summary>
        [PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(List<ArrayItem>))]
        public List<ArrayItem> Values { get; set; }

        /// <summary>
        /// Converts our ArrayItem into a List<int> 
        /// </summary>
        /// <returns></returns>
        private List<int> ItemsToList()
        {
            return (from q in this.Values
                    select q.Value).ToList<int>();
        }
    }
}

这将导致:
<xx:CustomUserControl  runat="server">
  <Values>
            <xx:ArrayItem Value="1" />
  </Values>
</xx:CustomUserControl>

1

要添加元素到您的列表,您需要按照特定的方式设置您的控件:

[ParseChildren(true, "Actions")]
[PersistChildren(false)]
[ToolboxData("<{0}:PageActionManager runat=\"server\" ></PageActionManager>")]
[NonVisualControl]
public class PageActionManager : Control
{

上面的 Actions 是子元素所在的 cproperty 名称。我使用 ArrayList,因为我还没有用其他东西进行测试。
        private ArrayList _actions = new ArrayList();
    public ArrayList Actions
    {
        get
        {
            return _actions;
        }
    }

当你的控件初始化时,它将具有子元素的值。你可以创建一个仅包含整数的小型类。


0

要做Bill所说的关于列表的事情,您只需要在用户控件上创建一个List属性。然后,您可以按照Bill所描述的实现它。


0
你可以实现一个类型转换器类,用于在 int 数组和字符串数据类型之间进行转换。 然后使用 TypeConverterAttribute 对你的 int 数组属性进行装饰,指定你实现的类。Visual Studio 将会在你的属性上使用你的类型转换器进行类型转换。

0

您可以在aspx文件中添加类似以下代码的页面事件:

<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
    YourUserControlID.myintarray = new Int32[] { 1, 2, 3 };
}
</script>

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