フリーソフト等で、リストビューのヘッダーが標準のものからカスタマイズされていることがありますよね。
例えば、FenrirFSが該当します。

このような感じの見た目になるようなStylishListViewというListViewコントロールを作ってみました。
今回は、ヘッダーのカスタマイズの他に、奇数行、偶数行の色分けも実装しました。
左が標準コントロール、右が今回作成したカスタムコントロールです。


実装プロパティ説明
コントロールには、以下のプロパティが実装されています。
| 項目名 |
説明 |
| HeaderTopColor |
ヘッダーの上部色 |
| HeaderBottomColor |
ヘッダーの下部色 |
| HeaderBorderColor |
ヘッダーの枠線色 |
| ViewStylishHeader |
ヘッダーをカスタマイズするか |
| EvenBackColor |
偶数行の背景色 |
| EvenForeColor |
偶数行の前景色 |
| OddBackColor |
奇数行の背景色 |
| OddForeColor |
奇数行の前景色 |
| OddEvenColorCoding |
奇数、偶数行を色分けするか |
ソースダウンロード
以下からソースファイルをダウンロード出来ます。ソースのライセンスはGPLです。

ダウンロード出来るソリューションについて
このソリューションは、コントロールが実装されている「StylishListView」プロジェクトとコントロールのテスト用プロジェクト「StylishListViewTest」の2つで出来ています。
開発言語はVB.NETで、開発環境はVisual Studio 2005です。
「StylishListView」プロジェクトは、ListViewコントロールを継承したStylishListViewコントロールと、ヘッダー画像を描画するListViewImageクラスの2つで出来ています。
ヘッダーのカスタマイズ方法について
OnDrawColumnHeaderメソッドでヘッダー描画を行います。
まず始めに、e.Graphics.DrawImageで背景画像の描画を行います。
次に、e.Graphics.DrawStringでヘッダーに表示するテキストを描画します。
ちなみに
今回は、ヘッダーには文字のみ描画していますが、画像を表示することも可能なので、ソート用のアイコンを表示したりも出来ます。
通常、リストアイテムには、左端にしかアイコンは表示出来ませんが、OnDrawSubItemメソッドを使うと、リストのサブアイテムにもアイコンや画像を表示することが出来ます。
StylishListViewコントロールのソース
ソースのライセンスはGPLです。
''' <summary>
''' 標準ListViewをちょっとオシャレにカスタマイズしたコントロールです。
''' </summary>
''' <remarks>
''' ライセンス:GNU General Public License (http://www.gnu.org/licenses/gpl.html)
''' 著作者:rider (http://www.lasical.com/)
''' </remarks>
Public Class StylishListView
#Region "変数"
''' <summary>
''' ヘッダーの上部色です。
''' </summary>
''' <remarks></remarks>
Private _HeaderTopColor As Color = System.Drawing.ColorTranslator.FromHtml("#DCDCDC")
''' <summary>
''' ヘッダーの下部色です。
''' </summary>
''' <remarks></remarks>
Private _HeaderBottomColor As Color = System.Drawing.ColorTranslator.FromHtml("#CDCDCD")
''' <summary>
''' ヘッダーの枠線色です。
''' </summary>
''' <remarks></remarks>
Private _HeaderBorderColor As Color = System.Drawing.ColorTranslator.FromHtml("#7F7F7F")
''' <summary>
''' ヘッダーをカスタマイズするかの値です。
''' </summary>
''' <remarks></remarks>
Private _ViewStylishHeader As Boolean = False
''' <summary>
''' 偶数行の背景色です。
''' </summary>
''' <remarks></remarks>
Private _EvenBackColor As Color = SystemColors.Window
''' <summary>
''' 偶数行の前景色です。
''' </summary>
''' <remarks></remarks>
Private _EvenForeColor As Color = SystemColors.WindowText
''' <summary>
''' 奇数行の背景色です。
''' </summary>
''' <remarks></remarks>
Private _OddBackColor As Color = SystemColors.Window
''' <summary>
''' 奇数行の前景色です。
''' </summary>
''' <remarks></remarks>
Private _OddForeColor As Color = SystemColors.WindowText
''' <summary>
''' 奇数、偶数行を色分けするかの値です。
''' </summary>
''' <remarks></remarks>
Private _OddEvenColorCoding As Boolean = False
Const WM_PAINT As Integer = &HF
#End Region
#Region "プロパティ"
''' <summary>
''' ヘッダーの上部色を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("ヘッダーの上部色を示します。")> _
<Category("カスタム - ヘッダー")> _
Public Property HeaderTopColor() As Color
Get
Return Me._HeaderTopColor
End Get
Set(ByVal value As Color)
Me._HeaderTopColor = value
End Set
End Property
''' <summary>
''' ヘッダーの下部色を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("ヘッダーの下部色を示します。")> _
<Category("カスタム - ヘッダー")> _
Public Property HeaderBottomColor() As Color
Get
Return Me._HeaderBottomColor
End Get
Set(ByVal value As Color)
Me._HeaderBottomColor = value
End Set
End Property
''' <summary>
''' ヘッダーの枠線色を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("ヘッダーの枠線色を示します。")> _
<Category("カスタム - ヘッダー")> _
Public Property HeaderBorderColor() As Color
Get
Return Me._HeaderBorderColor
End Get
Set(ByVal value As Color)
Me._HeaderBorderColor = value
End Set
End Property
''' <summary>
''' ヘッダーをカスタマイズするかの値を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("ヘッダーをカスタマイズするかの値を示します。")> _
<Category("カスタム - ヘッダー")> _
<DefaultValue(GetType(Boolean), "False")> _
Public Property ViewStylishHeader() As Boolean
Get
Return Me._ViewStylishHeader
End Get
Set(ByVal value As Boolean)
Me._ViewStylishHeader = value
If value Then
'オーナードローを有効に変更
Me.OwnerDraw = True
End If
End Set
End Property
''' <summary>
''' 偶数行の背景色を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("偶数行の背景色を示します。")> _
<Category("カスタム - リスト")> _
<DefaultValue(GetType(Color), "Window")> _
Public Property EvenBackColor() As Color
Get
Return Me._EvenBackColor
End Get
Set(ByVal value As Color)
Me._EvenBackColor = value
End Set
End Property
''' <summary>
''' 偶数行の前景色を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("偶数行の前景色を示します。")> _
<Category("カスタム - リスト")> _
<DefaultValue(GetType(Color), "WindowText")> _
Public Property EvenForeColor() As Color
Get
Return Me._EvenForeColor
End Get
Set(ByVal value As Color)
Me._EvenForeColor = value
End Set
End Property
''' <summary>
''' 奇数行の背景色を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("奇数行の背景色を示します。")> _
<Category("カスタム - リスト")> _
<DefaultValue(GetType(Color), "Window")> _
Public Property OddBackColor() As Color
Get
Return Me._OddBackColor
End Get
Set(ByVal value As Color)
Me._OddBackColor = value
End Set
End Property
''' <summary>
''' 奇数行の前景色を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("奇数行の前景色を示します。")> _
<Category("カスタム - リスト")> _
<DefaultValue(GetType(Color), "WindowText")> _
Public Property OddForeColor() As Color
Get
Return Me._OddForeColor
End Get
Set(ByVal value As Color)
Me._OddForeColor = value
End Set
End Property
''' <summary>
''' 奇数、偶数行を色分けするかの値を取得または設定します。
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Description("奇数、偶数行を色分けするかの値を示します。")> _
<Category("カスタム - リスト")> _
<DefaultValue(GetType(Boolean), "False")> _
Public Property OddEvenColorCoding() As Boolean
Get
Return Me._OddEvenColorCoding
End Get
Set(ByVal value As Boolean)
Me._OddEvenColorCoding = value
End Set
End Property
#End Region
#Region "コンストラクタ"
''' <summary>
''' StylishListViewのコンストラクタです。
''' </summary>
''' <remarks></remarks>
Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
'リストビューを詳細表示に設定
Me.View = System.Windows.Forms.View.Details
End Sub
#End Region
#Region "WndProc"
''' <summary>
''' WndProcをオーバーライド
''' </summary>
''' <param name="m"></param>
''' <remarks></remarks>
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
'メッセージの種類
Select Case m.Msg
Case WM_PAINT
'リストの偶数、奇数の色分けをするか(デザインモードの時も処理しない)
If DesignMode = False AndAlso Me._OddEvenColorCoding Then
Me.OnPaint(New PaintEventArgs(Me.CreateGraphics, Me.Bounds))
End If
End Select
End Sub
#End Region
#Region "イベント"
''' <summary>
''' ペイントメソッドオーバーライド
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
'偶数行と奇数行の色分け
For i As Integer = 0 To Me.Items.Count - 1
If i / 2 <> Int(i / 2) Then
Me.Items(i).BackColor = Me._EvenBackColor
Me.Items(i).ForeColor = Me._EvenForeColor
Else
Me.Items(i).BackColor = Me._OddBackColor
Me.Items(i).ForeColor = Me._OddForeColor
End If
Next
End Sub
#End Region
#Region "ヘッダー描画時"
''' <summary>
''' ヘッダー描画時の処理です。
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnDrawColumnHeader(ByVal e As System.Windows.Forms.DrawListViewColumnHeaderEventArgs)
MyBase.OnDrawColumnHeader(e)
'カスタムヘッダーを使うか
If Me._ViewStylishHeader Then
'自分で描画
e.DrawDefault = False
Else
'標準描画
e.DrawDefault = True
'終了
Exit Sub
End If
Dim TextBrush As System.Drawing.Brush
Dim HeaderStringFormat As StringFormat
'ヘッダーテキストのブラシ取得
TextBrush = New SolidBrush(e.ForeColor)
'ヘッダーテキストの描画フォーマット取得
HeaderStringFormat = GetDrawHeaderStringFormat(e.ColumnIndex)
'背景描画
e.Graphics.DrawImage(ListViewImage.HeaderBackgroundImage(e.Bounds.Width, e.Bounds.Height - 1, Me._HeaderTopColor, Me._HeaderBottomColor, Me._HeaderBorderColor, e.ColumnIndex), e.Bounds.Left, e.Bounds.Top)
'テキスト描画
e.Graphics.DrawString(e.Header.Text, e.Font, TextBrush, e.Bounds, HeaderStringFormat)
'開放
TextBrush.Dispose()
End Sub
#End Region
#Region "アイテム描画時"
''' <summary>
''' アイテム描画時の処理です。
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawListViewItemEventArgs)
MyBase.OnDrawItem(e)
'標準描画
e.DrawDefault = True
End Sub
#End Region
#Region "ヘッダーテキストの文字列描画設定取得"
''' <summary>
''' ヘッダーテキストの文字列描画設定を取得します。
''' </summary>
''' <param name="ColumnIndex">カラム番号です。</param>
''' <remarks></remarks>
Private Function GetDrawHeaderStringFormat(ByVal ColumnIndex As Integer) As StringFormat
Dim SubItemStringFormat As New StringFormat
'テキストの描画位置
Select Case Me.Columns(ColumnIndex).TextAlign
Case HorizontalAlignment.Left
SubItemStringFormat.Alignment = StringAlignment.Near
Case HorizontalAlignment.Right
SubItemStringFormat.Alignment = StringAlignment.Far
Case HorizontalAlignment.Center
SubItemStringFormat.Alignment = StringAlignment.Center
End Select
SubItemStringFormat.LineAlignment = StringAlignment.Center
'末尾に省略記号を表示する
SubItemStringFormat.Trimming = StringTrimming.EllipsisCharacter
'折り返し
If Me.LabelWrap = False Then
SubItemStringFormat.FormatFlags = StringFormatFlags.NoWrap
End If
'ヘッダーの文字は左寄せ固定
SubItemStringFormat.Alignment = StringAlignment.Near
'折り返し
SubItemStringFormat.FormatFlags = StringFormatFlags.NoWrap
Return SubItemStringFormat
End Function
#End Region
End Class
ListViewImageクラスのソース
ソースのライセンスはGPLです。
''' <summary>
''' リストビュー用の画像を取得します。
''' </summary>
''' <remarks>
''' ライセンス:GNU General Public License (http://www.gnu.org/licenses/gpl.html)
''' 著作者:rider (http://www.lasical.com/)
''' </remarks>
Public Class ListViewImage
#Region "ヘッダー用画像"
''' <summary>
''' リストビューヘッダー用の背景画像を作成します。
''' </summary>
''' <param name="Width">リストビューヘッダーの横幅です。</param>
''' <param name="Height">リストビューヘッダーの高さです。</param>
''' <param name="TopColor">上部の色です。</param>
''' <param name="BottomColor">下部の色です。</param>
''' <param name="BorderColor">枠線色です。</param>
''' <param name="ColumnIndex">ヘッダーのカラムインデックスです。</param>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function HeaderBackgroundImage(ByVal Width As Integer, ByVal Height As Integer, ByVal TopColor As Color, ByVal BottomColor As Color, ByVal BorderColor As Color, ByVal ColumnIndex As Integer) As Image
Dim HeaderImage As Image
Dim HeaderGraphics As Graphics
Dim HeaderBrush As SolidBrush
Dim SplendorPen As Pen
Dim BorderPen As Pen
'引数チェック
If Width = 0 OrElse Height = 0 Then
Return Nothing
End If
'描画用の画像作成
HeaderImage = New Bitmap(Width, Height)
HeaderGraphics = Graphics.FromImage(HeaderImage)
'上に色を塗る
HeaderBrush = New SolidBrush(TopColor)
HeaderGraphics.FillRectangle(HeaderBrush, 0, 0, Width, CInt(Height * 0.45))
HeaderBrush.Dispose()
'下に色を塗る
HeaderBrush = New SolidBrush(BottomColor)
HeaderGraphics.FillRectangle(HeaderBrush, 0, CInt(Height * 0.45), Width, CInt(Height * 0.55))
HeaderBrush.Dispose()
'枠線を引く
If ColumnIndex = 0 Then
BorderPen = New Pen(BorderColor)
HeaderGraphics.DrawRectangle(BorderPen, 0, -1, Width - 1, Height)
BorderPen.Dispose()
Else
BorderPen = New Pen(BorderColor)
HeaderGraphics.DrawRectangle(BorderPen, -1, -1, Width, Height)
BorderPen.Dispose()
End If
'光彩描画
SplendorPen = New Pen(Color.FromArgb(64, Color.MintCream), 1)
HeaderGraphics.DrawRectangle(SplendorPen, 1, 0, Width - 3, Height - 1)
SplendorPen.Dispose()
SplendorPen = New Pen(Color.FromArgb(24, Color.MintCream), 1)
HeaderGraphics.DrawRectangle(SplendorPen, 2, 1, Width - 5, Height - 3)
SplendorPen.Dispose()
'開放
HeaderGraphics.Dispose()
Return HeaderImage
End Function
#End Region
End Class