【问题标题】:Asp.Net Custom Control design time questionAsp.Net 自定义控件设计时间问题
【发布时间】:2010-02-09 18:16:03
【问题描述】:

我正在开发一组自定义控件,其中一个是“父级”,任何其他控件都必须添加到该父级的 ITemplate 属性中。

但是在页面中,在设计时,我可以通过智能感知看到页面级别的其他控件,理论上我可以将它们添加到任何地方。

我想模拟asp:Table和asp:TableRow的行为,不能直接在asp:Table之外添加asp:TableRow...

有没有办法做到这一点? 非常感谢!

编辑:我已经通过 KP 建议部分解决了问题,但如果您在评论中阅读,这不是“真正”的方法(我认为)。 没有人知道该怎么做吗? :(

【问题讨论】:

    标签: asp.net custom-controls web-controls


    【解决方案1】:

    我根据我们的讨论编辑了整个答案。这是一个有效且经过测试的示例。我们有以下两个控件 - ParentControlChildControlParentControl 通过 Intellisense 可见,其中 ChildControl 仅作为 ParentControl 的子级可见。出于简单的渲染目的,孩子渲染为 li 标签并输出他们的“文本”属性。父控件确保每个子控件在其自己的RenderContents 事件期间被要求呈现。

    儿童控制:

    using System.ComponentModel;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace TestControls
    {
        [ToolboxItem(false), Bindable(false)]
        public class ChildControl : WebControl
        {
            protected override void Render(System.Web.UI.HtmlTextWriter writer)
            {
                base.Render(writer);
    
                //render the text property as a list item for example's sake
                writer.RenderBeginTag(HtmlTextWriterTag.Li);
                writer.Write(this.Text);
                writer.RenderEndTag();
            }
    
            [Browsable(true)]
            public string Text { get; set; }
        }
    }
    

    家长控制:

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace TestControls
    {
        [ToolboxData("<{0}:ParentControl runat=\"server\"></{0}:ParentControl>")]
        [DefaultProperty("Children"), ParseChildren(true, "Children")]
        public class ParentControl : WebControl
        {
            private List<ChildControl> _children;
    
            protected override void RenderContents(HtmlTextWriter writer)
            {
                base.RenderContents(writer);
    
                //create a div, and write some sample text
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.Write("Parent Control. Children:");
    
                //create a ul, and ask each child control to render
                writer.RenderBeginTag(HtmlTextWriterTag.Ul);
    
                foreach (ChildControl child in _children)
                {
                    child.RenderControl(writer);
                }
    
                //close all tags
                writer.RenderEndTag();
                writer.RenderEndTag();
            }
    
            [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
            public virtual List<ChildControl> Children
            {
                get
                {
                    if (_children == null)
                        _children = new List<ChildControl>();
    
                    return _children;
                }
            }
        }
    }
    

    在我的标记中,我通过命名空间注册了控件:

    <%@ Register TagPrefix="test" Namespace="TestControls" %>
    

    然后添加一些标记:

    <test:ParentControl ID="test" runat="server">
        <test:ChildControl ID="child" Text="Hello World from Child 1" runat="server" />
        <test:ChildControl ID="child2" Text="Hello World from Child 2" runat="server" />
    </test:ParentControl>
    

    在上面的标记中,Intellisense 拾取外部父控件,但看不到子控件。一旦光标位于父控件内,Intellisense 就会根据需要选择 ChildControl 标记。

    最终输出为:

    家长控制。孩子们:

    * Hello World from Child 1
    * Hello World from Child 2
    

    另外,这里有一个good article on how the whole intellisence creation works,我按照它来创建上面的。

    我希望这会有所帮助。您仍然需要以您认为适合您的特定控件的方式处理子控件级别的渲染,但是上面的内容可以帮助您入门并且确实满足工作 Intellisense 模型的需要。

    【讨论】:

    • 我添加了 [ToolboxItem(false)] 到我的子控件,然后我将其作为父控件的属性公开了属性 [PersistenceMode(PersistenceMode.InnerProperty)]。我认为这不是“正确”的做法,但目前是唯一能做到这一点的方法......
    • 为什么这是“不正确”的方式?我相信你在正确的轨道上。另一个使用相同属性的示例:robertwray.co.uk/blog/2008/02/…
    • 因为这样我的子控件不会自动渲染自己,这是他父级的简单属性,我必须在父级实现渲染逻辑......老实说,我没有不了解 asp:TableRow 和 asp:Table 的工作原理,我在反射器中看到了它们的代码,但我没有找到使 TableRow 在 Table 之外不可见的原因....
    • @tanathos - 很公平。我编辑了答案,并带有一个很好的链接,描述了智能感知是如何生成的。 ToolboxItem 看起来是您在标记中隐藏控件的顶级可见性所需的唯一属性。
    • 是的,它似乎涉及到 ToolBoxItem。如果我将其设置为 false,则子控件不会出现在 intellisense(根本)上,但该控件可以工作,它会在 html 上呈现,即使 VS 无法识别该标签。但是我已经尝试了每一种组合,我不能让它只出现在父控件上......似乎什么都没有......最后我认为现在我将实现一个基于属性的渲染系统。无论如何,感谢您花时间帮助我!
    【解决方案2】:

    我以前做过,但我没有可用的代码。我可以告诉你,我通过在内置 ASP.NET Datagrid 控件上使用 Reflector 解决了这个问题。我能够对“包含”(“行”)和“容器”(“网格”)之间的关系进行逆向工程。您必须使用属性以非常特定的方式将类排列在一起。

    【讨论】:

      猜你喜欢
      • 2010-12-22
      • 1970-01-01
      • 1970-01-01
      • 2013-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-13
      • 2021-02-10
      相关资源
      最近更新 更多