如何创建模拟 switch/case 的 ASP.NET 控件?

发布于 2024-08-05 03:02:46 字数 1120 浏览 1 评论 0原文

我有一个中继器循环遍历不同类型的对象列表。我想根据对象的类型以不同的方式渲染它们。为此,我需要某种具有类似于 switch/case 语句行为的控制(因为我想避免使用隐藏代码)。基本上它可能看起来像这样:

<xxx:TestType Object='<%# Container.DataItem %>'>
    <Case Type="Namespace.ClassX">
        <asp:Label ... />
    </Case>
    <Case Type="Namespace.ClassY">
        <asp:TextBox ... />
    </Case>
    <Default>
        <p>Other</p>
    </Default>
</xxx:TestType>

我以前制作过 Web 控件,但这是一个相当复杂的控件...

  • 如何使其支持多个 元素?
  • 是否可以实现 元素,或者我是否仅限于无属性元素?

我猜我必须为 元素创建一个类型,并以某种方式为主 Web 控件指定它?

如果有任何指示、教程链接等,我将不胜感激!

替代方案

或者,建议一种更好的方法来根据当前绑定对象的类型呈现不同的 HTML/ASP.NET 控件。我脑海中闪现的第一个方法是这个,我认为它(非常)丑陋:

<asp:PlaceHolder Visible='<%# CheckType(Container, typeof(ClassX)) %>' runat="server">
...
</asp:PlaceHolder>
<asp:PlaceHolder Visible='<%# CheckType(Container, typeof(ClassY)) %>' runat="server">
...
</asp:PlaceHolder>

I've got a repeater looping through a list of objects that are of different types. I'd like to render the objects differently depending on their type. For this I need some kind of control (since I want to avoid using the code-behind) that has a behavior similar to a switch/case statement. Basically it could look like this:

<xxx:TestType Object='<%# Container.DataItem %>'>
    <Case Type="Namespace.ClassX">
        <asp:Label ... />
    </Case>
    <Case Type="Namespace.ClassY">
        <asp:TextBox ... />
    </Case>
    <Default>
        <p>Other</p>
    </Default>
</xxx:TestType>

I've made web controls before, but this is a rather complex one...

  • How do I make it support multiple <Case> elements?
  • Is it possible to implement the <Case Type="..."> elements, or am I limited to attribute-less elements?

I'm guessing I have to make a type for the <Case> elements and somehow specifying it for the main web control?

I'd be grateful for any pointers, links to tutorials, etc!

Alternative

Alternatively, suggest a nicer way of rendering different HTML/ASP.NET controls based on the type of the currently bound object. The first method that popped into my head was this, which I consider (very) ugly:

<asp:PlaceHolder Visible='<%# CheckType(Container, typeof(ClassX)) %>' runat="server">
...
</asp:PlaceHolder>
<asp:PlaceHolder Visible='<%# CheckType(Container, typeof(ClassY)) %>' runat="server">
...
</asp:PlaceHolder>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

守望孤独 2024-08-12 03:02:46

MultiView 控件是最接近的ASP.NET 中现成的东西转换为 C# switch 语句。

The MultiView control is the closest thing out-of-the-box in ASP.NET to a C# switch statement.

说不完的你爱 2024-08-12 03:02:46

查看实现 ITemplate 接口

  public class Case        
    {

        [PersistenceMode(PersistenceMode.Attribute)]
        public string Type { get; set; }

        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public ITemplate Template { get; set; }

    }

    public class DeclarativeCase
        : CompositeControl
    {
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public List<Case> Cases { get; set; }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate Default { get; set; }
    }

<xxx:DeclarativeCase runat="server" ID="test">
  <Cases>
   <xxx:Case Type="Namespace.TypeName">
    <Template>
     <asp:Label ID="Label1" runat="server"></asp:Label>
    </Template>
   </xxx:Case>
  </Cases>

<Default>
 <asp:Label ID="Label2" runat="server"></asp:Label>
</Default>

</xxx:DeclarativeCase>

Look at implementing ITemplate interface

  public class Case        
    {

        [PersistenceMode(PersistenceMode.Attribute)]
        public string Type { get; set; }

        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public ITemplate Template { get; set; }

    }

    public class DeclarativeCase
        : CompositeControl
    {
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public List<Case> Cases { get; set; }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate Default { get; set; }
    }

