Пример использования свойств серверного веб-элемента управления

Visual Studio 2010

Обновлен: Ноябрь 2007

В этом примере демонстрируется создание элемента управления с именем Book, содержащего простые свойства и свойства с вложенными свойствами.

Простое свойство — это свойство строкового типа или типа, который можно легко преобразовать в строку. Простое свойство хранится как атрибут в открывающем теге элемента управления, для чего не требуется никаких действий со стороны разработчика. Свойства типа String и примитивные типы значений в библиотеке классов платформы .NET Framework, такие как Boolean, Int16, Int32 и Enum являются простыми свойствами. Можно добавить код для хранения простого свойства в словаре ViewState для управления состоянием во время обратной передачи.

Свойство считается сложным, если его тип является классом, в свою очередь имеющим свойства, которые называются вложенными свойствами. Например, свойство Font элемента управления WebControl — это класс FontInfo со своими свойствами, такими как Bold и Name. Свойства Bold и Name — это вложенные свойства Font элемента управления WebControl. Структура страницы ASP.NET позволяет хранить вложенные свойства в открывающем теге элемента управления при помощи синтаксиса с использованием дефиса (например, Font-Bold="true"), но при хранении в теге элемента управления вложенные свойства более удобочитаемы (например, <font Bold="true">).

Чтобы визуальный конструктор хранил вложенные свойства как потомки элемента управления, необходимо применить к свойству и его типу несколько атрибутов времени разработки. По умолчанию атрибуты хранятся в теге элемента управления с использованием дефисного синтаксиса. Кроме этого, для свойства с вложенными свойствами необходимо пользовательское управление состоянием для использования просмотра состояния, как описано в подразделе «Рассмотрение кода» далее.

Элемент управления Book, определенный в примере — это элемент управления, который можно использовать в веб-странице для отображения данных о книге или каталоге. Элемент управления Book определяет следующие свойства.

  • Author, свойство с вложенными свойствами пользовательского типа Author. У типа Author есть собственные свойства, такие как FirstName и LastName, являющиеся вложенными свойствами свойства Author.

  • BookType, простое свойство с типом пользовательского перечисления BookType. У перечисления BookType могут быть значения, такие как Fiction и NonFiction.

  • CurrencySymbol, простое свойство встроенного типа String.

  • Price, простое свойство встроенного типа Decimal.

  • Title, простое свойство встроенного типа String.

Свойства BookType, CurrencySymbol, Price и Title — простые свойства, поэтому для них не требуются специальные атрибуты при хранении страницы. Структура страницы сохраняет эти свойства по умолчанию как атрибуты в теге элементе управления, как показано в следующем примере:

<aspSample:Book Title="Wingtip Toys Stories" 
  CurrencySymbol="$" 
  Price="16" 
  BookType="Fiction">
</aspSample:Book>

Для свойства Author и свойств класса Author необходимы атрибуты времени разработки для их сохранения в тегах элемента управления, как показано в следующем примере:

<aspSample:Book >
  <Author FirstName="Judy" LastName="Lew" />
</aspSample:Book>

Элемент управления Book хранит свои простые свойства в словаре ViewState. Однако элемент управления Book должен реализовать пользовательское управления состоянием свойства Author, чтобы управлять состоянием свойства во время обратной передачи.

Реализация элемента управления Book, пригодная для производственного применения, может определять свойства для других данных, связанных с книгами, например, издателя и дату публикации. Кроме того, свойство Author можно заменить свойством коллекции. Дополнительные свойства о реализации свойства коллекции см. в разделе Пример свойства-коллекции веб-элементов.

4s70936s.alert_note(ru-ru,VS.100).gifПримечание.

Разработчик страницы может отключить состояние просмотра для страницы или отдельных элементов управления на странице. Если элемент управления должен поддерживать критичное состояние во время обратной передачи, можно использовать механизм управления состоянием элемента управления, определенный в ASP.NET 2.0. Дополнительные сведения о состоянии элемента управления см. в разделе Сравнительный пример использования состояния элемента управления и состояния просмотра.

