Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - Все статьи »

Обсудить на форуме Обсудить на форуме

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

Резюме

В этой статье рассматриваются основы наследования из другого элемента управления и добавления собственных свойств, методов и событий наряду с добавлением собственного кода; каждый пример разработки элемента управления Microsoft Windows Forms следует читать вместе с обзорной статьей на смежную тему. (12 печатных страниц)

Исходный код WinFormControls.exe можно загрузить из MSDN Code Center.

Эта статья является второй статьей в серии из пяти статей по разработке элементов управления в Microsoft® .NET:

  • Разработка пользовательских элементов управления Windows с помощью Visual Basic .NET (обзор)
  • Добавление проверки правильности регулярного выражения
  • Объединение нескольких элементов управления в один
  • Расширение элемента управления TreeView
  • Рисование собственных элементов управления с помощью GDI+

Содержание

Введение

В этой статье рассматриваются два примера: создание пользовательского TextBox, выполняющего проверку правильности регулярного выражения, и создание расширителя функциональности (extender provider), использующего альтернативный способ проверки правильности регулярного выражения.

Пример 1a: добавление проверки правильности регулярного выражения к элементу управления TextBox

В обзорной статье было показано, как с помощью создания нового элемента управления и при минимальном объеме работы со стороны разработчика быстро расширить элемент управления TextBox, чтобы он принимал только числовые данные. В приведенном примере было только проиллюстрировано, как быстро создать элемент управления с помощью наследования, поэтому применение примера было весьма ограничено. В первом примере будет показано, как построить элемент управления, достигающий той же цели более изящным способом. Вместо того, чтобы просто расширить этот элемент управления для поддержки формата валюты и других числовых форматов, лучше создать более универсальный элемент управления, ограничивающий текстовый ввод. Чтобы точно выполнить поставленную задачу, при построении (Web)-приложения ASP.NET элемент управления RegularExpressionValidator, документированный в Общем справочнике .NET Framework, уже был предоставлен. Этот элемент управления позволяет ограничить вводимый текст любым форматом, который можно описать регулярным выражением, т.е. фактически любым форматом. Поскольку версия этого элемента управления не была предоставлена для использования в Windows Forms, отличным примером пользовательского элемента управления, который можно построить, является Windows Form TextBox, проверяющий достоверность его содержания на основе регулярного выражения.

Краткое обсуждение регулярных выражений

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

  • Регулярные выражения .NET Framework
    В этом разделе документации по .NET Framework содержится введение в концепцию и цель регулярных выражений, а также справочник по использованию релевантных классов в Framework.
  • Примеры регулярных выражений на Web-сайте библиотеки регулярных выражений Ознакомившись с материалом в документации по .NET Framework, на этом Web-сайте можно найти большой список типовых регулярных выражений, которые можно использовать.

Что требуется построить?

Чтобы создать проверяющий достоверность элемент управления TextBox, необходимо выполнить несколько шагов. Сначала нужно создать новый пустой элемент управления, который наследуется из TextBox. Затем нужно добавить новое свойство, в котором будет храниться проверяющее достоверность регулярное выражение, и написать закрытую функцию, проверяющую содержание TextBox на основе свойства регулярного выражения. Наконец, с помощью переопределения события OnValidating данного элемента управления можно проверить, допустимо ли содержание элемента управления, и отменить событие.

Шаг 1: создание нового пользовательского элемента управления

Если элементы управления разрабатываются для себя или для других, их рекомендуется встроить в их собственный проект для совместного использования в качестве откомпилированной сборки (DLL в данном случае), а не передавать код. Учитывая это, создадим новый проект Windows Control Library для хранения нового элемента управления, затем в том же самом решении создадим проект Windows Application для тестирования элемента управления. По умолчанию при создании нового проекта Windows Control Library новый пустой пользовательский элемент управления будет добавлен как точка старта. В этом случае пользовательский элемент управления не будет использоваться, поскольку он наследуется из существующего элемента управления, и поэтому его файл можно удалить и просто добавить новый файл класса.

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

Затем, чтобы определить наследование этого нового класса из класса TextBox, оператор Inherits добавляется к пустому классу Microsoft® Visual Studio® .NET:

Public Class RegExTextBox
    Inherits System.Windows.Forms.TextBox

End Class

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

