カテゴリー ‘ VB.NET

.NETでデータベース操作に利用できるデータプロバイダまとめ – ODBC、MySQL、PostgreSQL、SQLite、DB2、Firebird

.NETから利用できるデータベース接続ライブラリの紹介です。

今回、紹介するデータプロバイダは、ODBC、MySQL、PostgreSQL、SQLite、DB2、Firebirdの6つです。

ここで紹介していないデータベースで有名なものとして、「Microsoft SQL Server」と「Oracle」があります。

「Microsoft SQL Server」は、.NET Frameworkに標準搭載されており、「Oracle」はOracleクライアントに搭載されている「Oracle Data Provider for .NET」を利用して接続します。

ODBC

ODBC接続する為のデータプロバイダです。マイクロソフト公式のデータプロバイダとなります。

ダウンロード詳細 ODBC .NET Data Provider

MySQL

MySQLが公式に提供しているデータプロバイダです。

こちらのデータプロバイダは、ライセンスがGPLとなっているのでご注意ください。

MySQL :: Download Connector/Net

MySQLに関しては、使い方を解説した記事を書いてあるので、そちらもご参考にしてください。

VB.NETでデータベースのMySQLに接続する方法

PostgreSQL

サイトやドキュメントが日本語で記載されており、分かりやすくなっています。

最新バージョンの公開日が「2006-10-08」とずいぶん前なのが気になりますが、現状、利用は問題ないかと思います。

Postgresql のための Npgsql .Net データプロバイダ : プロジェクトホームページ

SQLite

組み込みデータベースのSQLiteに接続できるデータプロバイダです。

ライセンスは、パブリックドメインとなっています。

System.Data.SQLite

SQLiteに関しては、使い方や、接続文字列の解説を記事にしたことがあるので、そちらもご参考にしてください。

DB2

IBMが提供するDB2に接続できる、公式データプロバイダです。

IBM – DB2 for .NET: Innovate with Visual Studio

Firebird

あまり有名ではありませんが、オープンソースのデータベース「Firebird」に接続できるデータプロバイダです。

Firebird: .NET Provider

Share on Facebook

.NETで手軽にFTP接続できるライブラリ – TKFP

C#、VB.NETで利用できる、FTP接続ライブラリ「TKFP」のご紹介です。

TKFPは、面倒なコマンド操作をラップして、簡単に利用出来るようにしたクラスライブラリです。

 

こちらのライブラリは、ファイルの送受信やパーミッションの変更など、FTP操作の基本的なことはもちろん、暗号化通信(FTP over SSL/TLS)にも対応しています。

ダウンロード

以下のリンクよりダウンロードできます。

ソースとライブラリ単体それぞれダウンロードできますので、必要な方をダウンロードしてください。
.NET用FTPクラスライブラリ (TKFP.DLL)

ライセンス

ライセンスは独自ライセンスで、商用・非商用どちらでも自由に使うことが可能になっています。

細かい内容については、公式サイトの使用条件の項目をご覧ください。

使い方

使い方については、公式サイトによくまとまっているので、そちらをご覧ください。
TKFP.DLL プログラミングTips

Share on Facebook

.NETでUDPプロトコルを使ってメッセージを送信する方法

メッセージを送信するプロトコルとして主に使われるのは、TCP/IPとUDPが多いですが、今回はUDPによるメッセージ送信の方法を紹介します。

UDPは、TCP/IP通信の信頼性は低いが、送信速度が速いという特徴があるので、多くのメッセンジャーソフトで利用されています。

動作サンプル画像

初期起動時です。デフォルトでは、自分のパソコンに送信するようになっています。

UPD

送信するメッセージを入力して送信した後です。きちんと送信されていることが分かります。

UPD

サンプルソース

ソースのライセンスはGPLとします。

Imports System.Net
Imports System.Net.Sockets

