Как я могу использовать тег кнопки с ASP.NET?
Я хотел бы использовать более новый <button>
тег на веб-сайте ASP.NET, который, помимо прочего, позволяет вводить текст в стиле CSS и вставлять графику внутри кнопки. Элемент управления asp:Button отображается как <input type="button">
Есть ли способ сделать ранее существующий элемент управления для <button>
?
Из того, что я прочитал, есть несовместимость с IE, публикующим разметку кнопки вместо атрибута значения, когда кнопка находится внутри <form>
, но в ASP.NET он будет использовать событие onclick для запуска __doPostBack, так что я не думаю, что это будет проблемой.
Есть ли причины, по которым я не должен использовать это? Если нет, как бы вы поддержали его с помощью asp:Button или нового серверного элемента управления на его основе? Я бы предпочел не писать свой собственный серверный элемент управления, если этого можно избежать.
Сначала <button runat="server">
Решение сработало, но я немедленно столкнулся с ситуацией, когда ему нужно иметь свойство CommandName, которого нет у элемента управления HtmlButton. Похоже, мне все-таки понадобится создать элемент управления, унаследованный от Button.
Что мне нужно сделать, чтобы переопределить метод рендеринга и заставить его рендерить то, что я хочу?
ОБНОВИТЬ
Ответ ДанХерберта снова заинтересовал меня в поиске решения этой проблемы, поэтому я потратил еще немного времени на его разработку.
Во-первых, существует гораздо более простой способ перегрузки TagName:
public ModernButton() : base(HtmlTextWriterTag.Button)
{
}
Проблема с решением Дэна в его нынешнем виде заключается в том, что innerhtml тега помещается в свойство value, что вызывает ошибку проверки при обратной передаче. Связанная проблема заключается в том, что даже если вы правильно отобразите свойство value, реализация мозговых мертвецов в IE <button>
тег отправляет innerhtml вместо значения в любом случае. Таким образом, любая реализация этого должна переопределить метод AddAttributesToRender, чтобы правильно отобразить свойство value, а также предоставить какой-то обходной путь для IE, чтобы он не полностью испортил обратную передачу.
Проблема IE может быть непреодолимой, если вы хотите использовать свойства CommandName/CommandArgument для элемента управления с привязкой к данным. Надеюсь, кто-то может предложить обходной путь для этого.
Я сделал успехи в рендеринге:
Это делает как правильный HTML <button>
с правильным значением, но он не работает с системой ASP.Net PostBack. Я написал кое-что из того, что мне нужно, чтобы Command
событие, но оно не срабатывает.
При осмотре этой кнопки рядом с обычной кнопкой asp:Button, они выглядят так же, кроме различий, которые мне нужны. Так что я не уверен, как ASP.Net подключает Command
событие в этом случае.
Дополнительная проблема заключается в том, что вложенные серверные элементы управления не отображаются (как вы можете видеть по атрибуту ParseChildren(false)). Во время рендеринга довольно просто внедрить буквенный HTML-текст в элемент управления, но как разрешить поддержку вложенных серверных элементов управления?
7 ответов
Это старый вопрос, но для тех из нас, кому не повезло по-прежнему поддерживать приложения ASP.NET Web Forms, я сам прошел через это, пытаясь включить глифы Bootstrap во встроенные элементы управления кнопками.
Согласно документации Bootstrap, желаемая разметка выглядит следующим образом:
<button class="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</button>
Мне нужно, чтобы эта разметка отображалась серверным элементом управления, поэтому я решил найти варианты.
кнопка
Это был бы первый логический шаг, но, как объясняет этот вопрос, кнопка отображает <input>
элемент вместо <button>
, поэтому добавление внутреннего HTML невозможно.
LinkButton (благодарность ответу Цветомира Цонева)
Источник
<asp:LinkButton runat="server" ID="uxSearch" CssClass="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</asp:LinkButton>
Выход
<a id="uxSearch" class="btn btn-default" href="javascript:__doPostBack('uxSearch','')">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</a>
Pros
- Выглядит хорошо
Command
событие;CommandName
а такжеCommandArgument
свойства
Cons
- Оказывает
<a>
вместо<button>
- Оказывает и полагается на навязчивый JavaScript
HtmlButton (кредит на ответ Филиппа)
Источник
<button runat="server" id="uxSearch" class="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</button>
Результат
<button onclick="__doPostBack('uxSearch','')" id="uxSearch" class="btn btn-default">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</button>
Pros
- Выглядит хорошо
- Делает правильный
<button>
элемент
Cons
- нет
Command
событие; нетCommandName
или жеCommandArgument
свойства - Рендерится и использует навязчивый JavaScript для обработки
ServerClick
событие
На данный момент ясно, что ни один из встроенных элементов управления не кажется подходящим, поэтому следующий логический шаг - попытаться изменить их для достижения желаемой функциональности.
Таможенный контроль (кредит к ответу Дэна Герберта)
ПРИМЕЧАНИЕ. Это основано на коде Дэна, так что вся заслуга принадлежит ему.
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);
}
}
}
Я сократил класс до минимума и реорганизовал его для достижения той же функциональности с как можно меньшим количеством кода. Я также добавил пару улучшений. А именно:
- Удалить
PersistChildren
атрибут (кажется ненужным) - Удалить
TagName
переопределить (кажется ненужным) - Удалить HTML-декодирование из
Text
(базовый класс уже обрабатывает это) - Покидать
OnPreRender
неповрежденными; переопределениеAddParsedSubObject
вместо (проще) - упрощать
RenderContents
переопределение - Добавить
Value
собственность (см. ниже) - Добавить пространство имен (чтобы включить образец директивы @ Register)
- Добавить необходимо
using
директивы
Value
собственность просто получает доступ к старому Text
имущество. Это потому, что нативный элемент управления Button отображает value
атрибут в любом случае (с Text
как его стоимость). поскольку value
является действительным атрибутом <button>
элемент, я решил включить свойство для него.
Источник
<%@ 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>
Выход
<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
- Выглядит хорошо
- Делает правильный
<button>
элемент Command
событие;CommandName
а такжеCommandArgument
свойства- Не отображает и не использует навязчивый JavaScript
Cons
- Нет (кроме того, что не является встроенным элементом управления)
Хотя вы говорите, что использование [button runat="server"] не является достаточно хорошим решением, важно упомянуть об этом - многие программисты.NET боятся использовать "собственные" HTML-теги...
Использование:
<button id="btnSubmit" runat="server" class="myButton"
onserverclick="btnSubmit_Click">Hello</button>
Обычно это прекрасно работает, и все счастливы в моей команде.
Я наткнулся на ваш вопрос, ища точно такую же вещь. Я в конечном итоге с помощью Reflector, чтобы выяснить, как ASP.NET Button
контроль фактически оказан. Оказывается, это действительно легко изменить.
Это действительно сводится к переопределению TagName
а также TagKey
свойства Button
учебный класс. После того, как вы это сделали, вам просто нужно убедиться, что вы визуализируете содержимое кнопки вручную, так как оригинал Button
У класса никогда не было содержимого для отображения, и элемент управления будет отображать кнопку без текста, если вы не отображаете содержимое.
Обновить:
Можно сделать несколько небольших изменений в элементе управления Button с помощью наследования и при этом работать достаточно хорошо. Это решение устраняет необходимость реализации собственных обработчиков событий для OnCommand (хотя, если вы хотите узнать, как это сделать, я покажу вам, как это обрабатывается). Это также устраняет проблему отправки значения с разметкой, за исключением, вероятно, IE. Я все еще не уверен, как исправить плохую реализацию IE тега Button, хотя. Это может быть просто техническим ограничением, которое невозможно обойти...
[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);
}
}
Чтобы использовать этот элемент управления, у вас есть несколько вариантов. Одним из них является размещение элементов управления непосредственно в разметку 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>
Вы также можете добавить элементы управления в коллекцию элементов управления кнопки в вашем коде.
// 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());
Я не знаю, насколько хорошо работает комбинация обоих вариантов, поскольку я не проверял это.
Единственный недостаток этого элемента управления в настоящее время заключается в том, что я не думаю, что он запомнит ваши элементы управления через PostBacks. Я не проверял это, так что это может уже работать, но я сомневаюсь, что это работает. Я думаю, вам нужно добавить некоторый управляющий код ViewState для субэлементов управления через PostBacks, однако это, вероятно, не проблема для вас. Добавление поддержки ViewState не должно быть очень сложным, хотя при необходимости это можно легко добавить.
Вы можете использовать свойство Button.UseSubmitBehavior, как описано в этой статье, об отображении элемента управления ASP.NET Button в качестве кнопки.
РЕДАКТИРОВАТЬ: Извините.. это то, что я получаю за скимминг вопросы на моем перерыв на обед Есть ли причины, по которым вы бы просто не использовали тег
Вы можете создать новый элемент управления, наследуя от Button, и переопределить метод рендеринга, или использовать файл.browser, чтобы переопределить все кнопки на сайте, аналогично тому, как CSS Friendly работает для элемента управления TreeView и т. Д.
Я бы пошел с LinkButton и стилизовал бы его с помощью CSS в зависимости от ситуации.
Я боролся весь день с этим - мой обычай <button/>
сгенерированный контроль не работает:
System.Web.HttpRequestValidationException: потенциально опасное значение Request.Form было обнаружено от клиента
Что происходит, что.Net добавляет name
атрибут:
<button type="submit" name="ctl02" value="Content" class="btn ">
<span>Content</span>
</button>
name
Атрибут выдает ошибку сервера при использовании IE 6 и IE 7. Все отлично работает в других браузерах (Opera, IE 8, Firefox, Safari).
Лекарство заключается в том, чтобы избавиться от этого name
приписывать. Тем не менее я не понял это.