Как я могу использовать тег кнопки с ASP.NET?

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

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

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

ModernButton.cs

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
62
0
81 377
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Я бы выбрал LinkButton и при необходимости стилизовал его с помощью CSS.

Мне нужна кнопка, а не гиперссылка. Конечно, я знаю о LinkButton.

Adam Lassek 09.10.2008 18:30

Его можно оформить так, чтобы он выглядел как единое целое. Вот например: hedgerwow.com/360/dhtml/…

Tsvetomir Tsonev 09.10.2008 20:29

Кнопки обрабатываются операционной системой, и каждая из них выглядит по-разному. В некоторых операционных системах они также могут быть тематическими. Если бы я сделал кнопку так, чтобы она выглядела как кнопка Vista, она бы везде выглядела неконгруэнтной.

Adam Lassek 09.10.2008 21:52

Если это то, что вам нужно ... Я думал о полном изменении стиля кнопок, когда вы упомянули CSS и изображения. В любом случае, просто следите за IE;)

Tsvetomir Tsonev 09.10.2008 22:14

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

Похоже, что переопределение метода рендеринга может быть частью решения, которое мне нужно. Вы сами это сделали? Можете ли вы уточнить детали?

Adam Lassek 09.10.2008 20:22

Я не делал этого для кнопки, но сделал это для других элементов управления. Я вставлю код, когда вернусь на свой компьютер, если меня никто не опередит.

Steven Robbins 09.10.2008 21:12

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


EDIT: Sorry.. that's what I get for skimming questions on my lunch break. Are there reasons why you wouldn't just use a <button runat = "server"> tag or an HtmlButton?

Я наткнулся на ваш вопрос в поисках того же самого. В итоге я использовал Отражатель, чтобы выяснить, как на самом деле отображается элемент управления ASP.NET Button. Оказывается, это действительно легко изменить.

На самом деле все сводится к переопределению свойств TagName и TagKey класса Button. После того, как вы это сделали, вам просто нужно убедиться, что вы визуализируете содержимое кнопки вручную, поскольку исходный класс Button никогда не имел содержимого для визуализации, и элемент управления будет отображать кнопку без текста, если вы не визуализируете содержимое.

Обновлять:

Можно внести несколько небольших изменений в элемент управления Button посредством наследования, и при этом он будет работать достаточно хорошо. Это решение избавляет от необходимости реализовывать собственные обработчики событий для OnCommand (хотя, если вы хотите узнать, как это сделать, я могу показать вам, как это обрабатывается). Он также устраняет проблему отправки значения с разметкой, за исключением, вероятно, IE. Я все еще не уверен, как исправить плохую реализацию тега Button в IE. Это может быть просто техническое ограничение, которое невозможно обойти ...

[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 не должно быть очень сложным, хотя при необходимости ее можно легко добавить.

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

Adam Lassek 23.02.2009 18:11

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

Dan Herbert 23.02.2009 21:25

Это помогло мне приблизиться к решению, спасибо. Однако есть еще несколько важных вещей, которые необходимо решить, прежде чем это сработает. Подробнее см. Мой измененный вопрос.

Adam Lassek 25.02.2009 02:07

+1 Это наиболее полный ответ, так как нет встроенного элемента управления, отвечающего требованиям вопроса. См. Мой ответ ниже для отредактированной версии.

Daniel Liuzzi 07.08.2015 16:53

Я весь день боролся с этим - мой пользовательский элемент управления, сгенерированный <button/>, не работает:

System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client

Что происходит, так это то, что .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. До сих пор я этого не понял.

Тег имени не проблема. См. asp.net/learn/whitepapers/request-validation. Это потому, что вместо публикации атрибута value, как предполагалось, IE вместо этого отправляет разметку из тега, а отправка обратной разметки всегда будет вызывать ошибку сервера в ASP.Net, если вы не отключите проверку запроса.

Adam Lassek 10.06.2009 19:32

Наиболее серьезным препятствием для использования тега кнопки является тот факт, что IE ведет себя совсем не так, как все остальное. Возможно, вам придется изменить значения сообщений в javascript перед их отправкой на сервер, чтобы он вел себя предсказуемо.

Adam Lassek 10.06.2009 19:36

@ Адам Да, вы правы, вот в чем проблема. Есть ли у вас обходной путь для этого? Без использования javascript.

David Andersson 11.06.2009 09:52

Да - не используйте IE;) В противном случае вам придется манипулировать значениями Post, и javascript - единственный способ сделать это.

Adam Lassek 17.06.2009 02:20

К сожалению, я пришел к выводу, что тег кнопки не использовать вообще. Мне это нравится, но для моего использования уровень проникновения IE составляет 50%.

David Andersson 17.06.2009 13:20

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

Использовать:

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

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

Да, это работает, хотя это не эквивалент asp: button, поскольку вы теряете много функциональности. В моем случае кнопка находится внутри элемента управления с привязкой к данным, поэтому она имеет очень ограниченную полезность без CommandName и CommandArgument.

Adam Lassek 24.07.2009 03:42

Вы можете добавлять настраиваемые атрибуты в такие элементы управления и легко извлекать значения в коде.

G. Ghez 30.11.2011 12:41

Похоже, что это нарушает причиныvalidation = "false"

niico 18.02.2014 11:42

Обратите внимание, что это решение - как и LinkButton - не будет работать, если отключен JavaScript (источник).

Daniel Liuzzi 07.08.2015 16:57

@niico И моя проблема. Хотелось бы иметь встроенную поддержку кнопок HTML5 в веб-формах ASP.NET.

Brack 19.04.2018 15:51
Ответ принят как подходящий

Это старый вопрос, но для тех из нас, кому не повезло, которым все еще приходится поддерживать приложения веб-форм ASP.NET, я сам прошел через это, пытаясь включить глифы 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 (см. Ниже)
  • Добавьте пространство имен (чтобы включить образец директивы @ Регистр)
  • Добавьте необходимые директивы using

Свойство Value просто обращается к старому свойству Text. Это связано с тем, что собственный элемент управления Button в любом случае отображает атрибут valueText в качестве его значения). Поскольку 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

Минусы

  • Нет (кроме того, что не является встроенным элементом управления)

В настраиваемом элементе управления все еще есть ошибка: AddParsedSubObject никогда не вызывается, если вспомогательное содержимое содержит какое-либо выражение рендеринга. Пример: <mc:ModernButton runat = "server"><b><%= this.AnyString %></b></mc:ModernButton>. Однако вы можете напрямую использовать ресурс ('<%$ Resources:AnyString %>') или выражения привязки ('<%# this.AnyString %>') в свойстве Text, но это заставит вас поместить все содержимое в одно выражение (включая HTML).

Martin Braun 29.11.2015 20:47

@modiX: Отлично! Это решило мою проблему. Я использовал свойство Text, чтобы добавить текст и изображение.

krlzlx 09.05.2016 15:39

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

kman 28.06.2016 23:28

Этот настраиваемый элемент управления почти работал у меня правильно, но он не позволял правильно использовать вложенный элемент управления, значения которого были назначены на стороне сервера (AddParsedSubObject запускался до того, как значение вложенного элемента управления было изменено - даже если я переместил манипуляцию в Page_Init) . В конце концов, мне пришлось воспользоваться методами Дэна Герберта OnPreRender и RenderContents. Это позволяло изменять вложенные элементы управления на стороне сервера. Пока я успешно использую это с CommandName и CommandArgument в Repeater, а также с основной кнопкой отправки в форме. Спасибо всем!

J Stuart 14.07.2018 10:24

Возможно, вам также потребуется добавить сборку: <% @ Register TagPrefix = "mc" Namespace = "ModernControls" Assembly = "myApplication"%>

mparkuk 01.11.2018 14:34

Другие вопросы по теме