Imports System.Collections.Generic
'''
'''Encapsulates the rendering of a list of items. Each item's description is shown in a list, and a single item is selected.
'''
'''The type of item that this ItemListView will draw.
Public Class ItemListView(Of T As IItem)
Implements IDisposable
Private Const percentOfArticleDisplayBoxToFillWithText As Single = 0.5F
Private Const percentOfFontHeightForSelectionBox As Single = 1.5F
Private Const padding As Integer = 20
' Where to draw
Private m_location As Point
Private m_size As Size
Private m_title As String
Private m_itemFont As Font
Private m_titleFont As Font
Private m_backColor As Color
Private m_borderColor As Color
Private m_foreColor As Color
Private m_titleBackColor As Color
Private m_titleForeColor As Color
Private m_selectedForeColor As Color
Private m_selectedBackColor As Color
Private m_itemFontHeight As Single
' An index of the currently selected item
Private m_selectedIndex As Integer = 0
' The underlying RssChannel to display
Private m_items As IList(Of T)
Private m_maxItemsToShow As Integer
' The minimum number of articles that will be displayed
' If there are less items than this in the RSS channel
' then there will be blank space in the display
Private m_minItemsToShow As Integer
'''
''' Gets the number of articles that will be displayed.
'''
Private ReadOnly Property NumArticles() As Integer
Get
Return Math.Min(Me.m_items.Count, MaxItemsToShow)
End Get
End Property
'''
''' Gets the number of rows that will appear in the display.
'''
'''
''' This may be more than NumArticles if there are less articles available than
''' would fill up the minimum number of rows.
'''
Private ReadOnly Property NumArticleRows() As Integer
Get
Return Math.Max(NumArticles(), MinItemsToShow)
End Get
End Property
Public Property Location() As Point
Get
Return Me.m_location
End Get
Set(ByVal value As Point)
Me.m_location = value
End Set
End Property
Public Property Size() As Size
Get
Return Me.m_size
End Get
Set(ByVal value As Size)
Me.m_size = value
End Set
End Property
Public Property ForeColor() As Color
Get
Return Me.m_foreColor
End Get
Set(ByVal value As Color)
Me.m_foreColor = value
End Set
End Property
Public Property BackColor() As Color
Get
Return Me.m_backColor
End Get
Set(ByVal value As Color)
Me.m_backColor = value
End Set
End Property
Public Property BorderColor() As Color
Get
Return Me.m_borderColor
End Get
Set(ByVal value As Color)
Me.m_borderColor = value
End Set
End Property
Public Property TitleForeColor() As Color
Get
Return Me.m_titleForeColor
End Get
Set(ByVal value As Color)
Me.m_titleForeColor = value
End Set
End Property
Public Property TitleBackColor() As Color
Get
Return Me.m_titleBackColor
End Get
Set(ByVal value As Color)
Me.m_titleBackColor = value
End Set
End Property
Public Property SelectedForeColor() As Color
Get
Return Me.m_selectedForeColor
End Get
Set(ByVal value As Color)
Me.m_selectedForeColor = value
End Set
End Property
Public Property SelectedBackColor() As Color
Get
Return Me.m_selectedBackColor
End Get
Set(ByVal value As Color)
Me.m_selectedBackColor = value
End Set
End Property
Public Property MaxItemsToShow() As Integer
Get
Return Me.m_maxItemsToShow
End Get
Set(ByVal value As Integer)
Me.m_maxItemsToShow = value
End Set
End Property
Public Property MinItemsToShow() As Integer
Get
Return Me.m_minItemsToShow
End Get
Set(ByVal value As Integer)
Me.m_minItemsToShow = value
End Set
End Property
Public ReadOnly Property SelectedIndex() As Integer
Get
Return Me.m_selectedIndex
End Get
End Property
Public ReadOnly Property SelectedItem() As T
Get
Return Me.m_items(Me.SelectedIndex)
End Get
End Property
Public ReadOnly Property RowHeight() As Integer
Get
' There is one row for each item plus 2 rows for the title.
Return Me.Size.Height / (NumArticleRows + 2)
End Get
End Property
Public ReadOnly Property ItemFont() As Font
Get
' Choose a font for each of the item titles that will fit all numItems
' of them (plus some slack for the title) in the control
m_itemFontHeight = System.Convert.ToSingle(percentOfArticleDisplayBoxToFillWithText * RowHeight)
If Me.m_itemFont Is Nothing OrElse Me.m_itemFont.Size <> m_itemFontHeight Then
Me.m_itemFont = New Font("Microsoft Sans Serif", m_itemFontHeight, GraphicsUnit.Pixel)
End If
Return Me.m_itemFont
End Get
End Property
Public ReadOnly Property TitleFont() As Font
Get
' Choose a font for the title text.
' This font will be twice as big as the ItemFont
Dim titleFontHeight As Single = System.Convert.ToSingle(percentOfArticleDisplayBoxToFillWithText * 2 * RowHeight)
If Me.m_titleFont Is Nothing OrElse Me.m_titleFont.Size <> titleFontHeight Then
Me.m_titleFont = New Font("Microsoft Sans Serif", titleFontHeight, GraphicsUnit.Pixel)
End If
Return Me.m_titleFont
End Get
End Property
Public Sub NextArticle()
If Me.m_selectedIndex < NumArticles - 1 Then
Me.m_selectedIndex += 1
Else
Me.m_selectedIndex = 0
End If
End Sub
Public Sub PreviousArticle()
If Me.m_selectedIndex > 0 Then
Me.m_selectedIndex -= 1
Else
Me.m_selectedIndex = NumArticles - 1
End If
End Sub
Public Sub New(ByVal title As String, ByVal items As IList(Of T))
If items Is Nothing Then
Throw New ArgumentException("Items cannot be null", "items")
End If
Me.m_items = items
Me.m_title = title
End Sub
Public Sub Paint(ByVal args As PaintEventArgs)
Dim g As Graphics = args.Graphics
' Settings to make the text drawing look nice
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit
DrawBackground(g)
' Draw each article's description
Dim index As Integer = 0
Do While ((index < Me.m_items.Count) And (index < Me.MaxItemsToShow))
DrawItemTitle(g, index)
index += 1
Loop
' Draw the title text
DrawTitle(g)
End Sub
'''
'''Draws a box and border ontop of which the text of the items can be drawn.
'''
'''The Graphics object to draw onto
Private Sub DrawBackground(ByVal g As Graphics)
Using backBrush As New SolidBrush(BackColor)
g.FillRectangle(backBrush, New Rectangle(Location.X + 4, Location.Y + 4, Size.Width - 8, Size.Height - 8))
End Using
Using borderPen As New Pen(BorderColor, 4)
g.DrawRectangle(borderPen, New Rectangle(Location, Size))
End Using
End Sub
'''
'''Draws the title of the item with the given index.
'''
'''The Graphics object to draw onto
'''The index of the item in the list
Private Sub DrawItemTitle(ByVal g As Graphics, ByVal index As Integer)
Dim stringFormat As New StringFormat(StringFormatFlags.LineLimit)
stringFormat.Trimming = StringTrimming.EllipsisCharacter
Dim articleRect As New Rectangle(Location.X + padding, Location.Y + (index * RowHeight) + padding, Size.Width - (2 * padding), Fix(percentOfFontHeightForSelectionBox * Me.m_itemFontHeight))
' Select color and draw border if current index is selected
Dim textBrushColor As Color = ForeColor
If index = SelectedIndex Then
textBrushColor = SelectedForeColor
Using backBrush As New SolidBrush(SelectedBackColor)
g.FillRectangle(backBrush, articleRect)
End Using
End If
' Draw the title of the item
Dim textToDraw As String = Me.m_items(index).Title
Using textBrush As New SolidBrush(textBrushColor)
g.DrawString(textToDraw, ItemFont, textBrush, articleRect, stringFormat)
End Using
End Sub
'''
'''Draws a title bar.
'''
'''The Graphics object to draw onto
Private Sub DrawTitle(ByVal g As Graphics)
Dim titleLocation As New Point(Location.X + padding, Location.Y + Size.Height - RowHeight - padding)
Dim titleSize As New Size(Size.Width - (2 * padding), 2 * RowHeight)
Dim titleRectangle As New Rectangle(titleLocation, titleSize)
' Draw the title box and the selected item box
Using titleBackBrush As New SolidBrush(TitleBackColor)
g.FillRectangle(titleBackBrush, titleRectangle)
End Using
' Draw the title text
Dim titleFormat As New StringFormat(StringFormatFlags.LineLimit)
titleFormat.Alignment = StringAlignment.Far
titleFormat.Trimming = StringTrimming.EllipsisCharacter
Using titleBrush As New SolidBrush(TitleForeColor)
g.DrawString(Me.m_title, TitleFont, titleBrush, titleRectangle, titleFormat)
End Using
End Sub
'''
'''Dispose all disposable fields
'''
Public Sub Dispose() Implements IDisposable.Dispose
If m_itemFont IsNot Nothing Then
m_itemFont.Dispose()
End If
If m_titleFont IsNot Nothing Then
m_titleFont.Dispose()
End If
End Sub
End Class