''' <summary>
''' UDPプロトコルを使ってメッセージのやりとりをするサンプルプログラムです。
''' </summary>
''' <remarks>
''' ライセンス:GNU General Public License (http://www.gnu.org/licenses/gpl.html)
''' 著作者:rider (http://www.rider-n.sakura.ne.jp/wp/)
''' </remarks>
Public Class Form1
    Dim Udp As UdpClient
    Dim Ep As IPEndPoint

    ''' <summary>
    ''' フォームロード時の処理です。UDPクライアントの定義と非同期の受信処理を実行します。
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'スレッドセーフでなくてもエラーを出さない
        Control.CheckForIllegalCrossThreadCalls = False

        'UPDクライアントを定義
        Ep = New IPEndPoint(IPAddress.Any, Me.TextBox2.Text)
        Udp = New System.Net.Sockets.UdpClient(Ep)

        '非同期の受信処理
        Udp.BeginReceive(New AsyncCallback(AddressOf ReceiveCallback), Nothing)
    End Sub

    ''' <summary>
    ''' 送信ボタンクリック時の処理です。
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        '入力された文字をバイト配列に読み込む
        Dim SendBytes As Byte() = System.Text.Encoding.UTF8.GetBytes(Me.TextBox3.Text)

        '入力されたホストにメッセージを送信
        Udp.Send(SendBytes, SendBytes.Length, Me.TextBox1.Text, Me.TextBox2.Text)

        '非同期処理
        Udp.BeginReceive(New AsyncCallback(AddressOf ReceiveCallback), Nothing)
    End Sub

    ''' <summary>
    ''' 非同期のUDP受信処理です。UDPプロトコルからのメッセージを受信すると呼び出されます。
    ''' </summary>
    ''' <param name="ar"></param>
    ''' <remarks></remarks>
    Private Sub ReceiveCallback(ByVal ar As IAsyncResult)
        '受信したメッセージをバイト配列に読み込む
        Dim RcvBytes As Byte() = Udp.EndReceive(ar, Ep)
        'バイトデータを文字列に変換
        Dim RcvMsg As String = System.Text.Encoding.UTF8.GetString(RcvBytes)

        '受信したデータをテキストに表示
        Me.TextBox4.Text = Me.TextBox4.Text & "送信メッセージ:" & RcvMsg & vbCrLf
        Me.TextBox4.Text = Me.TextBox4.Text & "送信元アドレス:" & Ep.Address.ToString & vbCrLf
        Me.TextBox4.Text = Me.TextBox4.Text & "ポート番号  :" & Ep.Port & vbCrLf & vbCrLf
    End Sub
End Class

プログラム中では、「Control.CheckForIllegalCrossThreadCalls = False」でスレッドセーフでない場合でもエラーを出さないようにしていますが、本来は、きちんとスレッドセーフになるようにプログラムを書いてください。

スレッドセーフにする方法は以下の記事を参考にしてください。
.NETのスレッド処理でスレッドセーフでない場合でもエラーを出さないようにする方法

サンプルプログラムダウンロード

“UDPMessenger” をダウンロード UDPMessenger.zip – 1629回ダウンロードされました – 30 kB

Share on Facebook

.NETのマルチスレッド処理で引数を渡す方法

スレッド処理のサンプルは、引数を渡さないものが紹介されていることが多いのですが、実際に使う時には、引数を渡したい場面が多々あります。

今回は、スレッド処理で引数を渡す方法の紹介です。

ソースのライセンスはGPLとします。

引数なしのスレッド処理

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim ThredTestThread As System.Threading.Thread

    'スレッドのクラス作成
    ThredTestThread = New System.Threading.Thread(AddressOf ThredTest)

    '別スレッドで呼び出し
    ThredTestThread.Start()
End Sub

Private Sub ThredTest()
    Debug.Print("デバッグ情報")
End Sub

引数ありのスレッド処理

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim ThredTestThread As System.Threading.Thread

    'スレッドのクラス作成
    ThredTestThread = New System.Threading.Thread(New System.Threading.ParameterizedThreadStart(AddressOf ThredTest))

    '別スレッドで呼び出し
    ThredTestThread.Start("デバッグ情報")
End Sub

Private Sub ThredTest(ByVal Text As Object)
    Debug.Print(Text)
End Sub

 

今回はサンプルなので、実行結果は同じですが、引数として文字列を渡せていることを確認できると思います。

引数は、Object型で指定するので、クラスや配列などを渡すこともできます。

Share on Facebook

マルチスレッドで動作する.NETのプログラムサンプル

最近のパソコンは、マルチコアのCPUを積んでいるものが多く、マルチスレッドプログラミングで処理の効率化を図れる環境が整ってきました。

もちろん、なんでもかんでもマルチスレッド化すれば、処理効率がよくなる!ってわけではありません。マルチスレッド化しても処理効率があまり上がらないだろうなというものをまとめてみました。

マルチスレッド化しても処理効率があまり上がらないパターン

  • 処理中に同一ファイルに対して読み書きが発生する場合

    同一ファイルへの読み書きがある場合は、あまり処理効率が上がらない可能性があります。

    なぜかというと、ディスクへの読み書きというのは、結構時間がかかる処理なので、ひとつの処理が読んだり書き込んだりする間は他の処理は、待ち状態になります。その待ち時間がボトルネックになって処理速度が上がらない可能性があります。

  • 同一のオブジェクトへアクセスする場合

    上のファイルと同じ理由で、同一オブジェクト(変数とか)へのアクセスがある場合には、そこで待ちが発生して遅くなる可能性があります。

他にもあると思いますが、パッと出てくるのはこのくらい。

 

どういう時にマルチスレッド化した方がいいのかというと、大きく分けて以下の2パターン。

  1. 処理時間がかかるので処理を分割したい場合

    これは単純に、処理を分割して処理効率を上げたい場合です。

  2. 処理中に画面上に進捗状況を出したい場合(フォームを応答なしの状態にしたくない場合)

    Windows Formアプリケーションの画面描画は、CPUを使って描画しているので、プログラムがCPUを占有すると画面が描画されません。(応答なしになって画面が白くなった状態)

    ただ、処理の進捗状況を表示しないといけないということはよくあることなので、DoEventsを実行して画面の表示をリフレッシュするという人も多いのではないでしょうか。

    DoEventsを実行すると確かに画面が再表示されるのですが、この命令は「メッセージキューにある処理を全て処理する」という命令なので、DoEventsを1行入れるだけで、処理が遅くなることがあります。

マルチスレッドのサンプル

簡単なサンプルを作ってみました。

画面には、ラベルを1つとボタンを2つ配置します。

multi_thread01

Button1を押すと、マルチスレッド処理なしでループ処理を実行、Button2を押すと、マルチスレッド処理でループ処理を実行します。

ソースのライセンスはGPLとします。

''' <summary>
''' ラベルに値をセットする為のデリゲートです。
''' </summary>
''' <param name="Text">表示するテキストです。</param>
''' <remarks></remarks>
Delegate Sub SetLabelTextDelegate(ByVal Text As String)

''' <summary>
''' マルチスレッドなしで処理を実行するクリックイベントです。
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    'マルチスレッドなしの通常呼び出し
    Call MultiThreadTest(1000)
End Sub

''' <summary>
''' マルチスレッドで処理を実行するクリックイベントです。
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    Dim MultiThreadTestThread As System.Threading.Thread

    'スレッドのクラス作成
    MultiThreadTestThread = New System.Threading.Thread(New System.Threading.ParameterizedThreadStart(AddressOf MultiThreadTest))

    'バックグラウンドで動作
    MultiThreadTestThread.IsBackground = True

    '別スレッドで呼び出し
    MultiThreadTestThread.Start(1000)
End Sub

''' <summary>
''' 指定回数ループ処理を実行してラベルに件数を表示します。
''' </summary>
''' <param name="LoopCount">ループ処理回数です。</param>
''' <remarks></remarks>
Private Sub MultiThreadTest(ByVal LoopCount As Object)
    Dim SetLabelTextDgl As New SetLabelTextDelegate(AddressOf SetLabelText)
    Dim Count As Integer = DirectCast(LoopCount, Integer)

    '指定回数ループ
    For i As Integer = 1 To Count
        '10ミリ秒ストップ
        System.Threading.Thread.Sleep(10)

        'ラベルに値をセット
        Me.Label1.Invoke(SetLabelTextDgl, i.ToString)
    Next
End Sub

''' <summary>
''' ラベルに値をセットします。
''' </summary>
''' <param name="Text"></param>
''' <remarks></remarks>
Private Sub SetLabelText(ByVal Text As String)
    'ラベルにカウンターを表示
    Me.Label1.Text = Text
End Sub

サンプルの補足

サンプルプログラム中のラベルに件数を出力するところなのですが、単純にラベルに出すだけなのになんでこんなことやってるの?と思った人もいると思います。

もちろんこれにはちゃんと理由があって、.NETのオブジェクト類の多くは、スレッドセーフ(スレッドセーフ – Wikipedia)ではないので、複数のスレッドからアクセスされると問題が発生することがあります。

サンプルプログラムにあるような方法を使うことで、スレッドセーフになり、安全に処理を実行することができます。

前に記事も書いたのでそちらもご覧ください。

.NETのスレッド処理でスレッドセーフでない場合でもエラーを出さないようにする方法

Share on Facebook

.NETのスレッド処理でスレッドセーフでない場合でもエラーを出さないようにする方法

.NETでは、別スレッドからスレッドセーフでないコントロールオブジェクトを操作すると、エラーが発生するようになっています。

スレッド処理を実行する前に「Control.CheckForIllegalCrossThreadCalls」プロパティを False に変更すると、エラーが発生しないようになります。

Control.CheckForIllegalCrossThreadCalls = False

 

ただし、この方法はエラーを無視しているだけで、根本的な解決にはなっていません。

スレッドセーフにしてコントロールを操作するには、通常とはちょっと違った特殊な操作が必要になります。

以下、サンプルです。ソースのライセンスはGPLとします。

''' <summary>
''' テキストボックスに値をセットする為のデリゲートです。
''' </summary>
''' <param name="Text">表示するテキストです。</param>
''' <remarks></remarks>
Delegate Sub SetTextBoxTextDelegate(ByVal Text As String)

''' <summary>
''' 別スレッド処理を実行するクリックイベントです。
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim MultiThreadTestThread As System.Threading.Thread

    'スレッドのクラス作成
    MultiThreadTestThread = New System.Threading.Thread(AddressOf ThredTest)

    '別スレッドで呼び出し
    MultiThreadTestThread.Start()
End Sub

''' <summary>
''' 別スレッドの処理です。
''' </summary>
''' <remarks></remarks>
Private Sub ThredTest()
    Dim SetTextBoxTextDgl As New SetTextBoxTextDelegate(AddressOf SetTextBoxText)

    'テキストボックスに値をセット
    Me.TextBox1.Invoke(SetTextBoxTextDgl, "表示する文字")
End Sub

''' <summary>
''' テキストボックスに値をセットします。
''' </summary>
''' <param name="Text"></param>
''' <remarks></remarks>
Private Sub SetTextBoxText(ByVal Text As String)
    'テキストボックスに指定テキストを表示
    Me.TextBox1.Text = Text
End Sub

Share on Facebook

.NETの仮想リスト機能をちょっとだけ実用的にしたListViewコントロール – VirtualListView

ListViewに大量のリストを追加すると、パフォーマンスがかなり落ちますよね。

ListViewコントロールの仮想リスト機能を使うとパフォーマンスは改善するのですが、使い勝手がいまいちです。

なので、ちょっとだけ実用的に使えるようにカスタマイズしたコントロールを作成しました。

 

サンプル

左が仮想リストビューで右が標準リストビューです。

見た目は、まったく変わりませんが、スクロールバーを使ってリストを上下に動かしてみてください。仮想リストビューの方は、さくさく動くの対して、標準リストビューでは、もたもたした動きになることが分かると思います。

VirtualListView

ボタンをクリックすると、リストを1万件ずつ作成します。

「描画停止あり」と「描画停止なし」の違いは、リスト生成前にBeginUpdateメソッドを実行し、リスト生成後にEndUpdateメソッドを実行するかしないかです。2つのメソッドを実行することで、リスト生成時のパフォーマンスが向上します。

「描画停止あり」の場合、「描画停止なし」の場合、どちらも仮想リストビューの方が高速に動作することがわかります。特に、「描画停止なし」では速度の差が大きくなっています。

ソースコード

以下からソースファイルをダウンロード出来ます。ソースのライセンスはGPLです。

“VirtualListViewサンプルソース” をダウンロード VirtualListViewTest.zip – 1249回ダウンロードされました – 46 kB

ダウンロード出来るソリューションについて

このソリューションは、コントロールが実装されている「VirtualListView」プロジェクトとコントロールのテスト用プロジェクト「VirtualListViewTest」の2つで出来ています。

開発言語はVB.NETで、開発環境はVisual Studio 2005です。

「VirtualListView」プロジェクトは、ListViewコントロールを継承したVirtualListViewコントロールと、仮想リストビュー用のListViewコレクションのクラスで出来ています。

VirtualListViewコントロールについて

  • VirtualListViewItem … 仮想リストビューのアイテムクラスです。
  • VirtualListViewItemCollection … 仮想リストビューのアイテムコレクションです。
  • VirtualListView … 仮想リストビューコントロールの本体です。

VirtualListViewのアイテムには、単純に配列を使ってもよかったのですが、せっかくですので、コレクションクラスを作ったものにしました。

アイテムの追加は、Addメソッドを使って行います。通常のListViewでアイテムを追加するのと同じ感覚でアイテムを追加する事が出来ます。

多くの機能は実装していませんが、他にも、Clearメソッドでリストのクリア、Sortメソッドでアイテムの並び替えを行うことが出来ます。

リストの並び替えについては、以下のサイトを参考にしてください。

ListViewの項目を並び替える: .NET Tips: C#, VB.NET, Visual Studio

Share on Facebook

VB.NETでデータベースのMySQLに接続する方法

MySQLとは、SQL ServerやOracleと同じ、データベースソフトです。

多くのデータベースソフトが、有料なのに対しMySQLは無料で使うことが出来ます。

今回は、そのMySQLをVB.NETから使用する方法のご紹介です。Visual Studioは、Visual Studio 2005を使います。

 

データプロバイダのライセンスに関する注意点

今回利用するMySQLのデータプロバイダは、ライセンスがGPLとなっています。GPLライセンスの原文はこちらです。

GPLライセンスのソースコードの一部でも利用した場合は、利用したプログラムにもGPLライセンスが適用され、ソースコードを公開しなくてはならなくなります。

これは、ソースコードだけでなく、生成された実行ファイルやライブラリにリンクして利用する場合も同様です。

ただし、これは、作成したプログラムを配布する場合に限りますので、私的な利用の場合は、ソースコードを公開する必要はありません。

今回のサンプルのように、静的にリンクをした場合は、作成したプログラムには必ずGPLライセンスが適用されますが、動的にリンクした場合は、GPLライセンスの適用はされないという考え方もあるようです。

VB.NETでデータプロバイダに動的リンクにリンクするやり方は、以前、記事にしたので、よろしければご覧ください。

VB.NETから組み込みデータベースのSQLiteを操作する方法

ダウンロード

まず始めに、MySQLに接続する為のデータプロバイダをダウンロードします。

MySQLのデータプロバイダは、昔はいくつかあったのですが、現在は、公式サイトより提供されているので、そちらのデータプロバイダを利用します。

以下のURLよりデータプロバイダをダウンロードしてください。

http://dev.mysql.com/downloads/connector/net/

昔は、バイナリのみのダウンロードも出来ていたのですが、現在は、インストーラー形式とソースのみのようです。

「mysql-connector-net-X.X.X-src.zip」はソースファイルですので、ダウンロードは、「mysql-connector-net-X.X.X.zip」の方をダウンロードしてください。

この記事を書いた時点でのデータプロバイダのバージョンは、「6.3.6」です。

インストール

早速、インストールします。

ダウンロードしたZIPファイルを解凍すると、「mysql.data.msi」というファイルが入っているので実行します。

実行すると、インストーラーが起動するので、Nextボタンを押します。

MySQLデータプロバイダ

Typical、Custom、Completeの3つのボタンがあります。通常は、Typicalで問題ないと思います。

MySQLデータプロバイダ

インストールボタンを押すとイントールが開始されます。

MySQLデータプロバイダ

イントール処理は、数分で終わるので、しばらく待ちます。

MySQLデータプロバイダ

インストール完了画面が表示されたら、Finishボタンを押してイントールを完了します。

MySQLデータプロバイダ

Visual Studio起動

インストールが完了したら、Visual Studio 2005を起動します。

画面の左にある、作成のプロジェクトをクリックして新規プロジェクトを作成します。

MySQL Visual Studio 2005

テンプレートの種類は、Windowsアプリケーションを選択します。

プロジェクト名は、今回は変更せず進めますが、必要があれば変更してください。

MySQL Visual Studio 2005

データプロバイダの参照設定

新規プロジェクトが作成出来たら、MySQLデータプロバイダの参照設定を行います。

メニューのプロジェクト→参照の追加をクリックしてください。

MySQL Visual Studio 2005

.NETタブの一覧に、MySQL.Dataという項目があるので、選択してOKボタンを押します。

MySQL Visual Studio 2005

接続文字列

色々書き方やオプションはありますが、通常はこちらの書き方で問題ないと思います。日本語で書いてある部分は、それぞれの環境に応じて変更する必要があります。

接続文字列の詳しい説明は、暇を見つけてまとめたいと思います。

"Database=データベース名;Data Source=サーバー;User Id=ログインユーザー;Password=パスワード"

サンプルソース

ソースのライセンスはGPLとします。

Imports MySql.Data.MySqlClient

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim Connection As New MySqlConnection
        Dim Command As MySqlCommand
        Dim DataReader As MySqlDataReader

        '接続文字列を設定
        Connection.ConnectionString = "Database=データベース名;Data Source=サーバー;User Id=ログインユーザー;Password=パスワード"

        'オープン
        Connection.Open()

        'コマンド作成
        Command = Connection.CreateCommand

        'SQL作成
        Command.CommandText = "SELECT * FROM hoge"

        'データリーダーにデータ取得
        DataReader = Command.ExecuteReader

        'データを全件出力
        Do Until Not DataReader.Read
            Debug.Print(DataReader.Item("field01").ToString)
        Loop

        '破棄
        DataReader.Close()
        Command.Dispose()
        Connection.Close()
        Connection.Dispose()
    End Sub
End Class

Share on Facebook

.NETのListViewをちょっとオシャレにカスタマイズ

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

例えば、FenrirFSが該当します。

FenrirFS

このような感じの見た目になるようなStylishListViewというListViewコントロールを作ってみました。

今回は、ヘッダーのカスタマイズの他に、奇数行、偶数行の色分けも実装しました。

左が標準コントロール、右が今回作成したカスタムコントロールです。

標準コントロールStylishListView

実装プロパティ説明

コントロールには、以下のプロパティが実装されています。

項目名 説明
HeaderTopColor ヘッダーの上部色
HeaderBottomColor ヘッダーの下部色
HeaderBorderColor ヘッダーの枠線色
ViewStylishHeader ヘッダーをカスタマイズするか
EvenBackColor 偶数行の背景色
EvenForeColor 偶数行の前景色
OddBackColor 奇数行の背景色
OddForeColor 奇数行の前景色
OddEvenColorCoding 奇数、偶数行を色分けするか

ソースダウンロード

以下からソースファイルをダウンロード出来ます。ソースのライセンスはGPLです。

“StylishListViewサンプルソース” をダウンロード StylishListViewTest.zip – 1625回ダウンロードされました – 46 kB

ダウンロード出来るソリューションについて

このソリューションは、コントロールが実装されている「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

Share on Facebook

.NETのListViewで大量のデータを扱う場合にパフォーマンスを向上させる方法

ListViewコントロールは、件数が少ないとパフォーマンス的には問題ありませんが、1万件を超えるような大量のデータを扱う場合には、動作がもたつきます。

そのような場合は、VirtualModeを有効にすると動作の改善が見込めます。

以下にサンプルのソースを書きましたので試してみてください。

前準備として、フォーム上にListViewを追加しておく必要があります。

ソースのライセンスはGPLとします。

VirtualModeを有効にしない場合

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim Stopwatch As New System.Diagnostics.Stopwatch()

    'ストップウォッチ開始
    Stopwatch.Start()

    'リストの描画を停止
    Me.ListView1.BeginUpdate()

    'ListViewにアイテムを1万件追加
    For Index As Integer = 1 To 10000
        Me.ListView1.Items.Add(Index.ToString)
    Next

    'リストの描画を再開
    Me.ListView1.EndUpdate()

    '時間を出力
    Debug.Print(Stopwatch.Elapsed.ToString)
    '00:00:01.6476695
End Sub

VirtualModeを有効にした場合

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim Stopwatch As New System.Diagnostics.Stopwatch()

    'ストップウォッチ開始
    Stopwatch.Start()

    'バーチャルモードを有効に変更
    Me.ListView1.VirtualMode = True

    'バーチャルリストの行数
    Me.ListView1.VirtualListSize = 10000

    '時間を出力
    Debug.Print(Stopwatch.Elapsed.ToString)
    '00:00:00.0173539
End Sub

Private Sub ListView1_RetrieveVirtualItem(ByVal sender As Object, ByVal e As System.Windows.Forms.RetrieveVirtualItemEventArgs) Handles ListView1.RetrieveVirtualItem
    'リストビューにリストをセット
    e.Item = New ListViewItem(e.ItemIndex + 1)
End Sub

有効にしない場合は、フォームのロード時にリストの作成を作成しているので、1~2秒程度時間がかかります。

それに対し、有効にした場合は、ロード時にプロパティを変更しているだけなので、一瞬で終わっています。

この程度の差なら別にVirtualModeを有効にする必要はないと思うかもしれませんが、実はロード時間以外の箇所で速度改善がなされています。

試しに、表示されたListViewのスクロールバーをスクロールしてみてください。

VirtualModeを有効にした場合は、サクサク動きますが、VirtualModeを有効にしていない場合は、かなりもたつくと思います。

ListViewに表示する件数が少ない場合には、VirtualModeを有効にする必要はありませんが、表示する件数が数千件になる場合には、VirtualModeを有効にした方がいいでしょう。

Share on Facebook

広告

Facebook

カレンダー

2017年3月
« 5月    
 1234
567891011
12131415161718
19202122232425
262728293031  

最近の投稿

アーカイブ