Шаг 2: добавление нового свойства

В следующем шаге построения этого элемента управления необходимо добавить новое свойство String, в котором будет храниться оператор регулярного выражения. Назовем его RegularExpression, и, кроме свойства, создадим также внутреннюю переменную m_RegularExpression, в которой будет храниться значение свойства. Хотя этот класс описывает элемент управления Windows Form, процедура добавления нового свойства не отличается от процедуры его добавления к любому другому классу Microsoft Visual Basic® .NET:

    Private m_RegularExpression As String

    Public Property RegularExpression() As String
        Get
            Return m_RegularExpression
        End Get
        Set(ByVal Value As String)
            m_RegularExpression = Value
        End Set
    End Property

Чтобы использовать это новое свойство и проверить достоверность содержания TextBox, используется пространство имен System.Text.RegularExpressions. Следуя примерам в справочной документации, можно создать новый объект RegEx, определяющий свойство RegularExpression в конструкторе, и затем использовать его для проверки соответствия содержания TextBox выражению:

    'для упрощения кода Imports System.Text.RegularExpressions добавлен в
    'начало класса 
    Private Function IsValid(ByVal Contents As String) As Boolean
        Dim myRegEx As New Regex(RegularExpression)
        Dim myMatch As Match
        myMatch = myRegEx.Match(Contents)
        Return myMatch.Success
    End Function

Если бы в этой точке был возможен тест элемента управления, можно было бы найти ошибку в этом коде, поскольку если где-нибудь в строке будет найдено соответствие, будет возвращено значение True. При использовании этого кода регулярное выражение для поиска пятизначных почтовых индексов найдет соответствие первых пяти цифр в строке "23434fred", несмотря на дополнительный текст, добавленный в конце. Фактически же необходимо проверить точное соответствие строки выражению. Для правильной работы кода необходимо добавить проверку на совпадение найденного соответствия с полной строкой. В то же время эта проверка заключена в обертку очень простого блока обработки ошибок, при котором недействительное RegularExpression возвращает значение False:

    'для упрощения кода Imports System.Text.RegularExpressions добавлен в
    'начало класса 
    Private Function IsValid(ByVal Contents As String) As Boolean
        Try
            Dim myRegEx As New Regex(RegularExpression)
            Dim myMatch As Match
            myMatch = myRegEx.Match(Contents)
            If myMatch.Success _
              AndAlso myMatch.Index = 0 _
              AndAlso myMatch.Length = Contents.Length Then
                Return True
            Else
                Return False
            End If
        Catch
            'Ошибка при анализе шаблона.
            Return False
        End Try
    End Function

Этот код возвратит значение True, только если соответствие найдено и равно длине всей строки содержания, что и требовалось получить.

Шаг 3: переопределение метода OnValidating

Элементы управления Windows Forms располагают различными методами и событиями, используемыми при проверке правильности, поэтому уместно встроить эту новую проверку RegularExpression в существующую модель с помощью проверки содержания TextBox методом OnValidating. Этот метод будет вызываться всегда, когда элемент управления теряет фокус, а свойство CausesValidation элемента управления равно True. Чтобы этот элемент управления был полезным, даже если проверка правильности не используется (CausesValidation = False), также добавляется свойство только для чтения (Valid), поддерживающее непосредственную проверку правильности содержания:

    Public ReadOnly Property Valid() As Boolean
        Get
            Return IsValid(Text)
        End Get
    End Property
    Protected Overrides Sub OnValidating(ByVal e As _
      System.ComponentModel.CancelEventArgs)
        If Not Valid() Then
            e.Cancel = True
        End If
        MyBase.OnValidating(e)
    End Sub

Объединив весь этот код, можно получить законченный элемент управления, который можно протестировать. Постройте проект элемента управления, затем войдите в проект тестирования (в приложение Windows, добавленное к этому же решению), добавьте ссылку на созданный проект RegExTextBox и настройте панель инструментов, чтобы показать новый элемент управления. После добавления нового TextBox к Windows Form стандартное окно свойств может использоваться для редактирования свойства RegularExpression элемента управления. Некоторые примеры регулярных выражений для тестирования приведены ниже:

  • простой почтовый индекс, проверка пятизначных чисел: "\d{5}";
  • формат даты, проверка MM/DD/YYYY: "\d{1,2}\/\d{1,2}/\d{4}".
    Обратите внимание, что в данном примере проверяется не значение, а только формат. Поэтому "34/58/2341" будет рассматриваться как совершенно правильное значение, не являясь при этом правильным значением даты.