// Book.cs
using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Samples.AspNet.CS.Controls
{
    [
    AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, 
        Level=AspNetHostingPermissionLevel.Minimal),
    DefaultProperty("Title"),
    ToolboxData("<{0}:Book runat=\"server\"> </{0}:Book>")
    ]
    public class Book : WebControl
    {
        private Author authorValue;
        private String initialAuthorString;

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The name of the author."),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerProperty),
        ]
        public virtual Author Author
        {
            get
            {
                if (authorValue == null)
                {
                    authorValue = new Author();
                }
                return authorValue;
            }

        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(BookType.NotDefined),
        Description("Fiction or Not"),
        ]
        public virtual BookType BookType
        {
            get
            {
                object t = ViewState["BookType"];
                return (t == null) ? BookType.NotDefined : (BookType)t;
            }
            set
            {
                ViewState["BookType"] = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The symbol for the currency."),
        Localizable(true)
        ]
        public virtual string CurrencySymbol
        {
            get
            {
                string s = (string)ViewState["CurrencySymbol"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["CurrencySymbol"] = value;
            }
        }


        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue("0.00"),
        Description("The price of the book."),
        Localizable(true)
        ]
        public virtual Decimal Price
        {
            get
            {
                object price = ViewState["Price"];
                return (price  == null) ? Decimal.Zero : (Decimal)price;
            }
            set
            {
                ViewState["Price"] = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The title of the book."),
        Localizable(true)
        ]
        public virtual string Title
        {
            get
            {
                string s = (string)ViewState["Title"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["Title"] = value;
            }
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Table);

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.WriteEncodedText(Title);
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.WriteEncodedText(Author.ToString());
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.WriteEncodedText(BookType.ToString());
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write(CurrencySymbol);
            writer.Write("&nbsp;");
            writer.Write(String.Format("{0:F2}", Price));
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderEndTag();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);

            Author auth = (Author)ViewState["Author"];
            if (auth != null)
            {
                authorValue = auth;
            }
        }

        protected override object SaveViewState()
        {
            if (authorValue != null)
            {
                String currentAuthorString = authorValue.ToString();
                if (!(currentAuthorString.Equals(initialAuthorString)))
                {
                    ViewState["Author"] = authorValue;
                }
            }

            return base.SaveViewState();
        }

        protected override void TrackViewState()
        {
            if (authorValue != null)
            {
                initialAuthorString = authorValue.ToString();
            }
            base.TrackViewState();
        }

    }
}


Атрибуты DesignerSerializationVisibilityAttribute и PersistenceModeAttribute, примененные к свойству Author элемента управления Book, описываются в разделе Пример свойства-коллекции веб-элементов. Эти атрибуты необходимы для сериализации и хранения свойств класса Author.

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

Для управления состоянием простого свойства оно определяется как простое свойство, доступное для чтения и записи, которое хранится в свойстве ViewState элемента управления. Элемент управления Book определяет свои простые свойства (BookType, CurrencySymbol, Price и Title) этим способом. Управление состоянием свойств, хранимых в свойстве ViewState, происходит без участия разработчика.

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

Тип свойства ViewState, StateBag — это словарь со встроенным управлением состоянием. Класс StateBag реализует интерфейс IStateManager, определяющий методы TrackViewState, SaveViewState и LoadViewState. Класс StateBag реализует эти методы для запуска отслеживания изменений свойств элемента управления после инициализации, сохраняет измененные элементы в конце запроса страницы и загружает сохраненное состояние при обратной передаче. Метод StateBag отслеживает элементы, отмечая элемент, как измененный, если он устанавливается после выполнения метода OnInit для запроса страницы. Например, если любой код на странице, выполняемый после ее инициализации задает свойство Title элемента управления Book, изменения вносятся в ViewState["Title"]. Как следствие, значение, сохраненное, как ключ «Title» в свойстве ViewState помечается как измененное. Дополнительные сведения см. в разделе Общие сведения о жизненном цикле веб-страниц ASP.NET.

Элемент управления Book задает свойство Author как доступное только для чтения property и реализует пользовательское управление состоянием, как в следующем примере:

  • В методе TrackViewState элемент управления Book сначала сохраняет первоначальное свойство Author в строку и затем запускает отслеживание состояние, вызывая метод TrackViewState базового класса.

  • В методе SaveViewState элемент управления Book определяет, отличается ли значение свойства Author от первоначального. Если свойство изменено, элемент управления Book сохраняет свойство Author в словаре ViewState, используя ключ «Author». Затем элемент управления Book вызывает метод SaveViewState базового класса. Так как отслеживание состояния включено, объект Author, сохраненный в свойстве ViewState, автоматически отмечается как измененный и записывается в состояние просмотра базового класса.

  • В методе LoadViewState элемент управления Book сначала вызывает метод LoadViewState базового класса. При этом словарь ViewState автоматически восстанавливается. Затем элемент управления Book определяет, есть ли в словаре ViewState элемент, сохраненный с ключом «Author». Если элемент найден, элемент управления загружает значение состояния просмотра в свойство Author.

В типе Author (определенном в коде далее) есть пользовательский преобразователь типов, позволяющий хранить экземпляр Author в состоянии просмотра. Он преобразует экземпляр типа Author в строку и обратно. Определение преобразователя типов позволяет задавать вложенные свойства Author в визуальном конструкторе. Пользовательский преобразователь типов описывается в разделе Пример преобразователя типов. Типы, которые можно хранить в состоянии просмотра, ограничены классом LosFormatter, используемым ASP.NET для сериализации состояния просмотра. Наиболее эффективно сериализуются типы String, примитивные типы значения в библиотеке классов платформы .NET Framework, такие как Boolean, Int16, Int32, Enum, Pair, Triplet, Array, ArrayList и Hashtable, а также все типы, содержащие эти примитивные типы. Кроме этого в состоянии просмотра можно хранить пользовательские типы с определенными преобразователями типов, такие как Pair, Triplet, Array, ArrayList и Hashtable. При определении сериализации состояния просмотра для пользовательского элемента управления необходимо преобразовать данные элемента управления в один из этих типов. При хранении в состоянии просмотра типов, несовместимых с механизмом сериализации элемент управления может скомпилироваться, но выдаст ошибку во время выполнения. Наконец, сериализуемые типы (то есть типы, реализующие интерфейс ISerializable, или отмеченные атрибутом SerializableAttribute) можно хранить в состоянии просмотра, но сериализация для этих типов намного медленнее, чем для примитивных типов.

