Пользовательское управление контейнером ASP.NET

Я пытаюсь создать настраиваемый элемент управления, который работает точно так же, как и элемент управления Panel, за исключением окружения нескольких div и т.д., чтобы создать округленный вид окна. Я не смог найти достойный пример того, как это сделать.

Мне нужно иметь возможность размещать текст и элементы управления внутри элемента управления и обращаться к нему напрямую, не ссылаясь на панель (точно так же, как работает панель управления).

Есть ли у кого-нибудь примеры этого?

Ответы

Ответ 1

Существует два способа сделать это. Один из них - реализовать INamingContainer под вашим контролем, и это требует больших усилий.

Другой способ - наследовать от Panel и переопределить методы RenderBeginTag и RenderEndTag, чтобы добавить вашу собственную разметку. Это легко.

public class RoundedCornersPanel : System.Web.UI.WebControls.Panel
{
    public override RenderBeginTag (HtmlTextWriter writer)
    {
        writer.Write("Your rounded corner opening markup");
        base.RenderBeginTag(writer);
    }

    public override RenderEndTag (HtmlTextWriter writer)
    {
        base.RenderEndTag(writer);
        writer.Write("Your rounded corner closing markup");                     
    }
}

Ответ 2

Здесь уже немало ответов, но я просто хотел вставить самую основную реализацию этого без наследования класса Panel. Итак, вот оно:

using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;

[ToolboxData("<{0}:SimpleContainer runat=server></{0}:SimpleContainer>")]
[ParseChildren(true, "Content")]
public class SimpleContainer : WebControl, INamingContainer
{
    [PersistenceMode(PersistenceMode.InnerProperty)]
    [TemplateContainer(typeof(SimpleContainer))]
    [TemplateInstance(TemplateInstance.Single)]
    public virtual ITemplate Content { get; set; }

    public override void RenderBeginTag(HtmlTextWriter writer)
    {
        // Do not render anything.
    }

    public override void RenderEndTag(HtmlTextWriter writer)
    {
        // Do not render anything.
    }

    protected override void RenderContents(HtmlTextWriter output)
    {
        output.Write("<div class='container'>");
        this.RenderChildren(output);
        output.Write("</div>");
    }

    protected override void OnInit(System.EventArgs e)
    {
        base.OnInit(e);

        // Initialize all child controls.
        this.CreateChildControls();
        this.ChildControlsCreated = true;
    }

    protected override void CreateChildControls()
    {
        // Remove any controls
        this.Controls.Clear();

        // Add all content to a container.
        var container = new Control();
        this.Content.InstantiateIn(container);

        // Add container to the control collection.
        this.Controls.Add(container);
    }
}

Затем вы можете использовать его следующим образом:

<MyControls:SimpleContainer
    ID="container1"
    runat="server">
    <Content>
        <asp:TextBox
            ID="txtName"
            runat="server" />

        <asp:Button
            ID="btnSubmit"
            runat="server"
            Text="Submit" />
    </Content>
</MyControls:SimpleContainer>

И от codebehind вы можете делать такие вещи:

this.btnSubmit.Text = "Click me!";
this.txtName.Text = "Jack Sparrow";

Ответ 3

Создайте класс, наследующий System.Web.UI.Control, и переопределите метод Render (HtmlTextWriter). В этом методе визуализируйте окружающие начальные теги, затем отрисуйте дочерние элементы (RenderChildren), затем визуализируйте теги конца.

protected override void Render ( HtmlTextWriter output )
{
  output.Write ( "<div>" );
  RenderChildren ( output );
  output.Write ( "</div>" );
}

Округлые углы обычно достигаются с помощью CSS и угловых изображений для верхних левых, верхних правых, нижних левых и нижних правых углов. Это можно сделать, используя 4 вложенных divs, действующих как слои, каждый из которых имеет одно угловое изображение в качестве фонового изображения.

Ответ 5

Если вы не хотите наследовать напрямую из WebControl, а не из Panel, самый простой способ сделать это - украсить класс атрибутом [ParseChildren(false)]. Хотя на первый взгляд это может означать, что вы не хотите разбирать детей, то, что на самом деле указывает false, заключается в том, что вы не хотите, чтобы дети рассматривались как свойства. Вместо этого вы хотите, чтобы к ним относились как к элементам управления.

Используя этот атрибут, вы получаете практически все функциональные возможности:

[ToolboxData("<{0}:RoundedBox runat=server></{0}:RoundedBox>")]
[ParseChildren(false)]
public class RoundedBox : WebControl, INamingContainer
{
    public override void RenderBeginTag(HtmlTextWriter writer)
    {
        writer.Write("<div class='roundedbox'>");
    }

    public override void RenderEndTag(HtmlTextWriter writer)
    {
        writer.Write("</div>");
    }
}

Это позволит вам добавлять элементы RoundedBox на свои страницы и добавлять дочерние элементы (либо asp.net controls, либо raw html), которые будут отображаться внутри вашего div.

Конечно, css будет добавлен для правильного стиля класса roundedbox.

Ответ 6

Еще одна вещь, которую вы можете использовать: закругленный угловой расширитель в ASP.NET-пакете ajax.

Я знаю, что это не то, что вы просили, но вам не нужно писать какой-либо пользовательский код.

Надеюсь, что это поможет!

Ответ 7

Я просмотрел этот вопрос, потому что хотел создать панель компоновки с двумя столбцами. (не совсем, но это гораздо более простой пример того, что мне нужно. Я разделяю решение, которое я закончил, используя:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Syn.Test
{
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:MultiPanel runat=server></{0}:MultiPanel>")]
    [ParseChildren(true)]
    [PersistChildren(false)]
    public class MultiPanel : WebControl, INamingContainer
    {
        public ContentContainer LeftContent { get; set; }

        public ContentContainer RightContent { get; set; }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
        }

        protected override void Render(HtmlTextWriter output)
        {
            output.AddStyleAttribute("width", "600px");
            output.RenderBeginTag(HtmlTextWriterTag.Div);

            output.AddStyleAttribute("float", "left");
            output.AddStyleAttribute("width", "280px");
            output.AddStyleAttribute("padding", "10px");
            output.RenderBeginTag(HtmlTextWriterTag.Div);
            LeftContent.RenderControl(output);
            output.RenderEndTag();

            output.AddStyleAttribute("float", "left");
            output.AddStyleAttribute("width", "280px");
            output.AddStyleAttribute("padding", "10px");
            output.RenderBeginTag(HtmlTextWriterTag.Div);
            RightContent.RenderControl(output);
            output.RenderEndTag();

            output.RenderEndTag();
         }
    }

    [ParseChildren(false)]
    public class ContentContainer : Control, INamingContainer
    {
    }
}

Проблема, которую я все еще имею, заключается в том, что intellisense не работает в этом сценарии, она не будет предлагать теги Left и Right Content.

Ответ 8

public class myCustomPanel : Panel
{
    public override void RenderBeginTag(HtmlTextWriter writer)
    {
        writer.AddAttribute(HtmlTextWriterAttribute.Class, "top_left_corner");
        writer.RenderBeginTag(HtmlTextWriterTag.Div);
            base.RenderBeginTag(writer);
    }

    public override void RenderEndTag(HtmlTextWriter writer)
    {
            base.RenderEndTag(writer);
        writer.RenderEndTag();
    }

}