.NETで色々なコントロールをReadOnlyにしたいときどうすれば。
.NETの標準コントロール群は、ReadOnlyプロパティがTextBoxBaseにしかなく、全コントロールにあるEnabledは前景色/背景色が強制的に変わってしまう。なんという残念なAPI設計。
いろいろ調べてあれこれ考えて、方針をまとめたのでメモ。
- コントロールは継承せず、標準コントロールを使う。
- TextBoxBase系はReadOnlyプロパティで制御する。
- 上記以外はWndProcでメッセージを補足して、ReadOnlyにする時はフォーカス禁止・キー入力禁止・マウスクリック禁止とする。
- コントロールのReadOnlyは専用のコンテナで制御する。
これでテキストボックスはコピーができる。
年末に実装を書いてみる。
VB.NET+Quill+S2Dao.NETで、データベース接続文字列を動的に変更する
via. http://d.hatena.ne.jp/senbei3/20090410
app.configのquillセクションにはデータベース情報(
ASP.NETだとweb.configを暗号化すればよいらしいけれどWindowsフォームアプリケーションではそうもいかない。
というわけで、app.configのDB接続文字列にはユーザー名とパスワードは書かずにおいて、アプリ実行時に動的に差し込む方法。当然DBアクセス前に行う必要がある。例えばメインフォームのLoadイベントでやる場合。
メインフォームのメンバ変数に以下を追加。
Protected _dataSourceDict As SelectableDataSourceProxyWithDictionary
メインフォームのLoadイベントに以下を記述。
'DIでデータソース辞書を取得 QuillInjector.GetInstance.Inject(Me) 'app.configのquillセクションで定義したデータソースを取得 Dim ds As DataSourceImpl = _dataSourceDict.DataSourceCollection("sampleDb") 'データベース接続文字列にユーザー名とパスワードを追加 ds.ConnectionString &= ";user id=username;password=mypass"
これで実行時にユーザー名とパスワードを動的に設定できる。
.NETの継承フォームで、Anchorを固定したコントロールの位置がズレる件の対策
2011/12/09追記:Protected にすると継承先でコントロールがロックされないので、用途によってはいまいち。Anchorの利用を諦めて、継承元のOnResizeをOverridesし、コントロールのSizeから表示位置を計算してLocation設定→Invalidateとしたほうがよい場合もある。
サポート情報にも書いてある(http://support.microsoft.com/kb/316560/ja)が、機械翻訳でわかりづらいのでVB.NETを例にメモ。
つまりButton1であった場合は、
Friend WithEvents Button1 As System.Windows.Forms.Button
を
Protected WithEvents Button1 As System.Windows.Forms.Button
と変更する。これで継承先フォームのサイズを変更しても、コントロール位置がズレなくなる。
DataGridViewにEntity/DTO入りのListを繋げてSort/Filterしたいので、ライブラリ探し&サンプル作成
S2Dao.NETを使ってて悩んだのはここ。
せっかくモデルクラスに閉じ込めて固くしたデータを、表示/編集のためだけにDataTableに展開するのは勿体ない。
.NETフレームワークには、ソート/フィルターするためのIBindingListViewインターフェースはあるが、これを実装したクラスはDataViewだけ。そしてDataViewはDataTable専用。標準フレームワークにDataObjectViewとか用意しといて欲しいぞ。
定石ライブラリはあるかと探したが見つからず。フル装備っぽいBindingListViewというクラスを提供するライブラリもある。が、ちょっと大きいか。
http://blw.sourceforge.net/
以下は最低限の機能を実装したサンプルのよう。
http://lemoncake.wordpress.com/2007/06/13/filtering-on-a-list-bindingsource/
これをVB.NET用に移植してみた。このままでは実用にはならない(BindingListから継承してるのでItems周りの制御を奪うのが大変。IBindingListを自分で実装すべきなんだろう)がサンプルとして。
Seasar.NETのQuillで独自インターセプターを書いてAOPしてみる
via. http://banban55.dip.jp/~ragnarok/blog/archives/cat3/index.html
AbstractInterceptorを継承して自前の差し込み処理クラスを作る。
Imports Seasar.Framework.Aop.Interceptors Public Class MyInterceptor Inherits AbstractInterceptor Public Overrides Function Invoke(ByVal aInvocation As Seasar.Framework.Aop.IMethodInvocation) As Object Try '前処理をここに書く MsgBox("Before") 'メソッドを呼び出す Dim result As Object = aInvocation.Proceed '後処理をここに書く MsgBox("After") Return result Catch ex As Exception Throw Finally End Try End Function End Class
サービスクラスに差し込みクラスをアスペクトする。
Imports Seasar.Quill.Attrs Public Class AbcServiceImpl Implements IAbcServices Protected dao As IAbcDao <Aspect(GetType(MyInterceptor))> Public Overridable Function GetAll(ByVal aEntity As AbcEntity) As System.Collections.IDictionary Implements IAbcServices.Execute Return dao.SelectAll() End Function End Class
これでGetAll()を実行すると処理の前後にメッセージが表示される。とっても簡単。使いどころは色々ありそう。
VB.NET+Quill+S2Dxoにて、PONO->IDictionaryの変換でハマったのでメモ
S2DxoのドキュメントだとDXOインターフェースに定義するメソッドでIDictionaryをそのまま使うように見えるが、これだとインスタンスが生成できずに例外が出る。Hashtableを使えばOK。.NETに精通してれば当たり前なのかも。
以下サンプル。
エンティティが、
Public Class AbcEntity Property Field1 As Integer Property Field2 As String End Class
データ交換オブジェクトインターフェースが、
Imports Seasar.Quill.Attrs <Implementation()> Public Interface IAbcEntityDxo <Aspect(GetType(Seasar.Dxo.Interceptor.DxoInterceptor))> Function ConvertToDictionary(ByVal aEntity As AbcEntity) As Hashtable End Interface
サービスインターフェースが、
Imports Seasar.Quill.Attrs <Implementation(GetType(AbcServiceImpl))> Public Interface IAbcServices Function Execute(ByVal aEntity As AbcEntity) As Hashtable End Interface
サービスクラスが、
Public Class AbcServiceImpl Implements IAbcServices Protected dxo As IAbcEntityDxo Public Overridable Function Execute(ByVal aEntity As AbcEntity) As IDictionary Implements IAbcServices.Execute Return dxo.ConvertToDictionary(aEntity) End Function End Class
フォームにQuillControlとButtonを1つおいて、
Public Class Form1 Protected service As IAbcServices Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'エンティティを作って、 Dim entity As New AbcEntity With {.Field1 = 1234, .Field2 = "Hello, world"} 'プロパティ名=値、のハッシュテーブルに変換し、 Dim dict As Hashtable = service.Execute(entity) 'ハッシュテーブルの中身を表示してみる。 For Each item As DictionaryEntry In dict MessageBox.Show(String.Format("Key={0}, Value={1}", item.Key, item.Value)) Next End Sub End Class
うまく動作しました。これで3時間も・・・くやしい!