Распределение свойств по категориям и добавление точечного рисунка панели инструментов

При использовании элемента управления в другом проекте возникают некоторые косметические недостатки, которые необходимо исправить, чтобы элемент управления выглядел профессионально. Первая проблема: если не определить конкретную категорию, свойства появляются внизу списка Properties в категории Misc согласно поведению по умолчанию.

Присвоение свойств категориям

Добавление атрибута к определению свойства позволяет легко распределить свойства по категориям или даже скрыть их в окне Properties. У данного элемента управления имеется два свойства: Valid и RegularExpression. Присвоим RegularExpression категории "Behavior" (поведение). Здесь нет реальных ограничений на присвоение конкретного свойства, можно даже создать собственную категорию. Для определения соответствующей категории будет использоваться атрибут System.ComponentModel.Category; однако обратите внимание, что он принимает как параметр только строку, поэтому имя категории необходимо написать правильно:

    <System.ComponentModel.Category("Behavior")> _
     Public Property RegularExpression() As String
        Get
      …

Автор статьи, как канадец, сразу "правильно" написал слово "behavior" (поведение) и закончил новую категорию в окне Properties.

Рис. 1. Можно использовать любое имя категории, оно появится как раздел окна свойств.

Независимо от правильности написания имени категории можно заметить, что у нового свойства отсутствует описание (которое обычно выводится в нижней области окна Properties). Для этого, как можно предположить, используется другой атрибут. Атрибут System.ComponentModel.Description принимает в качестве параметра строку, которая выводится всегда, когда это свойство выбрано в окне Properties:

Private Const regularExpressionDescription As String _
= "The Regular Expression used to validate the contents of this TextBox"

    <System.ComponentModel.Category("Behavior"), _
    System.ComponentModel.Description(regularExpressionDescription)> _
    Public Property RegularExpression() As String
        Get

В отличие от RegularExpression, при разработке свойство Valid не очень полезно (это свойство - только для чтения и вычисляется на основании содержания TextBox), поэтому оно будет скрыто в окне Properties в любой категории. Для этого можно использовать другой атрибут System.ComponentModel.Browsable, который принимает булевский параметр, определяющий вывод свойства в окне Properties:

<System.ComponentModel.Browsable(False)> _
    Public ReadOnly Property Valid() As Boolean
        Get
            Return IsValid(Text)
        End Get
    End Property

Добавление точечного рисунка на панели инструментов

Другая проблема с видом нового элемента управления состоит в том, что значок на панели инструментов не был определен. Поэтому вместо этого используется значок элемента управления по умолчанию. Как и категории свойств, значок на панели инструментов добавляется с помощью атрибутов, в данном случае с помощью атрибута ToolboxBitmap. Этот атрибут позволяет определить путь к фактическому файлу точечной графики (16-x-16) или точечный рисунок на панели инструментов, который внедрен в сборку как ресурс. В этом примере определяется только путь к файлу, и используется точечный рисунок на панели инструментов, созданный в программе Paint:

<ToolboxBitmap("C:\mytoolboxbitmap.bmp")> _
Public Class regexTextBox
    Inherits System.Windows.Forms.TextBox

Пример 1b: альтернативный способ добавления проверки правильности регулярного выражения

Построение собственной версии элемента управления TextBox - это один из способов добавления дополнительных функциональных возможностей. Однако в .NET подобного результата можно достигнуть также с помощью объекта расширителя функциональности. Расширители функциональности, например, компоненты ErrorProvider или ToolTip, которые уже существуют в Windows Forms, позволяют динамически добавлять свойства к другим элементам управления. С помощью такого компонента можно добавить свойство RegularExpression ко всем элементам управления TextBox в данной форме и предоставить службы проверки правильности любому элементу управления, имеющему значение для этого нового свойства. В этом конкретном случае конечный результат не отличается от построения собственного варианта TextBox, однако подход с использованием расширителей функциональности хорошо работает для любых функциональных возможностей, которые требуется применить сразу для всей группы элементов управления.

Создание собственного расширителя функциональности

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

