vb.net - 在转发器控件中使用数据绑定表达式的自定义模板问题

时间:2013-03-11 17:46:26

标签: vb.net templates data-binding custom-controls repeater

我是新来的,但在寻找答案时,我一直在浏览stackoverflow。

问题在于:我正在尝试使用多个条件模板实现自定义转发器,以避免尽可能多地在模板中进行测试

至于现在,我的ascx代码看起来像这样:

<custom:Repeater runat="server">
    <headerTemplate>...</headerTemplate>
    <templates>
    <custom:template match="[filter1]"><contents>[filter1] is true for <%# Container.DataItem.ID%></contents></custom:template>
    <custom:template match="[filter2]"><contents>[filter2] is true for <%# Container.DataItem.ID%></contents></custom:template>
    </templates>
</custom:Repeater>

除了这个语法太冗长之外,以下代码可以正常工作

<custom:template match="[filter1]"><contents><%# TypeOf Container is IDataItemContainer%></contents></custom:template>

但是这段代码失败了

<custom:template match="[filter1]"><contents>[filter1] is true for <%# Container.DataItem.ID%></contents></custom:template>

我收到错误消息::'DataItem'不是'System.Web.UI.Control'的成员。 似乎vb尝试在编译时解析模板内容而不是数据绑定

这是我的vb类

<ParseChildren(True, "contents")>
Public Class Template : Inherits WebControl : Implements ITemplate
    Private _match As String
    <PersistenceMode(PersistenceMode.Attribute)>
    Public Property match() As String
        Get
            Return _match
        End Get
        Set(ByVal value As String)
            'TODO compile filter as an expression
            _match = value
        End Set
    End Property

    Private _source As ITemplate
    <PersistenceMode(PersistenceMode.Attribute)>
    Public Property contents() As ITemplate
        Get
            Return Nothing
        End Get
        Set(ByVal value As ITemplate)
            _source = value
        End Set
    End Property

    Public Sub InstantiateIn(container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn
        _source.InstantiateIn(container)
    End Sub
End Class

<ParseChildren(True)>
Public Class ApplyTemplate : Inherits Repeater

    _template as List(Of Template)
    <PersistenceMode(PersistenceMode.InnerProperty), TemplateContainerAttribute(GetType(Template))>
    Public Overloads Property templates() As List(Of Template)
        Get
            Return Nothing
        End Get
        Set(value As List(Of Template))
            _templates = value
        End Set
    End Property

End Class

如何在模板的内容中添加数据绑定表达式?

提前致谢。

最大

PS:是否有可能(以及如何;))压缩ascx代码,使它看起来像这样:

<custom:Repeater runat="server">
    <headerTemplate>...</headerTemplate>
    <custom:template match="[filter1]">[filter1] is true for <%# Container.DataItem.ID%></custom:template>
    <custom:template match="[filter2]">[filter2] is true for <%# Container.DataItem.ID%></custom:template>
    ...
</custom:Repeater>

1 个答案:

答案 0 :(得分:0)

最后我有时间再次研究这个问题,感谢这个链接(http://www.codeproject.com/Articles/21521/Creating-a-Templated-User-Control)我能够按照自己的意愿实现自己的自定义转发器。

所以现在aspx代码看起来像这样

<custom:Repeater runat="server" >
    <headerTemplate>...</headerTemplate>
    <separatorTemplate on="1,9">some advertisement snippet</separatorTemplate>
    <separatorTemplate every="2"><hr/></separatorTemplate>
    <itemTemplate match="[filter1]"><source>[filter1] is true for <%# Container.DataItem.ID%></source></itemTemplate>
    <itemTemplate match="[filter2]"><source>[filter2] is true for <%# Container.DataItem.ID%></source></itemTemplate>
    ...
</custom:Repeater>

如果需要,内部源标记仍然是允许模板中的代码块所必需的。 如果有人知道如何删除它并仍然使用元数据属性保留该功能,请发表评论。

所以这里的vb代码是类骨架

Public Class Repeater
    Inherits System.Web.UI.UserControl ' I use a UserControl so i can add support any html-bound attributes like class, style, data-*... without hardcoding them in the class

    Private templates As New List(Of TemplateItem)
    <PersistenceMode(PersistenceMode.InnerProperty)>
    Public WriteOnly Property itemTemplate() As TemplateItem
        Set(value As TemplateItem)
            value.Container = Me 'to bind the container to the template instead of passing the reference on instanciation
            templates.Add(value)
        End Set
    End Property

    Public Overrides Sub DataBind()
        If Not IsNothing(datasource) Then 'this to avoid nested controls Databind method to be called twice
            [... iterate on dataitems]
            [... template selection on best matching filters]
                templates.instantiateFor(dataitem) ' to instanciate the template for the current item
            [... iteration done]
            MyBase.DataBind() ' to bind the newly created controls
        End If
    End Sub
    ...
End Class

'
<ParseChildren(True, "source")>
Public Class TemplateItem
    Inherits Control

    Friend Container As Repeater

    'handle as many attributes as you want here
    Private _matchExpression As String
    <PersistenceMode(PersistenceMode.Attribute)>
    Public Property match() As String
        Get
            Return _matchExpression
        End Get
        Set(value As String)
            _matchExpression = value
        End Set
    End Property

    'Now the simple part for parsing the inner code has a template
    'I use the standard RepeaterItem class as the template container because i don't need more features for now
    Private _source As ITemplate
    <PersistenceMode(PersistenceMode.InnerDefaultProperty)>
    <TemplateContainer(GetType(RepeaterItem))>
    Public Property source() As ITemplate
        Get
            Return _source
        End Get
        Set(value As ITemplate)
            _source = value
        End Set
    End Property

    'now the part to instantiate as template for a given item
    Public Sub instantiateFor(Item As Object, Optional itemIndex As Integer = -1)
        Dim instantiator = New RepeaterItem(itemIndex, ListItemType.Item)
        instantiator.DataItem = Item
        _source.InstantiateIn(instantiator)
        Container.Controls.Add(instantiator)
    End Sub
End Class

Etvoilà...终于!! 希望这会有所帮助