<xxx:DeclarativeCase runat="server" ID="test">
  <Cases>
   <xxx:Case Type="Namespace.TypeName">
    <Template>
     <asp:Label ID="Label1" runat="server"></asp:Label>
    </Template>
   </xxx:Case>
  </Cases>

<Default>
 <asp:Label ID="Label2" runat="server"></asp:Label>
</Default>

</xxx:DeclarativeCase>
吃兔兔 2024-08-12 03:02:46

为什么不放弃服务器控件并使用 C# switch 语句。您所需要做的就是将其包装在代码标签中。

另一种方法是迭代(for 循环)。创建一个具有类型属性和渲染方法的接口。然后迭代接口,直到找到正确的类型。

Why don't you ditch the server control and use the C# switch statement. All you need is to wrap it in the code tags.

Another approach is a iteration (for loop). Create an interface with a type property and a render method. Then iterate over the interfaces until you've found the correct type.

终难遇 2024-08-12 03:02:46

不久前我有类似的要求,我做了类似的事情:

[ParseChildren(true, "Templates")]
public class TypedRepeater : CompositeDataBoundControl
{
    [
    PersistenceMode(PersistenceMode.InnerProperty),
    Browsable(false),
    MergableProperty(false)
    ]
    public TypedTemplateCollection Templates
    {
        get;
    }

protected TypedTemplate GetTemplate(object dataItem)
{
如果(数据项==空)
{
返回空值;
}
foreach(模板中的TypedTemplate模板)
{
类型 itemType = dataItem.GetType();
if (dataItem.IsAssignableFrom(template.Type))
{
返回模板;
}
}
返回空值;
其中

    protected TypedTemplateRepeaterItem CreateItem(int index, object dataItem, bool dataBinding)
    {
        TypedTemplateRepeaterItem repeaterItem = new TypedTemplateRepeaterItem();
        if ((!dataBinding) && (ViewState[string.Format("TemplateIxc_{0}", index)] is int))
        {
            int _template = (int)ViewState[string.Format("TemplateIxc_{0}", index)];
            if ((_template >= 0) && (_template < Templates.Count) && (Templates[_template].ItemTemplate != null))
            {
                Templates[_template].ItemTemplate.InstantiateIn(repeaterItem);
            }
            else
            {
                DefaultTemplate.InstantiateIn(repeaterItem);
            }
        }
        else if (dataBinding)
        {
            TypedTemplate template = GetTemplate(dataItem);
            ITemplate itemTemplate = DefaultTemplate;
            if (template != null)
            {
                itemTemplate = template.ItemTemplate;
                ViewState[string.Format("TemplateIxc_{0}", index)] = Templates.IndexOf(template);
            }
            else
            {
                ViewState[string.Format("TemplateIxc_{0}", index)] = -1;
            }

            repeaterItem.DataItem = dataItem;
            repeaterItem.DataItemIndex =
                repeaterItem.DisplayIndex = index;
            itemTemplate.InstantiateIn(repeaterItem);
            repeaterItem.DataBind();
            repeaterItem.DataItem = null;
        }
        return repeaterItem;
    }

    protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
    {
        int count = 0;
        if (dataSource != null)
        {
            foreach (object dataItem in dataSource)
            {
                TypedTemplateRepeaterItem repeaterItem = CreateItem(count, dataItem, dataBinding);      
                Controls.Add(repeaterItem);
                count++;
            }
        }
        return count;
    }
}

TypedTemplateCollection 是 TypedTemplate 类的 StateManagedCollection:

[ParseChildren(true, "ItemTemplate")]
public class TypedTemplate
{

    public Type Type
    {
        get { return Type.GetType(TypeName); }
    }

    [
    PersistenceMode(PersistenceMode.Attribute),
    Browsable(true),
    DefaultValue("")
    ]
    public string TypeName
    {
        get;
        set;
    }

    [
    PersistenceMode(PersistenceMode.InnerProperty),
    Browsable(true),
    DefaultValue(typeof(ITemplate), null),
    TemplateContainer(typeof(TypedTemplateRepeaterItem))
    ]
    public ITemplate ItemTemplate
    {
        get;
        set;
    }
}

并且 TypedTemplateRepeaterItem 是:

public class TypedTemplateRepeaterItem : WebControl, INamingContainer, IDataItemContainer
{
    #region IDataItemContainer Members

    public object DataItem
    {
        get;
        set;
    }

    public int DataItemIndex
    {
        get;
        set;
    }

    public int DisplayIndex
    {
        get;
        set;
    }

    #endregion
}

I had a similar requirement a while ago and I did something similar to:

[ParseChildren(true, "Templates")]
public class TypedRepeater : CompositeDataBoundControl
{
    [
    PersistenceMode(PersistenceMode.InnerProperty),
    Browsable(false),
    MergableProperty(false)
    ]
    public TypedTemplateCollection Templates
    {
        get;
    }

protected TypedTemplate GetTemplate(object dataItem)
{
if (dataItem == null)
{
return null;
}
foreach (TypedTemplate template in Templates)
{
Type itemType = dataItem.GetType();
if (dataItem.IsAssignableFrom(template.Type))
{
return template;
}
}
return null;
}

    protected TypedTemplateRepeaterItem CreateItem(int index, object dataItem, bool dataBinding)
    {
        TypedTemplateRepeaterItem repeaterItem = new TypedTemplateRepeaterItem();
        if ((!dataBinding) && (ViewState[string.Format("TemplateIxc_{0}", index)] is int))
        {
            int _template = (int)ViewState[string.Format("TemplateIxc_{0}", index)];
            if ((_template >= 0) && (_template < Templates.Count) && (Templates[_template].ItemTemplate != null))
            {
                Templates[_template].ItemTemplate.InstantiateIn(repeaterItem);
            }
            else
            {
                DefaultTemplate.InstantiateIn(repeaterItem);
            }
        }
        else if (dataBinding)
        {
            TypedTemplate template = GetTemplate(dataItem);
            ITemplate itemTemplate = DefaultTemplate;
            if (template != null)
            {
                itemTemplate = template.ItemTemplate;
                ViewState[string.Format("TemplateIxc_{0}", index)] = Templates.IndexOf(template);
            }
            else
            {
                ViewState[string.Format("TemplateIxc_{0}", index)] = -1;
            }

            repeaterItem.DataItem = dataItem;
            repeaterItem.DataItemIndex =
                repeaterItem.DisplayIndex = index;
            itemTemplate.InstantiateIn(repeaterItem);
            repeaterItem.DataBind();
            repeaterItem.DataItem = null;
        }
        return repeaterItem;
    }

    protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
    {
        int count = 0;
        if (dataSource != null)
        {
            foreach (object dataItem in dataSource)
            {
                TypedTemplateRepeaterItem repeaterItem = CreateItem(count, dataItem, dataBinding);      
                Controls.Add(repeaterItem);
                count++;
            }
        }
        return count;
    }
}

where TypedTemplateCollection is a StateManagedCollection of a TypedTemplate class:

[ParseChildren(true, "ItemTemplate")]
public class TypedTemplate
{

    public Type Type
    {
        get { return Type.GetType(TypeName); }
    }

    [
    PersistenceMode(PersistenceMode.Attribute),
    Browsable(true),
    DefaultValue("")
    ]
    public string TypeName
    {
        get;
        set;
    }

    [
    PersistenceMode(PersistenceMode.InnerProperty),
    Browsable(true),
    DefaultValue(typeof(ITemplate), null),
    TemplateContainer(typeof(TypedTemplateRepeaterItem))
    ]
    public ITemplate ItemTemplate
    {
        get;
        set;
    }
}

and TypedTemplateRepeaterItem is:

public class TypedTemplateRepeaterItem : WebControl, INamingContainer, IDataItemContainer
{
    #region IDataItemContainer Members

    public object DataItem
    {
        get;
        set;
    }

    public int DataItemIndex
    {
        get;
        set;
    }

    public int DisplayIndex
    {
        get;
        set;
    }

    #endregion
}
丶视觉 2024-08-12 03:02:46

MSDN 网站有一个简单清晰的模板示例,它看起来确实适合您的情况。

The MSDN site has a simple clear example of templating and it certainly seems like the way to go in your case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文