Объект состояния, передаваемый элементом управления для сериализации — это состояние просмотра элемента управления. Свойство ViewState элемента управления — это только часть состояния просмотра элемента управления, которая автоматически участвует в механизме состояния просмотра, причем для этого не требуются какие-либо действия со стороны разработчика. Класс Control реализует логику сохранения и загрузки измененных элементов в словаре ViewState в его методах SaveViewState и LoadViewState. Другая часть или части состояния просмотра — это дополнительные объекты, которые разработчик (и базовый класс элемента управления) сохраняются в состоянии просмотра при переопределении метода SaveViewState. При переопределении методов SaveViewState и LoadViewState следует вызвать соответствующие методы базового класса.

Применение атрибута NotifyParentPropertyAttribute к свойствам FirstName, LastName и MiddleName и присвоение аргументу атрибута значения true приводит к тому, что визуальный конструктор применяет и сериализует изменения этих свойств в их родительское свойство (экземпляр Author).

// Author.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Web.UI;

namespace Samples.AspNet.CS.Controls
{
    [
    TypeConverter(typeof(AuthorConverter))
    ]
    public class Author
    {
        private string firstnameValue;
        private string lastnameValue;
        private string middlenameValue;

        public Author()
            :
            this(String.Empty, String.Empty, String.Empty)
        {
        }

        public Author(string firstname, string lastname)
            :
            this(firstname, String.Empty, lastname)
        {
        }

        public Author(string firstname, 
                    string middlename, string lastname)
        {
            firstnameValue = firstname;
            middlenameValue = middlename;
            lastnameValue = lastname;
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("First name of author."),
        NotifyParentProperty(true),
        ]
        public virtual String FirstName
        {
            get
            {
                return firstnameValue;
            }
            set
            {
                firstnameValue = value;
            }
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Last name of author."),
        NotifyParentProperty(true)
        ]
        public virtual String LastName
        {
            get
            {
                return lastnameValue;
            }
            set
            {
                lastnameValue = value;
            }
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Middle name of author."),
        NotifyParentProperty(true)
        ]
        public virtual String MiddleName
        {
            get
            {
                return middlenameValue;
            }
            set
            {
                middlenameValue = value;
            }
        }

        public override string ToString()
        {
            return ToString(CultureInfo.InvariantCulture);
        }

        public string ToString(CultureInfo culture)
        {
            return TypeDescriptor.GetConverter(
                GetType()).ConvertToString(null, culture, this);
        }
    }
}


// BookType.cs
using System;

namespace Samples.AspNet.CS.Controls
{
    public enum BookType
    {
        NotDefined = 0,
        Fiction = 1,
        NonFiction = 2
    }
}


В следующем примере показана ASPX-страница, использующая элемент управления Book.

<%@ Page Language="C#" Debug="true" Trace="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
  void Button_Click(object sender, EventArgs e)
  {
    Book1.Author.FirstName = "Bob";
    Book1.Author.LastName = "Kelly";
    Book1.Title = "Contoso Stories";
    Book1.Price = 39.95M;
    Button1.Visible = false;
  }  
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" runat="server">
    <title>
      Book test page
    </title>
  </head>
  <body>
    <form id="Form1" runat="server">
      <aspSample:Book ID="Book1" Runat="server"  
        Title="Tailspin Toys Stories" CurrencySymbol="$" 
        BackColor="#FFE0C0" Font-Names="Tahoma" 
        Price="16" BookType="Fiction">
        <Author FirstName="Judy" LastName="Lew" />
      </aspSample:Book>
      <br />
      <asp:Button ID="Button1" OnClick="Button_Click" 
        Runat="server" Text="Change" />
      <asp:Button ID="Button2" Runat="server" Text="Refresh" />
      <br />
      <br />
      <asp:HyperLink ID="Hyperlink1" NavigateUrl="BookTest.aspx" 
        Runat="server">
        Reload Page</asp:HyperLink>
    </form>
  </body>
</html>


Выполните компиляцию классов в этом примере с классом AuthorConverter, описанном в подразделе Пример преобразователя типов.

Дополнительные сведения о компиляции и использовании примеров пользовательских элементов управления см. в разделе Примеры связывания пользовательского серверного элемента управления.

Показ: