Воспроизведение WAV-аудио
Платформа.NET Framework имеет небогатую историю поддержки звука. Версии 1.0 и 1.1 не предлагали никакого управляемого способа воспроизведения аудио, а когда долгожданная поддержка, наконец, появилась в.NET 2.0, она была представлена в форме не приводящего в восторг класса SoundPlayer (который можно найти в "малонаселенном" пространстве имен System.Media). Класс SoundPlayer довольно ограничен: он может воспроизводить только файлы в формате WAV, не поддерживает воспроизведения одновременно более одного звука и совсем не предоставляет возможностей управления никакими аспектами воспроизведения аудио (например, громкостью и балансом).
Чтобы получить эти возможности, разработчики, использующие Windows Forms, вынуждены были работать с библиотекой неуправляемого кода quartz.dll. Библиотека quartz.dll - ключевая часть DirectX, и она присутствует в проигрывателе Windows Media и операционной системе Windows. (Тот же компонент известен под названием DirectShow, а предыдущие версии назывались ActiveMovie.)
Класс SoundPlayer поддерживается в приложениях WPF. Если смириться с его существенными ограничениями, то можно сказать, что он предлагает наиболее простой и легкий способ добавления работы с аудио в приложения. Класс SoundPlayer также упаковывается в класс SoundPlayerAction. который позволяет воспроизводить звук через декларативный триггер (вместо написания нескольких строк кода C# в обработчике событий). В следующих разделах будет представлен краткий обзор обоих классов, а затем уже описания более мощных WPF-классов MediaPlayer и MediaElement.
Чтобы воспроизвести звук с помощью класса SoundPlayer, понадобится выполнить перечисленные ниже шаги:
Создать экземпляр SoundPlayer.
Указать звуковое содержимое, установив либо свойство Stream , либо свойство SoundLocation . Если есть объект Stream, содержащий звук в формате WAV, используйте свойство Stream. Если же есть путь к файлу или URL, указывающий на файл WAV, применяйте свойство SoundLocation.
Если аудио-содержимое хранится в виде двоичного ресурса и встроено в приложение, то потребуется доступ к нему в виде потока и использование свойства SoundPlayer.Stream. Причина в том, что SoundPlayer не поддерживает синтаксис упакованных URL в WPF.
Установив свойство Stream или SoundLocation, можно заставить SoundPlayer в действительности загрузить аудиоданные, вызвав метод Load() или LoadAsync(). Метод Load() наиболее прост - он останавливает выполнение кода до тех пор, пока весь звуковой фрагмент не будет загружен в память. LoadAsync() выполняет свою работу в другом потоке и по завершении инициирует событие LoadCompleted.
Формально использовать Load() или LoadAsync() не обязательно. Экземпляр SoundPlayer загружает аудиоданные по мере необходимости, когда вызывается метод Play() или PlaySync(). Однако явно загрузить аудио-фрагмент - хорошая идея; это не только позволит снизить накладные расходы при многократном воспроизведении, но также упростит обработку исключений, связанных с файловыми проблемами, отдельно от исключений, вызванных причинами, относящимися к процессу воспроизведения.
После этого можно вызвать PlaySync() , который приостановит код на время воспроизведения аудио-фрагмента, или же применить Play() для воспроизведения в другом потоке, обеспечивая интерфейсу приложения способность реагировать на действия пользователя. Единственный другой доступный вариант - это метод PlayLooping() , воспроизводящий аудио-фрагмент асинхронно в бесконечном цикле (что идеально для саундтреков). Чтобы остановить текущее воспроизведение в любой момент, необходимо вызвать метод Stop() .
В следующем фрагменте кода демонстрируется простейший подход к загрузке и асинхронному воспроизведению аудиофайла:
SoundPlayer sp = new SoundPlayer(); sp.SoundLocation = "tada.wav"; sp.Load(); sp.PlayLooping()
До сих пор в коде предполагалось, что аудиофайл присутствует в том же каталоге, что и скомпилированное приложение. Однако загружать SoundPlayer-аудио из файла не обязательно. Для коротких звуков, которые воспроизводятся в нескольких местах приложения, возможно, разумнее встроить звуковые файлы непосредственно в скомпилированную сборку в виде двоичных ресурсов (не путайте их с декларативными ресурсами, определяемыми в коде разметки XAML). Эта техника работает со звуковыми файлами так же хорошо, как и с графическими изображениями.
Например, если добавить файл ding.wav как ресурс по имени Ding (просто перейдите к узлу Properties --> Resources (Свойства --> ресурсы) в окне Solution Explorer и воспользуйтесь поддержкой визуального конструктора), то можно будет применить следующий код для его воспроизведения:
SoundPlayer player = new SoundPlayer(); player.Stream = Properties.Resources.Ding; player.Play();
Класс SoundPlayer не слишком хорошо работает с большими аудиофайлами, поскольку он должен загрузить в память весь файл целиком. Может показаться, что данную проблему можно разрешить, разбив большой аудиофайл на куски, однако класс SoundPlayer не предназначен для этого. Не существует простого способа такой синхронизации SoundPlayer, чтобы он мог воспроизвести множество аудиофрагментов друг за другом, поскольку он не обеспечивает никаких средств для организации очередей. Всякий раз, когда вызывается метод PlaySound() или Play(), текущее воспроизведение останавливается. Обходные пути возможны, но намного лучше вместо этого воспользоваться классом MediaElement.
Класс SoundPlayerAction позволяет более удобно использовать класс SoundPlayer. Класс SoundPlayerAction унаследован от TriggerAction, который позволяет использовать его в ответ на любое событие.
Ниже приведена разметка кнопки, применяющей SoundPlayerAction для подключения события Click к звуку. Триггер организован так, что его можно применить к множеству кнопок (если перенести его в коллекцию Resources):
При использовании SoundPlayerAction звук всегда воспроизводится асинхронно.
Последнее обновление: 31.10.2015
Хотя мы можем сами написать любой требуемый хелпер, но фреймворк MVC уже предоставляет большой набор встроенных html-хелперов, которые позволяют генерировать ту или иную разметку, главным образом, для работы с формами. Поэтому в большинстве случаев не придется создавать свои хелперы, и можно будет воспользоваться встроенными.
Для создания форм мы вполне можем использовать стандартные элементы html, например:
Это обычная html-форма, которая по нажатию на кнопку отправляет все введенные данные запросом POST на адрес /Home/Buy. Встроенный хелпер BeginForm/EndForm позволяет создать ту же самую форму:
Введите свое имя |
|
Введите адрес: |
|
Метод BeginForm принимает в качестве параметров имя метода действия и имя контроллера, а также тип запроса. Данный хелпер создает как открывающий тег
. Поэтому при рендеринге представления в выходной поток у нас получится тот же самый html-код, что и с применением тега form. Поэтому оба способа идентичны.Здесь есть один момент. Если у нас в контроллере определены две версии одного метода - для методов POST и GET, например:
Public ActionResult Buy() { return View(); } public string Buy(Purchase purchase) { .............. return "Спасибо за покупку книги";; }
То есть фактически вызов страницы с формой и отправка формы осуществляется одним и тем же действием Buy. В этом случае можно не указывать в хелпере Html.BeginForm параметры:
@using(Html.BeginForm()) { ............. }
В предыдущем примере вместе с хелпером Html.BeginForm использовались стандартные элементы html. Однако набор html-хелперов содержит также хелперы для ввода информации пользователем. В MVC определен широкий набор хелперов ввода практически для каждого html-элемента. Что выбрать - хелпер или стандартный элементы ввода html, уже решает сам разработчик.
Вне зависимости от типа все базовые html-хелперы используют как минимум два параметра: первый параметр применяется для установки значений для атрибутов id и name , а второй параметр - для установки значения атрибута value
Хелпер Html.TextBox генерирует тег input со значением атрибута type равным text . Хелпер TextBox используют для получения ввода пользователем информации. Так, перепишем предыдущую форму с заменой полей ввода на хелпер Html.TextBox:
@using(Html.BeginForm("Buy", "Home", FormMethod.Post)) {
Введите свое имя:
@Html.TextBox("Person", "Введите имя")Введите адрес:
@Html.TextBox("Address", "Введите адрес") }Мы получим тот же результат:
Хелпер TextArea используется для создания элемента
будет следующая html-разметка:
Обратите внимание, что хелпер декодирует помещаемое в него значение, в том числе и html-теги, (все хелперы декодируют значения моделей и значения атрибутов). Другие версии хелпера TextArea позволяют указать число строк и столбцов, определяющих размер текстового поля.
@Html.TextArea("text", "привет
мир", 5, 50, null)
Этот хелпер сгенерирует следующую разметку:
В примере с формой мы использовали скрытое поле input type="hidden" , вместо которого могли бы вполне использовать хелпер Html.Hidden . Так, следующий вызов хелпера:
@Html.Hidden("BookId", "2")
сгенерирует разметку:
А при передаче переменной из ViewBag нам надо привести ее к типу string: @Html.Hidden("BookId", @ViewBag.BookId as string)
Html.Password создает поле для ввода пароля. Он похож на хелпер TextBox , но вместо введенных символов отображает маску пароля. Следующий код:
@Html.Password("UserPassword", "val")
генерирует разметку:
Для создания переключателей применяется хелпер Html.RadioButton . Он генерирует элемент input со значением type="radio" . Для создания группы переключателей, надо присвоить всем им одно и то же имя (свойство name):
@Html.RadioButton("color", "red")
красный
@Html.RadioButton("color", "blue")
синий
@Html.RadioButton("color", "green", true)
зеленый
Этот код создает следующую разметку:
красный
синий
зеленый
Html.CheckBox может применяться для создания сразу двух элементов. Возьмем, к примеру, следующий код:
@Html.CheckBox("Enable", false)
Это выражение будет генерировать следующий HTML:
То есть кроме собственно поля флажка, еще и генерируется скрытое поле. Зачем оно нужно? Дело в том, что браузер посылает значение флажка только тогда, когда флажок выбран или отмечен. А скрытое поле гарантирует, что для элемента Enable будет установлено значение даже, если пользователь не отметил флажок.
Хелпер Html.Label создает элемент , а передаваемый в хелпер параметр определяет значение атрибута for и одновременно текст на элементе. Перегруженная версия хелпера позволяет определить значение атрибута for и текст на метке независимо друг от друга. Например, объявление хелпера Html.Label("Name") создает следующую разметку:
Элемент label представляет простую метку, предназначенную для прикрепления информации к элементам ввода, например, к текстовым полям. Атрибут for элемента label должен содержать ID ассоциированного элемента ввода. Если пользователь нажимает на метку, то браузер автоматически передает фокус связанному с этой меткой элементу ввода.
Хелпер Html.DropDownList создает выпадающий список, то есть элемент . Для генерации такого списка нужна коллекция объектов SelectListItem , которые представляют элементы списка. Объект SelectListItem имеет свойства Text (отображаемый текст), Value (само значение, которое может не совпадать с текстом) и Selected . Можно создать коллекцию объектов SelectListItem или использовать хелпер SelectList . Этот хелпер просматривает объекты IEnumerable и преобразуют их в последовательность объектов SelectListItem . Так, код @Html.DropDownList("countires", new SelectList(new string {"Russia","USA", "Canada","France"}),"Countries") генерирует следующую разметку:
Теперь более сложный пример. Выведем в список коллекцию элементов Book. В контроллере передадим этот список через ViewBag:
BookContext db = new BookContext(); public ActionResult Index() { SelectList books = new SelectList(db.Books, "Author", "Name"); ViewBag.Books = books; return View(); }
Здесь мы создаем объект SelectList, передавая в его конструктор набор значений для списка (db.Books), название свойства модели Book, которое будет использоваться в качестве значения (Author), и название свойства модели Book, которое будет использоваться для отображения в списке. В данном случае необязательно устанавливать два разных свойства, можно было и одно установить и для значения и отображения.
Тогда в представлении мы можем так использовать этот SelectList:
@Html.DropDownList("Author", ViewBag.Books as SelectList)
И при рендеринге представления все элементы SelectList добавятся в выпадающий список
Хелпер Html.ListBox , также как и DropDownList , создает элемент , но при этом делает возможным множественное выделение элементов (то есть для атрибута multiple устанавливается значение multiple). Для создания списка, поддерживающего множественное выделение, вместо SelectList можно использовать класс MultiSelectList:
@Html.ListBox("countires", new MultiSelectList(new string {"Россия","США", "Китай","Индия"}))
Этот код генерирует следующую разметку:
С передачей одиночных значений на сервер все понятно, но как передать множественные значения? Допустим, у нас есть следующая форма:
@using (Html.BeginForm()) { @Html.ListBox("countries", new MultiSelectList(new string { "Россия", "США", "Китай", "Индия" }))
}Тогда метод контроллера мог бы получать эти значения следующим образом:
Public string Index(string countries) { string result = ""; foreach (string c in countries) { result += c; result += ";"; } return "Вы выбрали: " + result; }
Как правило, на форме есть только одна кнопка для отправки. Однако в определенных ситуациях может возникнуть потребность, использовать более одной кнопки. Например, есть поле для ввода значения, а две кнопки указывают, надо это значение удалить или, наоборот, добавить:
@using (Html.BeginForm("MyAction", "Home", FormMethod.Post))
{
}
Самое простое решение состоит в том, что для каждой кнопки устанавливается одинаковое значение атрибута name , но разное для атрибута value . А метод, принимающий форму, может выглядеть следующим образом:
Public ActionResult MyAction(string product, string action) { if(action=="add") { } else if(action=="delete") { } // остальной код метода }
И с помощью условной конструкции в зависимости от значения параметра action, который хранит значение атрибута value нажатой кнопки, производятся определенные действия.
Button (Кнопка), LinkButton (Кнопка-ссылка) и ImageButton (Кнопка-изображение)Серверные элементы управления Button, LinkButton и ImageButton в ASP.NET 2.0, события Click и Command
Элементы управления, представляющие кнопки (Button , LinkButton и ImageButton ) ткже относятся к числу наиболее часто используемых. Набор свойств и событий у них очень похож. Основное отличие между ними заключается в том, как данная кнопка будет показана на Web -странице. Различия между ними наглядно показаны на рис. 4.5.3-1.
Рис. 4.5.3-1 Элементы управления Button , LinkButton и Imagebutton
В дальнейшем речь у нас будет идти про элемент управления Button , однако все возможности этого элемента управления применяются и к элементам управления LinkButton и ImageButton .
Самый простой вариант кода HTML для серверной кнопки ASP .NET может выглядеть как
< asp : Button ID =" Button 1" runat =" server " Text =" Button " />
Кнопки в формах ASP .NET разделяются на две большие категории: кнопки Submit и кнопки Command . Во внешнем представлении различий между кнопками разных типов нет. Различается только их поведение: при нажатии на кнопку типа Submit на сервер просто передается содержимое элементов управления формы, а при нажатии на кнопку типа Command на сервере должна выполниться событийная процедура Command для данной кнопки. В данной событийной процедуре при помощи объекта CommandEventArgs можно получить информацию о значении свойства Command и использовать его при выполнении событийной процедуры.
По умолчанию все кнопки в формах ASP .NET относятся к типу Submit . Чтобы отнести их к типу Command , достаточно просто заполнить информацию о имени команды при помощи свойства CommandName . После этого для данной кнопки можно будет использовать, помимо стандартного события Click , еще и событие Command . Обычно кнопки типа Command используются тогда, когда функциональности обычных кнопок Submit не хватает (например, нужно настроить взаимодействие родительского и вложенного элементов управления).
Главное свойство элемента управления Button , помимо CommandName - свойство Text , которое определяет надпись на кнопке. Другие важные свойства представлены ниже:
· CausesValidation - определяет, будет ли после нажатия этой кнопки производится проверка значений, введенных пользователем. По умолчанию для этого свойства устанавливается значение true , и проверка производится. Для некоторых кнопок (например, для кнопки Reset ) проверку введенных пользователем значений необходимо отключить, установив для этого свойства значение False ;
· Enabled - возможность включить или отключить кнопку (например, можно отключить ее до того момента, пока пользователь не заполнит все необходимые текстовые поля);
· OnClientClick - это свойство позволяет определить имя скрипта, который должен быть выполнен в броузере клиента при нажатии на эту кнопку;
· PostBackUrl - это свойство позволяет определить, какая страница будет отправлена пользователю в броузер после того, как будет нажата данная кнопка;
· UseSubmitBehavior - по умолчанию для этого свойства установлено значение True , что значит: отправлять информацию на сервер, используя стандартный механизм отправки информации, встроенный в броузер. Если установить для этого свойства значение false , то подсистема ASP .NET автоматически сгенерирует для этой кнопки клиентский скрипт, который будет заниматься отправкой информации (такое решение называется ASP .NET postback mechanism ). Этот способ можно использовать, если необходимо обеспечить дополнительную функциональность при отправке данных с клиента на сервер.
· ValidationGroup - при помощи этого свойства можно определить группу элементов управления, для которых значения будут проверяться при нажатии данной кнопки. Это свойство удобно использовать тогда, когда форма большая и удобнее проверять значения, вводимые пользователем, по частям.
К гланым событиям кнопок, как уже говорилось, относятся Click и Command .
С появлением достаточно быстрого соединения с сетью Интернет, Flash был единственным инструментом для воспроизведения звуков на веб-сайтах. Но HTML5 в корне изменит способ воспроизведения звуков в Интернет. В этой статье я хочу подробно рассказать Вам о том, как использовать тег на ваших сайтах.
Вот и всё на сегодня.
Надеюсь, что эта статья помогла Вам понять базовые возможности HTML5 тега .
Razor Pages in ASP.NET Core allow you to build page focused web applications using simple page based programming model. If you worked with Razor Pages before you are probably aware that by default you can handle requests using methods such as OnGet(), OnPost(), OnPut(), and OnDelete(). This means a form POSTed to the server needs to be handled using only one action - OnPost(). At times, however, you need to have multiple actions to deal with the same HTTP verb. A common scenario is when you have multiple submit buttons on a form.
Consider the following example that shows such a form.
As you can see, the Index.cshtml page has three submit buttons housed inside a form. And you want to handle each button different. By default, clicking on any of these three buttons will trigger OnPost() action. How to wire three different handlers instead of the default handler? To accomplish this you need to use the asp-page-handler attribute of the tag helpers. Have a look at the following mark that shows the above form:
Notice the code shown in bold letters. The input elements have asp-page-handler attribute set to certain values. This attribute decides the action from the page model that will be handling the form submission. The asp-page-handler attribute basically emits formaction HTML attribute in the browser. Also notice that the input elements also have asp-route-sessioncount attribute. This attribute sets a route value that is then supplied to the corresponding handler method. Specifying asp-route-* is, of course, optional. Form fields are made available to the handler methods through model binding as usual (also see my earlier article ).
Ok. So far so good. Now it"s time to write those handler actions as mentioned in the asp-page-handler attributes. Open the page model class (Index.cshtml.cs) and write the following actions into it:
Public void OnPostYogaPostures(int sessionCount) { //do your work here ViewData["message"] = $"Your request for {sessionCount} sessions in Yoga Postures is being processed."; } public void OnPostMeditation(int sessionCount) { //do your work here ViewData["message"] = $"Your request for {sessionCount} sessions in Kriya and Meditation is being processed."; } public void OnPostRestorativeYoga(int sessionCount) { //do your work here ViewData["message"] = $"Your request for {sessionCount} sessions in Restorative Yoga is being processed."; }
Notice the action naming convention. Since we want to handle POST requests we prepend all the action names (asp-page-handler name) with "OnPost". Thus we have OnPostYogaPostures, OnPostMeditation, OnPostRestorativeYoga. Also notice that all the handlers have sessionCount parameter. This parameter will come from the asp-route-sessioncount attribute we assigned earlier.
Set a breakpoint in each of these methods and run the application. You will find that clicking on a button takes the control to the corresponding page handler.
That"s it for now! Keep coding !!
Bipin Joshi is a software consultant, trainer, author, yoga mentor, and spiritual guide having 24+ years of experience in software development, consulting, and training. He conducts instructor-led online training courses in ASP.NET Core, ASP.NET MVC, and Design Patterns for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click .