Pregunta

He estado tratando de crear un control personalizado que funcione exactamente como el control del Panel, excepto rodeado por unos pocos divs y demás para crear un aspecto de cuadro redondeado. No he podido encontrar un ejemplo decente de cómo hacer esto.

Necesito poder colocar texto y controles dentro del control y acceder a él directamente sin hacer referencia al panel (exactamente como funciona el control del Panel).

¿Alguien tiene algún ejemplo de esto?

¿Fue útil?

Solución

Hay dos formas de hacer esto. Una es implementar INamingContainer bajo su control, y requiere mucho esfuerzo.

La otra forma es heredar del Panel y anular los métodos RenderBeginTag y RenderEndTag para agregar su marcado personalizado. Esto es fácil.

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");                     
    }
}

Otros consejos

Ya hay bastantes respuestas aquí, pero solo quería pegar la implementación más básica de esto sin heredar de la clase Panel. Así que aquí va:

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);
    }
}

Entonces puedes usarlo así:

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

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

Y desde el código subyacente puede hacer cosas como esta:

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

Cree una clase que herede System.Web.UI.Control y anule el método Render (HtmlTextWriter). En este método, renderice las etiquetas de inicio circundantes, luego renderice los elementos secundarios (RenderChildren), luego renderice las etiquetas de finalización.

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

Las esquinas redondeadas generalmente se logran utilizando CSS e imágenes de esquina para las esquinas superior izquierda, superior derecha, inferior izquierda e inferior derecha. Se podría hacer usando 4 divisiones anidadas, actuando como capas, cada una de ellas con una imagen de esquina como imagen de fondo.

El proyecto de código tiene algo que podría interesarle: Panel Curve Container - Un ASP .NET Nugget de control personalizado . Estoy seguro de que puedes jugar con el código y tener el comportamiento y la apariencia que deseas.

texto alternativo ??

Si no desea heredar directamente de WebControl en lugar de Panel, la forma más fácil de hacerlo es decorar la clase con el atributo [ParseChildren (false)] . Aunque a primera vista esto podría sugerir que no desea analizar los elementos secundarios, lo que el false realmente indica es que no desea que los elementos secundarios sean tratados como propiedades. En cambio, desea que se traten como controles.

Al usar este atributo, obtiene prácticamente toda la funcionalidad de la caja:

[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>");
    }
}

Esto le permitirá agregar controles RoundedBox a sus páginas y agregar elementos secundarios (controles asp.net o html sin formato) que se mostrarán dentro de su div.

Por supuesto, se agregaría css para diseñar correctamente la clase roundedbox.

Solo otra cosa que puede usar, hay un extensor de esquina redondeada en el kit de herramientas ASP.Net ajax.

Sé que no es exactamente lo que pediste, pero no tienes que escribir ningún código personalizado.

¡Espero que eso ayude!

Miré esta pregunta porque quería producir un panel de diseño de 2 columnas. (no del todo, pero es un ejemplo mucho más simple de lo que necesitaba. Estoy compartiendo la solución que terminé usando:

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
    {
    }
}

El problema que todavía tengo es que el intellisense no funciona en este escenario, no sugerirá las etiquetas de contenido izquierdo y derecho.

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();
    }

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top