2006年10月19日

My.Settingsの内容はどこに保存されるのか。

今まで不思議に思っていたのは、app.config内のMySettingsセクションに更新した内容が保存されるのものと思っていたのにファイルのタイムスタンプを見てもインストール時と全く同じままなので一体どこに保存されているのだろうかということだった。
いろいろ調べてみたところ、Documents and Settings\(LoginUser)\Local Settings\Application Data\(会社名)\(アプリ名)\(アセンブリバージョン)\
内にuser.configというファイルに保存されていることが判った。(下図)

格納場所

user.configのなかみ
user.config

※このことで、前Tipsで一部不正確なところがありました。
アセンブリバージョンが変わるとアプリケーション設定(app.config)のMy.Settingsの内容が初期化されると説明しましたが、正しくはアセンブリバージョン別に設定(user.config)が管理されているために結果として初期化され、バージョンを戻すと該当バージョンの設定を再び読み込むようになっています。
posted by なっちゃん at 17:18| 静岡 ????| Comment(0) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

VB2005 アプリケーション設定(app.config)とアセンブリバージョンの関係

前回、INIファイルに変わる環境設定の保存方法としてMy.Settingsオブジェクトを紹介した。前々回では、自アプリケーションのバージョン取得について紹介した。

今回のTipsでは、この2つのTipsが関係するちょっと困った現象とその回避策をとりあげる。

この現象に気付いたのは出来上がったプログラムを納品したときだった。
バグが見つかったため修正してプログラム本体だけをコピーして起動させたところ、修正箇所とは関係ないところでエラーを起こした。
原因はMy.Settingsオブジェクトで管理している設定内容がきれいさっぱり消えていたためである。なぜクリアされたのか。いろいろ調べた結果アセンブリバージョンを変更するとMy.Settingsの全項目が初期化されることを発見した。さらに、アセンブリバージョン情報にはAssemblyVersionAssemblyFileVersionの2つがあり後者のAssemblyFileVersionを変更してもMy.Settingsの内容は初期化されないことも判った。

顧客に最新版であることを示す目的でフォームにバージョン情報を表示させているのだが、この情報が前々回Tipsで紹介したMy.Application.Info.VersionではAssemblyVersionの方なのである。このため、バージョンを変更するたびに毎回環境設定を行わなくてはならないことになってしまう。これでは使い勝手が悪すぎるのでフォーム上のバージョンにはAssemblyFileVersionを表示させ、AssemblyVersionは変更しないようにすることにした。

アセンブリ情報ダイアログ
アセンブリ情報

ファイルのプロパティ
ファイルのプロパティより

サンプルプログラムの画面とソース
サンプル画面

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
Label1.Text = "AssemblyVersion : " & _
My.Application.Info.Version.ToString
Label2.Text = "AssemblyFileVersion : " & _
Application.ProductVersion.ToString
End Sub
posted by なっちゃん at 15:07| 静岡 ????| Comment(0) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

2006年10月03日

INIファイルに代わるVB2005のアプリケーション設定値の保存

以前に「INIファイルの読み書き」をVB6とVB.NETの比較で紹介したが、VB2005になってこれに代わるとっても楽な方法が追加されたので紹介する。
あまりに楽チンなのでINIファイルを使うことはもう無いだろうと思うほどだ。
VB.NETでもそれに類するものはあったが扱いが面倒だった。それがVB2005になってからは、まるでプロパティを設定するのと同じ感覚でできるのでつい利用したくなってしまう。

1.サンプル画面(TextBoxとCheckBoxの内容を保存)
サンプル画面

2.TextBoxのプロパティから(ApplicationSettings)の(PropertyBinding)を選択
プロパティ画面

3.規定値のTextプロパティのほかいろんなプロパティを保存できる
アプリケーション設定値を指定

4.「新規」から設定名(Name)を入力する
設定名称を入植

5.CheckBoxの場合はCheckedプロパティを指定
CheckBoxの場合

6.設定値はapp.configに記録される
app.configの記述

以上で設定は完了。ほかに何もしなくとも入力した値は保持され、次回起動時にはちゃんと反映されているという優れものである。

が、従来の「登録」や「キャンセル」ボタンを使う場面もまだ多いので、それに対応させる方法も紹介する。

'/// 登録をクリック ///
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnSave.Click
'-- ここで強制的に登録しなくても終了時に自動で保存される
'My.Settings.Save()
Me.Close()
End Sub
 
'/// キャンセルをクリック ///
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnCancel.Click
'-- 入力内容を破棄したい場合は、再読込みする
My.Settings.Reload()
Me.Close()
End Sub
 
設定内容をコードで確認するには My.Settingsに続いて設定名を指定する。
My.Settings.txtName
My.Settings.chk20
posted by なっちゃん at 15:13| 静岡 ??| Comment(0) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

2006年09月29日

自アプリケーションのバージョンを取得

MajorMinorBuildRevision
VB6App.MajorApp.Minor-App.Revison
Label1.Cation = App.Major & "." & App.Minor & "." & App.Revision
VB.NETDim Ver As New Version(Application.ProductVersion)
Ver.MajorVer.MinorVer.BuildVer.Revison
Dim Ver As New Version(Application.ProductVersion)
Label1.Text = Ver.ToString
VB2005Dim Ver As Version = My.Application.Info.Version
Ver.MajorVer.MinorVer.BuildVer.Revison
Label1.Text = My.Application.Info.Version.ToString

追加説明....
posted by なっちゃん at 20:29| 静岡 ????| Comment(0) | TrackBack(0) | VB vs VB.NET | このブログの読者になる | 更新情報をチェックする

DataGridViewの行ヘッダに行番号を表示させるには

以前のTips「DataGridViewの行ヘッダ(列ヘッダ)にContextMenuStripを関連付ける」のサンプル画面に行番号の実例がさりげなく写っていた。
これをご覧になった方からその方法が知りたいという要望があったので今回はこれを紹介する。(コードだけの紹介なのでイメージは上記を参照してください)

注:この方法はサイトを調べてC#のサンプルを見つけ、そこからVB用に直しただけの代物です。但し、Tipsとして公開するにあたり理解しやすいように個々のプロパティを直接引数に配置せず、一旦変数に置き換えてあります。また、行番号の右揃えの方法も追加しました。

その仕組みをみると簡単ではあるが泥臭い(APIで無理やり描画させているような感じの)もので、この程度の機能なら標準プロパティ等で指定できるようにすべきだと思う。

'///// 行ヘッダに行番号を描画 /////
Private Sub dataGridView_RowPostPaint(ByVal sender As Object, _
ByVal e As DataGridViewRowPostPaintEventArgs) _
Handles Me.RowPostPaint
' - 行番号と行の境界(枠)の左上のPOINT(X,Y)を取得
Dim RowNo As Integer = e.RowIndex + 1 '行番号を取得
Dim X as Integer = e.RowBounds.Location.X '行(Row)の境界の左上X座標
Dim Y as Integer = e.RowBounds.Location.Y ' 同上 Y座標

'塗り潰し用ブラシを作成
Using bs As SolidBrush = New SolidBrush(Me.RowHeadersDefaultCellStyle.ForeColor)
'文字列を描画
e.Graphics.DrawString(RowNo.ToString(), _ '行番号文字列
Me.DefaultCellStyle.Font, _ 'フォントを指定
bs, _ 'ブラシを指定
X + 15, Y + 4) '文字出力座標
End Using
End Sub
 
説明すると、DataGridViewの一行分が描画し終わったタイミング(RowPostPaintイベント)で、行ヘッダに直接文字を描画させている。このコードだけで全ての行に行番号を表示することができる。
行削除、行追加を行っても自動で更新(再描画)されるので便利である。

ここで使われる描画メソッド(Graphics.DrawString)はフォームやコントロールに文字列を描画するときに使うものだ。(ヘルプにはフォームに文字を出力するサンプルがいろいろある)
描画位置は文字列の左上を指定するので、文字が行ヘッダの適当な位置に収まるように調整する。(この例では右に15ピクセル、下に4ピクセル移動している)
左上が開始位置なので何もしないと左揃えになる、右揃えや中央揃えにするには文字列の長さを取得して位置を調整する必要がある。
右揃えにする簡単な方法は、DrawStringのオーバーロードでStringFormatを引数に渡すタイプを使う。

'///// 行番号を右揃えで表示させる方法 /////
Private Sub dataGridView_RowPostPaint(ByVal sender As Object, _
ByVal e As DataGridViewRowPostPaintEventArgs) _
Handles Me.RowPostPaint
Dim RowNo As Integer = e.RowIndex + 1
Dim X As Integer = e.RowBounds.Location.X
Dim Y As Integer = e.RowBounds.Location.Y
Dim drawPoint As New Point(X + 35, Y + 4) '右揃え用に位置をずらす
Dim drawFormat As New StringFormat
'このフラグで右から左に出力される。
drawFormat.FormatFlags = StringFormatFlags.DirectionRightToLeft

Using bs As SolidBrush = New SolidBrush(Me.RowHeadersDefaultCellStyle.ForeColor)
e.Graphics.DrawString(RowNo.ToString(), _
Me.DefaultCellStyle.Font, _
bs, _
drawPoint, _
drawFormat)
End Using
End Sub
posted by なっちゃん at 11:36| 静岡 ????| Comment(6) | TrackBack(1) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

2006年09月28日

VB2005から新たに加えられたMouseイベント

前回のTips用サンプルを作っていたときに偶然見つけたのだが、DoubleClickイベントとは別にMouseDoubleClickイベントなるものがあるのに気が付いた。ヘルプをみたら、.NET Framework2.0つまりVB2005で新たに追加されたものらしい。
どう違うのか、理解しやすいようにバージョン毎のイベントの流れを比較してみる。

ダブルクリックしたときのイベント発生順序
 
VB6 VB.NET VB2005
----------------------------------------------------
1. MouseDown MouseDown MouseDown
2. MouseUp Click Click
3. Click DoubleClick MouseClick
4. DblClick MouseUp MouseUp
5. MouseUp MouseDown
6. DoubleClick
7. MouseDoubleClick
8. MouseUp
----------------------------------------------------

VB6よりVB.NETの方がイベントがスッキリしているが、VB2005になって複雑になった。細かく制御できるわけだがそこまで使うかどうか・・・。

ClickとMouseClick、DoubleClickとMouseDoubleClickの違いは、Mouseと名づけられた方が、純粋にマウスからのイベントだけを処理するものだ。
クリックイベントは、コントロールにフォーカスがあるときEnterキーやSpaceキーでも発生させることができるからだ。キーボードだけで操作したいこともあるからね。
posted by なっちゃん at 15:23| 静岡 ????| Comment(0) | TrackBack(0) | VB vs VB.NET | このブログの読者になる | 更新情報をチェックする

2006年09月26日

イベントの中で他のコントロールのクリックを実行するには

例として、リストボックスの項目を選択・確定する処理で説明する。

一般的には
1.リストボックスの項目をクリックし選択状態にし、
2.ボタンコントロールをクリックして確定する。
の2段階で行う。

これを
1.リストボックスの項目をダブルクリックして選択・確定する。
という1つのイベントで実行させたいことがある。

VB6では以下のようになる。

Private Sub Form_Load()
With List1
.Clear
.AddItem "私"
.AddItem "お父さん"
.AddItem "お母さん"
.AddItem "お兄ちゃん"
.AddItem "お姉ちゃん"
.ListIndex = 0
End With
End Sub
 
'/// 選択したリストの項目を表示 ///
Private Sub Command1_Click()
MsgBox "「" & List1.List(List1.ListIndex) & "」が選ばれました"
End Sub
 
'/// ボタンのクリックを内部で実行 ///
Private Sub List1_DblClick()
Command1_Click '上記のクリックイベントを呼んでいるだけ
End Sub

VB.NET(2005含)になると、VB6のようにイベントプロシージャをそのまま呼ぶことはできない。そこで登場するのが PerformClickメソッド
ヘルプをみると「Clickイベントを発生させる」とある。クリック以外のイベントを発生させるメソッドがないか調べてみたがどうもなさそうだった。

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
With ListBox1
.Items.Clear()
.Items.Add("私")
.Items.Add("お父さん")
.Items.Add("お母さん")
.Items.Add("お兄ちゃん")
.Items.Add("お姉ちゃん")
.SelectedIndex = 0
End With
End Sub
 
'/// 選択したリストの項目を表示 ///
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
MsgBox("「" & ListBox1.SelectedItem & "」が選ばれました")
End Sub
 
'/// ボタンのクリックイベントを発生させる ///
Private Sub ListBox1_DoubleClick(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles ListBox1.DoubleClick
Button1.PerformClick()
End Sub
posted by なっちゃん at 20:35| 静岡 ????| Comment(0) | TrackBack(0) | VB vs VB.NET | このブログの読者になる | 更新情報をチェックする

2006年09月22日

DataGridViewの行ヘッダ(列ヘッダ)にContextMenuStripを関連付ける

VB6で使っていたメニューの仕様が.NETになってから大きく変わった。
メニューのデザインが直感的にわかるようになり、右クリックでポップアップするメニュー(ショートカットメニューとかコンテキストメニュー(ContextMenu)と呼ばれる)はフォームやコントロール毎にプロパティーに指定することで簡単に表示できるようになった。

DataGridViewのContextMenuStripプロパティに、作成したContextMenuStripコントロールを関連付けるとすべてのセル・ヘッダ上でショートカットメニューが表示されてしまう。
行ヘッダや列ヘッダで、それぞれの別のショートカットメニューを表示させるには実行時に以下の処理を追加する。

Private Sub AddContextMenu()
'-- 行ヘッダにContextMenuStrip1を関連付け
For Each row As DataGridViewRow In DataGridView1.Rows
row.HeaderCell.ContextMenuStrip = ContextMenuStrip1
Next
'-- 列ヘッダにContextMenuStrip2を関連付け
For Each column As DataGridViewColumn In DataGridView1.Columns
column.HeaderCell.ContextMenuStrip = ContextMenuStrip2
Next
End Sub

画面は合成イメージ
行ヘッダ・列ヘッダにショートカットメニューを関連付け
posted by なっちゃん at 10:30| 静岡 ????| Comment(3) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

2006年09月21日

DataGridViewの列毎に数字のみ入力許可を与える方法

前回、列毎にIMEを制御する方法を紹介したので、今度はIMEをOFFにした上で数値(0〜9)だけを許可する方法を紹介する。

この方法では前回のソースを再利用している。それというのも現在の列番号を取得するのに必要だからである。

普通のTextBoxコントロールであれば、通常のKeyPressイベント内で制御すれば良いのだが、DataGridViewでそれをやってもCell内のKeyPressイベントを拾ってはくれない。これはDataGridViewのセルにはTextBox・ComboBoxなどいくつものスタイルがあって、それぞれのタイプ別にイベントを持っているからである。

Private colNo, rowNo As Integer
'DataGridViewのTextBoxセルを宣言
Private TextEditCtrl As DataGridViewTextBoxEditingControl
 
'//// 列毎にIMEを制御 ///////
Private Sub DataGridView1_CellEnter(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles DataGridView1.CellEnter
colNo = e.ColumnIndex '現在の列番号
rowNo = e.RowIndex '現在の行番号
Select Case e.ColumnIndex
Case 0, 4, 11
'この列は日本語入力ON
DataGridView1.ImeMode = Windows.Forms.ImeMode.Hiragana
Case 1 To 3, 5 To 10
'この列はIME無効(半角英数のみ)
DataGridView1.ImeMode = Windows.Forms.ImeMode.Disable
End Select
End Sub
 
'///// DataGridViewの編集コントロールが表示された時に //////
'///// KeyPressイベントを関連付け //////
Private Sub DataGridView1_EditingControlShowing( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) _
Handles DataGridView1.EditingControlShowing
TextEditCtrl = CType(e.Control, DataGridViewTextBoxEditingControl)
AddHandler TextEditCtrl.KeyPress, AddressOf TextEditCtrl_KeyPress
End Sub
 
'///// TextBoxセル内でのKeyPressイベント //////
Private Sub TextEditCtrl_KeyPress(ByVal sender As Object, _
ByVal e As KeyPressEventArgs)
Select Case colNo '現在の列番号
Case 2, 3, 6 '数値のみ許可
Select Case e.KeyChar
Case Chr(Keys.Back) 'BackSpace
Case Chr(Keys.D0) To Chr(Keys.D9) '数値キー
'テンキー用は不要(コメント参照)
'Case Chr(Keys.NumPad0) To Chr(Keys.NumPad9)
'小数点(.)を許可したい場合は
'Case Chr(Keys.Decimal) を追加
Case Else
'上記キー以外は処理しないようにする
'(Delete,Enter,Tabなどは有効)
e.Handled = True
End Select
End Select
End Sub
 
'////// 編集が終わったタイミングでKeyPressイベントの関連付けを解除 /////
Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles DataGridView1.CellEndEdit
RemoveHandler TextEditCtrl.KeyPress, AddressOf TextEditCtrl_KeyPress
End Sub
posted by なっちゃん at 16:44| 静岡 ????| Comment(9) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする

Parameters の使用上の注意(ADO.NET)

SQLステートメントでパラメータを使用する場合にParametersプロパティに値をセットするが、連続してSQLを実行する場合、事前にパラメータの内容を消しておかないと同じ内容で処理されてしまうので注意する。
最初これに気が付かず、何故エラーするのか大いに迷ったことがある。

(Dim cmd As New OleDbCommand)
 
For i = 0 To 2
With Item(i)
cmd.CommandText = "insert into hoge_tb values(?,?,?)"
cmd.Parameters.Clear() 'これが無いとItem(0)の内容が3回登録されてしまう。
cmd.Parameters.Add("id", OleDbType.Integer).Value = .id
cmd.Parameters.Add("no", OleDbType.SmallInt).Value = i
cmd.Parameters.Add("namae", OleDbType.VarWChar).Value = .Name
cmd.ExecuteNonQuery()
End With
Next i
posted by なっちゃん at 14:44| 静岡 ????| Comment(8) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする