Модель кода в Visual Studio

108

Пока что мы рассказали только о том, как проектируются простые веб-страницы, и из каких частей состоит интерфейс Visual Studio. Но прежде чем приступать к серьезному кодированию, нужно обязательно разобраться в некоторых базовых деталях модели кода ASP.NET. Поэтому в данной статье речь пойдет о доступных вариантах использования кода для программирования веб-страниц и том, как события ASP.NET привязываются к коду.

Visual Studio поддерживает две модели для кодирования веб-страниц:

Внутритекстовый код

Эта модель наиболее близка к традиционной модели ASP. Весь код и HTML-разметка сохраняются в одном файле с расширением .aspx. Код вставляется в один или более блоков сценария. Однако, хотя код и находится внутри блока сценария, поддержку функции IntelliSense и возможностей отладки он из-за этого не теряет, да и выполнять его линейным образом сверху вниз (подобно классическому ASP-коду) вовсе не обязательно. Вместо этого в нем по прежнему можно реагировать на события элементов управления и использовать подпрограммы.

Эта модель удобна, поскольку позволяет хранить все в одном месте безо всяких излишеств и потому часто применяется для кодирования простых веб-страниц.

Отделенный код (code-behind)

Эта модель подразумевает создание для каждой веб-страницы ASP.NET двух файлов: файла разметки (.aspx) с дескрипторами HTML и дескрипторами элементов управления, и файла кода (.cs) с исходным кодом страницы (при условии, что для программирования веб-страницы применяется язык C#). Такая модель обеспечивает более удобную схему организации, позволяя отделять пользовательский интерфейс от программной логики, что очень важно при создании сложных страниц.

Чтобы лучше понять, в чем состоит разница между моделями внутритекстового и отделенного кода, не помешает рассмотреть какую-нибудь простую страницу. В следующем примере показан код разметки для страницы по имени WebForm1.aspx, который отображает текущее время в текстовой метке и обновляет страницу всякий раз, когда в ней выполняется щелчок на кнопке. В случае использования модели внутритекстового кода эта страница будет выглядеть следующим образом:

<%@ Page Language="C#" %>

<!DOCTYPE html>

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = "Текущее время: " + DateTime.Now.ToLongTimeString();
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
            <asp:Button ID="Button1" runat="server" Text="Click Me!" OnClick="Button1_Click" />
        </div>
    </form>
</body>
</html>

Приведенные ниже коды файлов WebForm1.aspx и WebForm1.aspx.cs демонстрируют, как эта же страница будет поделена на две части в случае использования модели отделенного кода:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
            <asp:Button ID="Button1" runat="server" Text="Click Me!" OnClick="Button1_Click" />
        </div>
    </form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Button1_Click(object sender, EventArgs e)
        {
            Label1.Text = "Текущее время: " + DateTime.Now.ToLongTimeString();
        }
    }
}

Единственное реальное отличие между примером с внутритекстовым кодом и примером с отделенным кодом состоит в том, что в последнем случае класс страницы больше не является неявным, а наоборот — объявляется как класс, содержащий все методы страницы.

В целом, модель отделенного кода предпочтительнее использовать для сложных страниц. Хотя модель внутритекстового кода является немного более компактной для небольших страниц, с увеличением объема кода и HTML-разметки с ними становится гораздо проще иметь дело по отдельности. Вдобавок модель отделенного кода является более чистой с концептуальной точки зрения, поскольку явно отображает созданный класс и импортированные пространства имен. И, наконец, она также еще позволяет веб-дизайнеру улучшать разметку страниц, не затрагивая код, написанный разработчиком.

Связывание файлов отделенного кода со страницами

Каждая страница .aspx начинается с директивы Page, указывающей язык для страницы и сообщающей ASP.NET местонахождение связанного кода (если только не используется встроенный код; в этом случае код содержится в том же самом файле).

Определять местонахождение связанного кода можно несколькими способами. В более старых версиях ASP.NET было распространено использование атрибута Src для указания на исходный код либо атрибута Inherits для указания на имя скомпилированного класса. Однако обе эти возможности имеют свои индивидуальные особенности.

Например, с помощью атрибута Inherits вы должны предварительно компилировать код, что довольно-таки утомительно (и может вызвать проблемы в командах разработчиков, поскольку стандартной возможностью является компиляция каждой страницы в отдельную DLL-библиотеку сборки). Но реальная проблема состоит в том, что оба подхода вынуждают объявлять каждый веб-элемент управления, который вы собираетесь использовать, с помощью переменной экземпляра. В результате получается большой объем стереотипного кода.

Эту проблему можно решить с помощью языкового средства, называемого частичные классы, которое позволяет разбивать один класс на несколько файлов исходного кода. По сути, эта модель является такой же, как раньше, но объявления элементов управления переносятся в отдельный файл. Вас как разработчика не должен отвлекать этот файл — наоборот, вы можете просто получать доступ к своим элементам управления веб-страницы по именам. Вы наверняка заметили слово partial (частичный) в объявлении класса веб-страницы:

