Вот мой опус.
Imports System
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Collections.Generic
Public Class RangeListBox
Inherits ListBox
Private _minValue As Integer
Private _maxValue As Integer
Private _items As RangeList
Private Const defaultMinValue As Integer = 0
Private Const defaultMaxValue As Integer = 999999
Public Sub New()
MyBase.New()
_items = New RangeList()
_minValue = defaultMinValue
_maxValue = defaultMaxValue
End Sub
<DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible), _
DescriptionAttribute("Min value of range."), CategoryAttribute("Constraints"), _
DefaultValue(defaultMinValue), BrowsableAttribute(True), LocalizableAttribute(False)> _
Public Property MinValue() As Integer
Get
Return _minValue
End Get
Set(ByVal value As Integer)
If value > _minValue Then
Throw New MaxLessMinException("Минимальное значение должно быть меньше или равно максимальному.")
' TODO: В режиме дизана формы не генерировать исключение.
Else
_maxValue = value
End If
End Set
End Property
<DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible), _
DescriptionAttribute("Max value of range."), CategoryAttribute("Constraints"), _
DefaultValue(defaultMaxValue), BrowsableAttribute(True), LocalizableAttribute(False)> _
Public Property MaxValue() As Integer
Get
Return _maxValue
End Get
Set(ByVal value As Integer)
If value < _minValue Then
Throw New MaxLessMinException("Максимальное значение должно быть больше или равно минимальному.")
' TODO: В режиме дизана формы не генерировать исключение.
Else
_maxValue = value
End If
End Set
End Property
<LocalizableAttribute(True)> _
Public Shadows ReadOnly Property Items() As RangeList
Get
Return _items
End Get
End Property
End Class ' RangeListBox
Public Class RangeList
Inherits CollectionBase
'Inherits ListBox.ObjectCollection
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal Capacity As Integer)
MyBase.New(Capacity)
End Sub
Public Shadows Function Add(ByVal value As RangeItem) As Integer
'Insert(Count, value)
'Return Count
Return List.Add(value)
End Function 'Add
Default Public Property Item(ByVal index As Integer) As RangeItem
Get
Return CType(List(index), RangeItem)
End Get
Set(ByVal value As RangeItem)
List(index) = value
End Set
End Property
Public Shadows Sub Insert(ByVal index As Integer, ByVal value As RangeItem)
'Dim ExistentItemIndex As Integer = List.IndexOf(value)
'' Не допустим пересечения диапазонов.
'' TODO: реализовать опциональность такого поведения.
'If ExistentItemIndex > -1 Then
' Dim ExistentRangeItem As RangeItem
' ExistentRangeItem = CType(Item(ExistentItemIndex), RangeItem)
' ' Манипуляции с проверкой на существование/перекрытие/вхождение с выводом соответствующих сообщений
' If value.IsOneNumber Then
' If ExistentRangeItem.IsOneNumber Then
' Throw New RangesIntersectionException("Номер уже присутствует в списке.")
' Else
' Throw New RangesIntersectionException("Номер входит в диапазон, присутствующий в списке.")
' End If
' Else
' If ExistentRangeItem.IsOneNumber Then
' Throw New RangesIntersectionException("В списке присутствует один или несколько номеров, принадлежащих диапазону.")
' Else
' If value.BottomValue = ExistentRangeItem.BottomValue And value.TopValue = ExistentRangeItem.TopValue Then
' Throw New RangesIntersectionException("Диапазон уже присутствует в списке.")
' Else
' Throw New RangesIntersectionException("Диапазон пересекается с присутствущим в списке.")
' End If
' End If
' End If
'End If
List.Insert(index, value)
End Sub 'Insert
'Public Property AllowIntersection() As Boolean
' Get
' Return _allowIntersection
' End Get
' Set(ByVal value As Boolean)
' If Not value AndAlso List.Count > 0 Then
' 'Throw New RangesIntersectionException("")
' 'TODO: сделать интеллектуальное изменение свойства.
' End If
' _allowIntersection = value
' End Set
'End Property
'Private _allowIntersection As Boolean
End Class ' RangeList
Public Class RangeItem
Inherits Object
Sub New()
MyBase.New()
_bottomValue = 0
_topValue = 0
End Sub
Sub New(ByVal Value As RangeItem)
MyBase.New()
_bottomValue = Value.BottomValue
_topValue = Value.TopValue
End Sub
Sub New(ByVal Value As Integer)
MyBase.New()
_bottomValue = Value
_topValue = Value
End Sub
Sub New(ByVal BottomValue As Integer, ByVal TopValue As Integer)
MyBase.New()
_bottomValue = BottomValue
_topValue = TopValue
End Sub
Public Property BottomValue() As Integer
Get
Return _bottomValue
End Get
Set(ByVal value As Integer)
If value > _topValue Then
Throw New MaxLessMinException("Нижнее значение диапазона должно быть меньше верхнего.")
Else
_bottomValue = value
End If
End Set
End Property
Public Property TopValue() As Integer
Get
Return _topValue
End Get
Set(ByVal value As Integer)
If value < _bottomValue Then
Throw New MaxLessMinException("Верхнее значение диапазона должно быть больше нижнего.")
Else
_topValue = value
End If
End Set
End Property
Public ReadOnly Property IsOneNumber() As Boolean
Get
Return Me.BottomValue = Me.TopValue
End Get
End Property
Public Overrides Function ToString() As String
If IsOneNumber Then
Return Convert.ToString(BottomValue)
Else
Return Convert.ToString(BottomValue & "-" & TopValue)
End If
End Function
Public Overrides Function Equals(ByVal obj As Object) As Boolean
' Check for null values and compare run-time types.
If obj Is Nothing Then
Return False
Else
If Not Me.GetType() Is obj.GetType() Then
Return False
End If
End If
Dim OtherRangeItem As RangeItem = CType(obj, RangeItem)
' Проведём сложную провеку, суть которой в том чтобы выявить
' 1) если введён номер, то есть ли уже он в списке или входит в какой-либо диапазон из списка;
' 2) если введён диапазон номеров, то есть ли уже он в списке или есть в списке номера/диапазоны номеров которые пересекаются с ним.
Return (Me.IsOneNumber And OtherRangeItem.IsOneNumber And Me.BottomValue = OtherRangeItem.BottomValue) Or _
(Me.IsOneNumber And Not OtherRangeItem.IsOneNumber And Me.BottomValue >= OtherRangeItem.BottomValue And Me.BottomValue <= OtherRangeItem.TopValue) Or _
(Not Me.IsOneNumber And OtherRangeItem.IsOneNumber And OtherRangeItem.BottomValue >= Me.BottomValue And OtherRangeItem.BottomValue <= Me.TopValue) Or _
(Not Me.IsOneNumber And Not OtherRangeItem.IsOneNumber And Me.BottomValue <= OtherRangeItem.TopValue And Me.TopValue >= OtherRangeItem.BottomValue)
End Function
Private _topValue As Integer
Private _bottomValue As Integer
End Class ' RangeItem
' Мои исключения.
Public Class MaxLessMinException
Inherits ArgumentOutOfRangeException
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal Message As String)
MyBase.New(Message)
End Sub
Public Sub New(ByVal Message As String, ByVal InnerEx As Exception)
MyBase.New(Message, InnerEx)
End Sub
End Class ' MaxLessMinException
Public Class RangesIntersectionException
Inherits InvalidOperationException
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal Message As String)
MyBase.New(Message)
End Sub
Public Sub New(ByVal Message As String, ByVal InnerEx As Exception)
MyBase.New(Message, InnerEx)
End Sub
End Class 'RangesIntersectionException