Public Class regexRevisted
    Inherits System.ComponentModel.Component
    Implements System.ComponentModel.IExtenderProvider

End Class

Добавление атрибутов для каждого свойства

После объявления класса необходимо добавить атрибут для каждого свойства, которое требуется предоставить другим элементам управления. В данном случае добавим свойство ValidationExpression, хранящее регулярные выражения для каждого элемента управления TextBox, и свойство Valid, возвращающее значение True или False, которое указывает, выполняется ли текущее ValidationExpression. Требуется добавить атрибут System.ComponentModel.ProvideProperty, имеющий два параметра для своего конструктора: имя нового свойства, которое необходимо предоставить, и тип элемента управления, к которому это новое свойство будет добавлено. Итак, в этом случае добавим следующий код:

<ProvideProperty("ValidationExpression", GetType(TextBox)), _
ProvideProperty("Valid", GetType(TextBox))> _
Public Class regexRevisted

Примечание Документация по ProvideProperty весьма запутана; предполагалось, что второй параметр - это тип свойства, однако он не работает с помощью GetType(String). К счастью, эта ошибка была обнаружена довольно быстро, когда код был передан в Microsoft, и параметр был изменен на GetType(TextBox).

Создание процедур свойств

Для каждого свойства необходимо определить использование атрибутов, а также предоставить процедуры Get и Set для просмотра и редактирования свойства во всех других элементах управления. Эти процедуры связаны с предоставляемыми свойствами только именем:

Public Function GetValidationExpression(ByVal o As TextBox) As String

Public Sub SetValidationExpression(ByVal o As TextBox, _
      ByVal ValidationExpression As String)

В этих процедурах свойств набор значений должен быть сохранен для каждого элемента управления, что позволяет отслеживать, какое значение свойства было применено к тому или иному элементу управления. Для реализации этого в коде был добавлен параметр NameValueCollection, который для каждого элемента управления отслеживает свойство ValidationExpression, устанавливающее какое-либо значение. NameValueCollection позволяет связать коллекцию строковых значений со строковыми ключевыми значениями, что очень похоже на объект Dictionary, однако имеет строгий контроль типов для работы только со строками. В этом случае отдельный элемент ValidationExpression был связан с именем соответствующего элемента управления. Имя элемента управления должно быть уникальным в пределах одной формы, поэтому необходимо убедиться в отсутствии конфликтов:

    Dim RegExpressions As New _
      System.Collections.Specialized.NameValueCollection()

    Public Function GetValidationExpression(ByVal o As TextBox) As String
        Return RegExpressions.Get(o.Name)
    End Function

    Public Sub SetValidationExpression(ByVal o As TextBox, _
            ByVal ValidationExpression As String)
        RegExpressions.Set(o.Name, ValidationExpression)
    End Sub

В дополнение к установке и получению значения регулярного выражения добавим также обработчик событий к любому элементу управления, устанавливающему непустое значение (указание на то, что элементу управления требуется проверка правильности). Этот обработчик событий позволяет перехватить событие OnValidation каждого TextBox и с помощью ExtenderProvider проверить достоверность содержания TextBox точно так же, как это делает RegExTextBox (см. Пример 1a). Если проверка правильности оказалась неуспешной, генерируется событие ExtenderProvider, позволяющее одному обработчику событий перехватывать все ошибки проверки правильности связанных элементов управления:

    Public Sub SetValidationExpression(ByVal o As TextBox, _
            ByVal ValidationExpression As String)
        RegExpressions.Set(o.Name, ValidationExpression)
        If ValidationExpression <> "" Then
            AddHandler o.Validating, _
     New System.ComponentModel.CancelEventHandler(AddressOf OnValidating)
        Else
            RemoveHandler o.Validating, _
     New System.ComponentModel.CancelEventHandler(AddressOf OnValidating)
        End If
    End Sub

    Private Sub OnValidating(ByVal sender As Object, _
            ByVal e As System.ComponentModel.CancelEventArgs)
        Dim tb As TextBox
        If TypeOf sender Is TextBox Then
            tb = CType(sender, TextBox)
            Dim validationExpression As String
            validationExpression = RegExpressions.Get(tb.Name)
            If validationExpression <> "" Then
                If Not IsValid(validationExpression, tb.Text) Then
                    RaiseEvent ValidationError(tb, _
                     New System.EventArgs())
                End If
            End If
        End If
    End Sub

