Как я могу использовать тег кнопки с ASP.NET? - PullRequest
62 голосов
/ 09 октября 2008

Я хотел бы использовать более новый тег <button> на веб-сайте ASP.NET, который, помимо прочего, позволяет вводить текст в стиле CSS и вставлять графику внутри кнопки. Элемент управления asp: Button отображается как <input type="button">, есть ли способ сделать ранее существующий элемент управления отображенным в <button>?

Из того, что я прочитал, есть несовместимость с IE, публикующим разметку кнопки вместо атрибута значения, когда кнопка находится в пределах <form>, но в ASP.NET она будет использовать событие onclick для запуска __doPostBack во всяком случае, поэтому я не думаю, что это будет проблемой.

Есть ли причины, по которым я не должен использовать это? Если нет, как бы вы поддержали его с помощью asp: Button или нового серверного элемента управления на его основе? Я бы предпочел не писать свой собственный серверный элемент управления, если этого можно избежать.


Сначала решение <button runat="server"> работало, но я сразу же столкнулся с ситуацией, когда ему нужно иметь свойство CommandName, которого нет у элемента управления HtmlButton. Похоже, мне все-таки понадобится создать элемент управления, унаследованный от Button.

Что мне нужно сделать, чтобы переопределить метод рендеринга и заставить его рендерить то, что я хочу?


UPDATE

Ответ ДанХерберта снова заинтересовал меня в поиске решения, поэтому я потратил еще немного времени на его разработку.

Во-первых, есть намного более простой способ перегрузить TagName:

public ModernButton() : base(HtmlTextWriterTag.Button)
{
}

Проблема с решением Дэна в его нынешнем виде заключается в том, что innerhtml тега помещается в свойство value, что вызывает ошибку проверки при обратной передаче. Связанная проблема заключается в том, что даже если вы правильно отобразите свойство value, реализация мозгового штурма IE тега <button> в любом случае отправляет innerhtml вместо значения. Таким образом, любая реализация этого должна переопределить метод AddAttributesToRender, чтобы правильно отобразить свойство value, а также предоставить какой-то обходной путь для IE, чтобы он не полностью испортил обратную передачу.

Проблема IE может быть непреодолимой, если вы хотите использовать свойства CommandName / CommandArgument для элемента управления с привязкой к данным. Надеюсь, кто-то может предложить обходной путь для этого.

Я сделал прогресс в рендеринге:

ModernButton.cs

Отображается как правильный html <button> с правильным значением, но он не работает с системой ASP.Net PostBack. Я написал кое-что из того, что нужно для предоставления события Command, но оно не срабатывает.

При осмотре этой кнопки рядом с обычной кнопкой asp: они выглядят так же, кроме различий, которые мне нужны. Поэтому я не уверен, как ASP.Net подключает событие Command в этом случае.

Дополнительная проблема заключается в том, что вложенные серверные элементы управления не отображаются (как вы можете видеть по атрибуту ParseChildren (false)). Во время рендеринга довольно просто ввести буквенный HTML-текст в элемент управления, но как разрешить поддержку вложенных серверных элементов управления?

Ответы [ 7 ]

42 голосов
/ 23 июля 2009

Хотя вы говорите, что использование [button runat = "server"] не является достаточно хорошим решением, важно упомянуть об этом - многие программисты .NET боятся использовать "собственные" HTML-теги ...

Использование:

<button id="btnSubmit" runat="server" class="myButton" 
    onserverclick="btnSubmit_Click">Hello</button>

Обычно это прекрасно работает, и все счастливы в моей команде.

35 голосов
/ 07 августа 2015

Это старый вопрос, но для тех из нас, кому не повезло по-прежнему поддерживать приложения ASP.NET Web Forms, я сам прошел через это, пытаясь включить глифы Bootstrap во встроенные элементы управления кнопок.

Согласно документации Bootstrap, желаемая разметка выглядит следующим образом:

<button class="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</button>

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

Кнопка

Это будет первый логический шаг, но, как объясняет этот вопрос, 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(&#39;uxSearch&#39;,&#39;&#39;)">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</a>

Плюсы

  • выглядит хорошо
  • Command событие; CommandName и CommandArgument свойства

Против

  • Отображает <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>

Плюсы

  • выглядит хорошо
  • Отображает правильный <button> элемент

Против

  • Нет 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>

Плюсы

  • выглядит нормально
  • Отображает правильный <button> элемент
  • Command событие; CommandName и CommandArgument свойства
  • Не отображает и не использует навязчивый JavaScript

Минусы

  • Нет (кроме встроенного элемента управления)
28 голосов
/ 22 февраля 2009

Я наткнулся на ваш вопрос, ища точно такую ​​же вещь. В итоге я использовал 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 не должно быть очень сложным, хотя при необходимости это можно легко добавить.

6 голосов
/ 09 октября 2008

Вы можете использовать свойство Button.UseSubmitBehavior , как описано в этой статьи о визуализации элемента управления ASP.NET Button в качестве кнопки .


РЕДАКТИРОВАТЬ: Извините .. это то, что я получаю за вопросы скимминга на моем перерыв на обед. Есть ли причины, по которым вы бы просто не использовали тег HtmlButton ?
6 голосов
/ 09 октября 2008

Вы можете создать новый элемент управления, наследуя от Button, и переопределить метод рендеринга, или использовать файл .browser, чтобы переопределить все кнопки на сайте, аналогично тому, как CSS Friendly работает для элемента управления TreeView и т. Д. 1001 *

2 голосов
/ 09 октября 2008

Я бы пошел с LinkButton и стилизовал бы его с помощью CSS в зависимости от ситуации.

1 голос
/ 10 июня 2009

Я боролся весь день с этим - мой пользовательский <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. И все же я не понял этого.

...