public partial class WebForm1 : System.Web.UI.Page
{ ... }

Когда есть такая часть инфраструктуры, все остальное несложно. Для указания используемого класса в странице .aspx применяется атрибут Inherits, а для указания файла, в котором содержится отделенный код — атрибут CodeBehind:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>

Обратите внимание, что Visual Studio использует несколько необычный синтаксис именования для файла исходного кода. Он содержит полное имя соответствующей веб-страницы, снабженное расширением .aspx и в конце сопровождаемое расширением .cs. Это просто соглашение, помогающее избежать проблемы при создании двух различных типов файлов отделенного кода (например, веб-страницы и веб-службы) с одинаковыми именами.

Связывание дескрипторов элементов управления с переменными страниц

При запросе веб-страницы в окне браузера ASP.NET сначала отыскивает связанный с ней файл кода, а затем генерирует объявление переменной для каждого присутствующего в ней серверного элемента управления (т.е. для каждого элемента, у которого имеется атрибут runat="server").

Например, предположим, что есть текстовое поле по имени txtInput:

<asp:TextBox ID="txtInput" runat="server" />

ASP.NET сгенерирует для него следующее объявление переменной экземпляра и объединит его с классом страницы с помощью "волшебного" механизма частичных классов:

protected System.Web.UI.TextBox txtInput;

Конечно, вы этого объявления не увидите, поскольку оно является частью автоматически генерируемого кода, который создает компилятор .NET. Но вы будете полагаться на него всякий раз, когда будете писать строку кода, ссылающуюся на объект txtInput (для чтения или записи свойства):

txtInput.Text = "Hello."; 

Для обеспечения работоспособности этой системы файл разметки .aspx (с дескрипторами элементов управления) и файл .cs (с исходным кодом) должны поддерживаться в синхронизированном состоянии. Редактирование имен элементов управления в одном из них с помощью какого-нибудь другого инструмента (например, текстового редактора) приведет к разрыву связи и невозможности компиляции кода.

Кстати, вы заметите, что переменные элементов управления всегда объявляются с помощью ключевого слова protected (обозначающего защищенный доступ). Все дело в способе, которым ASP.NET использует наследование в модели веб-страниц. Существуют следующие уровни:

  1. Класс Page, входящий в состав библиотеки классов .NET, определяет базовый набор функциональных возможностей, которые позволяют веб-странице обслуживать другие элементы управления, визуализировать HTML-код и предоставлять доступ к традиционным объектам в стиле ASP вроде Request, Response и Session.

  2. Ваш класс отделенного кода (например, WebForm1) наследуется от класса Page, чтобы получить этот базовый набор функциональных возможностей веб-страницы ASP.NET.

  3. Когда вы компилируете свой класс, ASP.NET добавляет в него кое-какой дополнительный код (с помощью "волшебного" механизма частичных классов). В этом генерируемом автоматически коде все имеющиеся на странице элементы управления определяются как защищенные переменные, чтобы можно было получать к ним доступ в коде.

  4. Компилятор ASP.NET создает еще один класс для представления самой страницы .aspx. Этот класс наследуется от вашего специального класса отделенного кода (вместе с добавленным в него дополнительным кодом). Имя для этого класса ASP.NET создает просто путем добавления к имени класса отделенного кода суффикса aspx (например, WebForm1aspx). В этом классе содержится код, необходимый для инициализации страницы и всех ее элементов управления, а также окончательная версия визуализируемой HTML-разметки. Вдобавок экземпляр именно этого класса ASP.NET и будет создаваться при получении запросов на страницу.

Связывание событий с обработчиками событий

Большая часть кода страницы ASP.NET помещается внутрь обработчиков событий, реагирующих на события веб-элементов управления. С помощью Visual Studio добавить в код обработчик событий можно одним из трех способов:

Второй и третий способы наиболее удобны. С другой стороны, третий способ самый гибкий, поскольку позволяет выбрать уже созданный ранее метод в классе страниц. Просто выберите событие в окне Properties и щелкните на стрелке раскрывающегося списка справа. Вы увидите список методов класса, которые соответствуют сигнатуре, ожидаемой этим событием. Затем в списке можно выбрать метод для его подключения, как показано на рисунке выше.

В Visual Studio используется автоматическое образование цепочек событий, как показывает директива Page. Автоматическое образование цепочек событий основано на двух базовых принципах:

Например, если вы собираетесь обработать событие Click элемента управления Button, необходимо лишь установить атрибут OnClick в дескрипторе элемента управления с именем обработчика событий, который вы собираетесь использовать.

Конечно, если вы знакомы с событиями .NET, то знаете, что существует другой способ подключения обработчика событий. Это можно сделать динамически в коде с применением делегатов. Ниже представлен пример:

Button1.Click += Button1_Click;

Этот подход служит для создания элементов управления "на лету".

Пройди тесты
Лучший чат для C# программистов