Обратите внимание, что обработчик следует удалить, если свойство ValidationExpression установлено на пустую строку; обработка события или прочая работа с элементом управления, который не работает с данным расширителем, бессмысленна. Теперь свойство Valid немного проще реализовать, поскольку оно является свойством только для чтения и требует только функцию GetValid, которую необходимо создать. Эта функция (фактически вызывающая другую функцию IsValid) проверяет содержание определенного TextBox на основе его свойства ValidationExpression и возвращает значение True или False согласно соответствию содержания выражению:

    Private Function IsValid(ByVal validationExpression As String, _
            ByVal input As String) As Boolean
        Dim reCheck As New Regex(validationExpression)
        Dim myMatch As Match
        myMatch = reCheck.Match(input)
        If Not (myMatch.Success AndAlso _
              myMatch.Index = 0 AndAlso _
              myMatch.Length = input.Length) Then
            Return False
        Else
            Return True
        End If
    End Function

    Public Function GetValid(ByVal o As TextBox) As Boolean
        Dim validationExpression As String
        validationExpression = RegExpressions.Get(o.Name)
        If validationExpression <> "" Then
            Return IsValid(validationExpression, o.Text)
        Else
            Return True
        End If
    End Function

Реализация функции CanExtend

Хотя логичнее сначала создать эту функцию, необходимую интерфейсу IExtenderProvider, который будет запрашивать эту функцию до тех пор, пока она не будет добавлена, последней частью кода было добавление реализации CanExtend. Ключевой задачей CanExtend является возвращение значения True или False для каждого проверяемого элемента управления, указывающего на необходимость применения двух новых свойств к данному элементу управления. В случае с данным ExtenderProvider требуется применить эти свойства к каждому TextBox, поэтому необходимо просто проверить тип предоставленного элемента управления и возвратить значение True, если это элемент управления TextBox, или False в противном случае. Приняв решение обрабатывать элемент управления, также добавим пустой элемент в NameValueCollection как метку-заполнитель для возможного ValidationExpression:

    Public Function CanExtend(ByVal extendee As Object) As Boolean _
     Implements System.ComponentModel.IExtenderProvider.CanExtend
        If TypeOf extendee Is System.Windows.Forms.TextBox Then
            RegExpressions.Set(CType(extendee, TextBox).Name, "")
            Return True
        Else
            Return False
        End If
    End Function

Последние штрихи

Как и в прежнем элементе управления, всегда имеется несколько дополнительных атрибутов, которые можно установить, или дополнительный код, который можно добавить, чтобы элемент управления был более полезен или выглядел более профессионально. В случае с данным ExtenderProvider случайный вызов процедур Get и Set для двух новых свойств нежелателен, поэтому их можно скрыть от Microsoft Intellisense® с помощью атрибута EditorBrowsableAttribute:
    <EditorBrowsableAttribute(EditorBrowsableState.Never)> _
    Public Function GetValid(ByVal o As TextBox) As Boolean

Дополнительная информация о ExtenderProvider содержится в пошаговом разборе этого процесса в документации по .NET Framework, код для этого примера является частью загрузки для этой статьи. После размещения в Windows Form готовый ExtenderProvider, называющийся regexRevisited, добавляет к каждому TextBox два свойства - ValidationExpression и Valid. Конечный результат и действия разработчика очень похожи на замену каждого TextBox пользовательским регулярным выражением TextBox, созданным ранее, однако весь код содержится в одном компоненте.

Резюме

В результате обе версии этого примера позволяют выполнить проверку правильности TextBox с помощью регулярных выражений, однако для этого используются различные способы. Рекомендовать тот или иной метод довольно сложно, поскольку они оба работают, и код отличается незначительно. Однако разработчику необходимо знать оба способа добавления возможностей к элементам управления Windows Forms, чтобы выбрать наиболее подходящее решение для того или иного проекта.


Может пригодится:


Автор: Дункан Маккензи
Прочитано: 4716
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (1)

Прислал: basis911
Электронная биржа недвижимости БРОКЕР приглашает агентства недвижимости и независимых маклеров к взаимовыгодному сотрудничеству. (068) 1200222, http://brok.biz.ua/

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру