c# - ¿Cómo puedo usar la etiqueta del botón con ASP.NET?
html htmlbutton (7)
Me gustaría usar la nueva etiqueta <button>
en un sitio web ASP.NET que, entre otras cosas, permite texto con estilo CSS e incrustando un gráfico dentro del botón. El ASP: el control del botón se representa como <input type="button">
, ¿hay alguna forma de hacer un control de preexistencia a <button>
?
Por lo que he leído hay una incompatibilidad con IE publicando el marcado del botón en lugar del atributo de valor cuando el botón está ubicado dentro de un <form>
, pero en ASP.NET usará el evento onclick para disparar __doPostBack de todos modos, por lo No creo que esto sea un problema.
¿Hay alguna razón por la que no debería usar esto? De lo contrario, ¿cómo lo apoyarías con el botón asp: o con un nuevo servidor basado en él? Preferiría no escribir mi propio control de servidor si eso puede evitarse.
Al principio, la solución <button runat="server">
funcionó, pero inmediatamente me encontré con una situación en la que debe tener una propiedad CommandName, que no tiene el control HtmlButton. Parece que voy a necesitar crear un control heredado de Button después de todo.
¿Qué debo hacer para anular el método de renderizado y hacer que represente lo que quiero?
ACTUALIZAR
La respuesta de DanHerbert me ha hecho interesarme en encontrar una solución a esto de nuevo, así que he pasado más tiempo trabajando en ello.
En primer lugar, hay una forma mucho más sencilla de sobrecargar el TagName:
public ModernButton() : base(HtmlTextWriterTag.Button)
{
}
El problema con la solución de Dan tal como está es que el innerhtml de la etiqueta se coloca en la propiedad de valor, lo que causa un error de validación en la devolución de datos. Un problema relacionado es que, incluso si representa correctamente el valor, la implementación de braindead de IE de la etiqueta <button>
publica el innerhtml en lugar del valor de todos modos. Por lo tanto, cualquier implementación de esto debe anular el método AddAttributesToRender para representar correctamente la propiedad de valor, y también proporcionar algún tipo de solución para IE para que no arruine por completo la devolución de datos.
El problema de IE puede ser insuperable si desea aprovechar las propiedades CommandName / CommandArgument para un control de datos. Con suerte, alguien puede sugerir una solución para esto.
He progresado en la representación:
Esto se representa como un <button>
html apropiado con el valor correcto, pero no funciona con el sistema ASP.Net PostBack. He escrito algo de lo que necesito para proporcionar el evento Command
, pero no se dispara.
Al inspeccionar este botón uno al lado del otro con un botón Asp: se ven igual que las diferencias que necesito. Así que no estoy seguro de cómo ASP.Net está conectando el evento Command
en este caso.
Un problema adicional es que los controles de servidor anidados no se representan (como se puede ver con el atributo ParseChildren (falso)). Es bastante fácil inyectar texto html literal en el control durante el procesamiento, pero ¿cómo se permite el soporte para controles de servidor anidados?
Me gustaría ir con un LinkButton y diseñarlo con CSS según corresponda.
Podrías hacer un nuevo control, heredando de Button, e invalidar el método de renderizado, o usar un archivo .browser para anular todos los botones en el sitio, similar a la manera en que funciona CSS Friendly para el control TreeView, etc.
Puede utilizar la propiedad Button.UseSubmitBehavior como se explica en este artículo sobre la representación de un botón ASP.NET control como un botón .
EDITAR: Lo siento ... eso es lo que obtengo por hacer preguntas sobre mi almuerzo. ¿Hay razones por las que no solo usarías una etiqueta <button runat = "server"> o un HtmlButton ? Me encontré con tu pregunta buscando exactamente lo mismo. Terminé usando Reflector para descubrir cómo se procesa realmente el control del Button
ASP.NET. Resulta ser muy fácil de cambiar.
Realmente solo se trata de anular las propiedades TagName
y TagKey
de la clase Button
. Después de que hayas hecho eso, solo tienes que asegurarte de mostrar los contenidos del botón manualmente, ya que la clase Button
original nunca tuvo contenido para representar y el control generará un botón sin texto si no procesas los contenidos.
Actualizar:
Es posible hacer algunas pequeñas modificaciones en el control Button a través de la herencia y aún así funcionar bastante bien. Esta solución elimina la necesidad de implementar sus propios manejadores de eventos para OnCommand (aunque si desea aprender cómo hacerlo, puedo mostrarle cómo se maneja). También soluciona el problema de enviar un valor que tiene marcado, a excepción de IE probablemente. Sin embargo, todavía no estoy seguro de cómo solucionar la pobre implementación de IE de la etiqueta Button. Esa puede ser una limitación verdaderamente técnica que es imposible de solucionar ...
[ParseChildren(false)]
[PersistChildren(true)]
public class ModernButton : Button
{
protected override string TagName
{
get { return "button"; }
}
protected override HtmlTextWriterTag TagKey
{
get { return HtmlTextWriterTag.Button; }
}
// Create a new implementation of the Text property which
// will be ignored by the parent class, giving us the freedom
// to use this property as we please.
public new string Text
{
get { return ViewState["NewText"] as string; }
set { ViewState["NewText"] = HttpUtility.HtmlDecode(value); }
}
protected override void OnPreRender(System.EventArgs e)
{
base.OnPreRender(e);
// I wasn''t sure what the best way to handle ''Text'' would
// be. Text is treated as another control which gets added
// to the end of the button''s control collection in this
//implementation
LiteralControl lc = new LiteralControl(this.Text);
Controls.Add(lc);
// Add a value for base.Text for the parent class
// If the following line is omitted, the ''value''
// attribute will be blank upon rendering
base.Text = UniqueID;
}
protected override void RenderContents(HtmlTextWriter writer)
{
RenderChildren(writer);
}
}
Para usar este control, tiene algunas opciones. Una es colocar controles directamente en el marcado ASP.
<uc:ModernButton runat="server"
ID="btnLogin"
OnClick="btnLogin_Click"
Text="Purplemonkeydishwasher">
<img src="../someUrl/img.gif" alt="img" />
<asp:Label ID="Label1" runat="server" Text="Login" />
</uc:ModernButton>
También puede agregar los controles a la colección de control del botón en su código subyacente.
// This code probably won''t work too well "as is"
// since there is nothing being defined about these
// controls, but you get the idea.
btnLogin.Controls.Add(new Label());
btnLogin.Controls.Add(new Table());
No sé qué tan bien funciona una combinación de ambas opciones, ya que no lo he probado.
La única desventaja de este control en este momento es que no creo que recuerde sus controles en PostBacks. No lo he probado así que puede que ya funcione, pero dudo que lo haga. Necesitarás agregar algún código de administración de ViewState para subcontroles que se manejarán a través de PostBacks, sin embargo, esto probablemente no sea un problema para ti. Agregar soporte de ViewState no debe ser terriblemente difícil de hacer, aunque si es necesario, puede agregarse fácilmente.
He estado luchando todo el día con esto: mi control <button/>
no funciona:
System.Web.HttpRequestValidationException: se detectó un valor potencialmente potencialmente peligroso Request.Form del cliente
Lo que sucede es que .Net agrega un atributo de name
:
<button type="submit" name="ctl02" value="Content" class="btn ">
<span>Content</span>
</button>
El atributo de name
arroja el error del servidor cuando se usa IE 6 e IE 7. Todo funciona bien en otros navegadores (Opera, IE 8, Firefox, Safari).
La cura es eliminar ese atributo de name
. Todavía no me he dado cuenta.
Aunque diga que usar [button runat = "server"] no es una solución lo suficientemente buena, es importante mencionarlo: muchos programadores .NET tienen miedo de usar las etiquetas HTML "nativas" ...
Utilizar:
<button id="btnSubmit" runat="server" class="myButton"
onserverclick="btnSubmit_Click">Hello</button>
Esto generalmente funciona perfectamente bien y todos están felices en mi equipo.
Esta es una vieja pregunta, pero para aquellos de nosotros que tenemos la mala suerte de tener que mantener las aplicaciones ASP.NET Web Forms, revisé esto yo mismo al tratar de incluir glifos Bootstrap dentro de los controles de botones incorporados.
Según la documentación de Bootstrap, el marcado deseado es el siguiente:
<button class="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</button>
Necesitaba que un control de servidor procesara este marcado, así que decidí buscar opciones.
Botón
Este sería el primer paso lógico, pero, como explica esta pregunta, Button representa un elemento <input>
lugar de <button>
, por lo que no es posible agregar HTML interno.
LinkButton (crédito a la respuesta de Tsvetomir Tsonev )
Fuente
<asp:LinkButton runat="server" ID="uxSearch" CssClass="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</asp:LinkButton>
Salida
<a id="uxSearch" class="btn btn-default" href="javascript:__doPostBack('uxSearch','')">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</a>
Pros
- Se ve bien
- Evento de
Command
; PropiedadesCommandName
yCommandArgument
Contras
- Renders
<a>
lugar de<button>
- Renderiza y se basa en JavaScript obstrusivo
HtmlButton (crédito a la respuesta de Philippe )
Fuente
<button runat="server" id="uxSearch" class="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</button>
Resultado
<button onclick="__doPostBack(''uxSearch'','''')" id="uxSearch" class="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</button>
Pros
- Se ve bien
- Renderiza el elemento
<button>
adecuado
Contras
- Sin evento de
Command
; sin propiedadesCommandName
oCommandArgument
- Renderiza y se basa en JavaScript
ServerClick
para manejar su eventoServerClick
En este punto, está claro que ninguno de los controles incorporados parece adecuado, por lo que el siguiente paso lógico es intentar modificarlos para lograr la funcionalidad deseada.
Control personalizado (crédito a la respuesta de Dan Herbert )
NOTA: Esto se basa en el código de Dan, por lo que todo el mérito recae en él.
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ModernControls
{
[ParseChildren]
public class ModernButton : Button
{
public new string Text
{
get { return (string)ViewState["NewText"] ?? ""; }
set { ViewState["NewText"] = value; }
}
public string Value
{
get { return base.Text; }
set { base.Text = value; }
}
protected override HtmlTextWriterTag TagKey
{
get { return HtmlTextWriterTag.Button; }
}
protected override void AddParsedSubObject(object obj)
{
var literal = obj as LiteralControl;
if (literal == null) return;
Text = literal.Text;
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write(Text);
}
}
}
Deshice la clase al mínimo y la modifiqué para lograr la misma funcionalidad con la menor cantidad de código posible. También agregué un par de mejoras. A saber:
- Eliminar el atributo
PersistChildren
(parece innecesario) - Eliminar anulación
TagName
(parece innecesario) - Elimine la decodificación de HTML desde el
Text
(la clase base ya maneja esto) - Deje
OnPreRender
intacto; anularAddParsedSubObject
enAddParsedSubObject
lugar (más simple) - Simplifique la anulación de
RenderContents
- Agregar una propiedad de
Value
(ver a continuación) - Agregue un espacio de nombre (para incluir una muestra de la directiva @ Register )
- Agregue las directivas de
using
necesarias
La propiedad Value
simplemente accede a la propiedad de Text
. Esto se debe a que el control Button nativo representa un atributo de value
todos modos (con Text
como su valor). Como el value
es un atributo válido del elemento <button>
, decidí incluir una propiedad para él.
Fuente
<%@ Register TagPrefix="mc" Namespace="ModernControls" %>
<mc:ModernButton runat="server" ID="uxSearch" Value="Foo" CssClass="btn btn-default" >
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</mc:ModernButton>
Salida
<button type="submit" name="uxSearch" value="Foo" id="uxSearch" class="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</button>
Pros
- Se ve bien
- Renderiza un elemento
<button>
adecuado - Evento de
Command
; PropiedadesCommandName
yCommandArgument
- No renderiza o se basa en JavaScript obstrusivo
Contras
- Ninguno (aparte de no ser un control incorporado)