簡體   English   中英

使用嵌套的可選控件創建自定義服務器控件

[英]Create a custom server control with nested optional controls

我想創建一個自定義服務器控件VersionedContentControl ,它將允許我指定最終標記的不同變體。

用法示例:

<custom:VersionedContentControl runat="server" VersionToUse="2">
    <ContentVersions>
        <Content Version="1">
            <asp:HyperLink runat="server" ID="HomeLink" NavigateUrl="~/Default.aspx">Home</asp:HyperLink>
        </Content>
        <Content Version="2">
            <asp:LinkButton runat="server" ID="HomeLink" OnClick="GoHome">Home</asp:LinkButton>
        </Content>
        <Content Version="3">
            <custom:HomeLink runat="server" ID="HomeLink" />
        </Content>
    </ContentVersions>
</custom:VersionedContentControl>

使用上面的標記,我希望頁面上將使用唯一的LinkButton控件。

很長的故事

我很難定義這個自定義控件。 我什至無法在MSDN上找到使用這樣的嵌套控件的好例子。 相反,我不得不以這些博客文章為例:

不幸的是,我嘗試過的一切都失敗了。 這是我目前擁有的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;

namespace CustomControls
{
    [ParseChildren(true)]
    [PersistChildren(false)]
    public class VersionedContentControl : Control, INamingContainer
    {
        public string VersionToUse { get; set; }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        public IList<Content> ContentVersions { get; set; }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            var controlToUse = ContentVersions.Single(x => x.Version == VersionToUse);
            Controls.Clear();
            controlToUse.InstantiateIn(this);
        }
    }

    public class Content : ITemplate
    {
        public string Version { get; set; }

        public void InstantiateIn(Control container)
        {
            // I don't know what this method should do
        }
    }

    public class ContentVersionsList : List<Content> {}
}

即使我還沒有實現InstantiateIn ,我所有內容的所有3個版本都顯示在頁面上。 它顯示3個鏈接。

另外,除非為每個嵌套控件指定不同的ID屬性值,否則我將無法使用該控件。 我不能全部使用"HomeLink" 我希望能夠重復使用ID以便可以從后面的代碼訪問控件。

我意識到,通常情況下,禁止在頁面上為多個控件指定重復的ID值。 但是,在有關System.Web.UI.MobileControls.DeviceSpecificMSDN文檔中 ,示例對嵌套控件使用重復的ID值。 實際上,該示例與我要執行的操作非常接近。 它基於移動設備兼容性過濾器而有所不同。

<mobile:Form id="Form1" runat="server">
    <mobile:DeviceSpecific Runat="server">
        <Choice Filter="isHTML32">
            <HeaderTemplate>
                <mobile:Label ID="Label1" Runat="server">
                    Header Template - HTML32</mobile:Label>
                <mobile:Command Runat="server">
                    Submit</mobile:Command>
            </HeaderTemplate>
            <FooterTemplate>
                <mobile:Label ID="Label2" Runat="server">
                    Footer Template</mobile:Label>
            </FooterTemplate>
        </Choice>
        <Choice>
            <HeaderTemplate>
                <mobile:Label ID="Label1" Runat="server">
                    Header Template - Default</mobile:Label>
                <mobile:Command ID="Command1" Runat="server">
                    Submit</mobile:Command>
            </HeaderTemplate>
            <FooterTemplate>
                <mobile:Label ID="Label2" Runat="server">
                    Footer Template</mobile:Label>
            </FooterTemplate>
        </Choice>
    </mobile:DeviceSpecific>
</mobile:Form>

最好查看這些控件的源代碼,以了解它們如何完成此操作,但是不幸的是,它不是開源的。

我的問題

如何創建一個自定義服務器控件,其中包含嵌套控件列表,並且僅基於屬性呈現一個嵌套控件? 理想情況下,在單獨的嵌套控件之間重用ID。

TL;博士

我最終使用了MultiView控件。 它不允許重復的ID,但可以滿足我的所有其他要求,並且可以避免維護任何自定義代碼。

我嘗試了什么

我終於能夠得到的東西與此代碼的工作

using System.Collections.Generic;
using System.Linq;
using System.Web.UI;

namespace CustomControls
{
    [ParseChildren(true)]
    [PersistChildren(false)]
    public class VersionedContent : Control
    {
        public string VersionToUse { get; set; }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(ContentContainer))]
        [TemplateInstance(TemplateInstance.Multiple)]
        public List<Content> ContentVersions { get; set; }

        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls();
                return base.Controls;
            }
        }

        public ContentContainer ContentContainer
        {
            get
            {
                EnsureChildControls();
                return _contentContainer;
            }
        } private ContentContainer _contentContainer;

        protected override void CreateChildControls()
        {
            var controlToUse = ContentVersions.Single(x => x.Version == VersionToUse);
            Controls.Clear();
            _contentContainer = new ContentContainer();
            controlToUse.InstantiateIn(_contentContainer);
            Controls.Add(_contentContainer);
        }
    }

    public class Content : Control, ITemplate
    {
        public string Version { get; set; }

        public void InstantiateIn(Control container)
        {
            container.Controls.Add(this);
        }
    }

    public class ContentContainer : Control { }
}

這使我可以像這樣使用控件:

<custom:VersionedContent ID="VersionedContentControl" runat="server" VersionToUse="1">
    <ContentVersions>
        <custom:Content Version="1">
            <custom:MyControlV1 runat="server" />
        </custom:Content>
        <custom:Content Version="2">
            <custom:MyControlV2 runat="server" CustomProperty="Foo" />
        </custom:Content>
    </ContentVersions>
</custom:VersionedContent>

不幸的是,該解決方案有幾個缺點。

  • 即使我使用Template實例,也不允許在單獨的“ Content部分中使用重復的ID
  • ViewState處理不正確
    • PostBack無法正常工作
    • 驗證根本不起作用

在查看了MultiView控件的反編譯源代碼(類似)之后,我意識到我必須使代碼復雜得多才能使其按需工作。 我將獲得只使用了唯一MultiView控制是可能能夠使用重復的ID, 如果我甚至可以拿到工作。 我認為最好只是使用內置的MultiView控件。

protected override void RenderContents(HtmlTextWriter output)
        {

            output.Write("<div><div class=\"UserSectionHead\">");

            Label l = new Label() { Text = Label };
            TextBox t = new TextBox() { Text = Text };
            l.AssociatedControlID = t.ID;
            l.RenderControl(output);

            output.Write("</div><div class=\"UserSectionBody\"><div class=\"UserControlGroup\"><nobr>");

            t.RenderControl(output);

            output.Write("</nobr></div></div><div style=\"width:100%\" class=\"UserDottedLine\"></div>");

        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM