WindowsにElixirをインストールする方法
chocolateyをインストールして、chocolateyでElixirをインストールする。
1.管理者モードで起動したコマンドプロンプトで次を実行する。
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin
2.コマンドプロンプトを閉じる。もう一度管理者モードでコマンドプロンプトを起動して次を実行する。
cinst elixir
Ruby 1.9.2 と Rails 3.2 で、rake test に色をつける。ついでに自動テストも。
仕事で使わないとほんと腰が重い。Ruby 1.9とRails3をやっと使ってみる。
Rails1や2のころはテストを書く作業が大変だった。とくにfixturesのメンテナンスが洒落にならない。最近はfixturesではなくモックを使うプラグインが出て来ているとかで、多少楽になっていればいいなと思う。
試しに作ったプロジェクトで rake test とテストを実行したら色がついてなくて素っ気なさすぎるので、まず成功は緑、失敗は赤で表示するよう設定。ついでにautotestも入れてみよう。
via. http://seanbehan.com/ruby/color-output-with-testunit-autotest-and-ruby-1-9/
RailsプロジェクトのGemfileを修正してテスト実行時に、"test-unit"、"minitest"、minitestで結果表示を書式化する"turn"、"autotest"、以上を使うよう設定。
group :development, :test do gem 'test-unit' gem 'minitest' gem 'turn' gem 'ZenTest' gem 'autotest-rails-pure' end
そんでbundleを実行して必要なGemをインストール。
$ bundle install
test/test_helper.rb に以下を追加。
require 'test/unit/ui/console/testrunner' class Test::Unit::UI::Console::TestRunner def guess_color_availability true end end
テストを走らせてみる。
$ rake test
テスト結果が色付きで表示されれば成功。続いて自動テストを実行する。
$ bundle exec autotest
.NETのフォームで2段階の継承をしてからイベントを作成するとフォームデザイナーがエラーを吐く件
VB.NET2010で確認。
- Form1を作成し、ボタンを1つ配置。ModifiersをProtectedにして継承先でイベント作成を可能にする。そしてビルドを実行。
- Form1を継承してForm2を作成。ビルドを実行。
- Form2を継承してForm3を作成。ビルドを実行。
- Form3にてボタンのClickイベントを記述。ビルドを実行。画面を閉じる。
- Form3を開こうとすると「値を Null にすることはできません。パラメーター名: objectType 」と表示されフォームデザイナーが起動しない。(無視して続行すれば開く)
ただしビルドはできるし、実行も問題ない。でも設計画面が開けないのではなあ。
.NETってフォームの継承は事実上1段だけで、多段継承は危ないってことかしら。でも画面で多段継承できないと、なんのための継承なんだか、という噺になるような。
念のためフィードバックセンターに出しておこう。
.NETでいろいろなコントロールの読み出し専用制御を一括で行うパネルを作ってみる
.NETのUIコントロールについて、設計の一貫性のなさに煩悶した。特に「TextBox系にしかReadOnlyがない」には参った。
データの表示と編集を同じフォームで処理したいケースは普通によくあるのではないか。みんなどうしているの。
ということで
http://d.hatena.ne.jp/zecl/20090201/p1
を参考にさせてもらい、配置したコントロールについて読み出し専用制御をするパネル「ReadOnlyPanel」を作ってみた。TextBox系はReadOnlyプロパティで、それ以外はメッセージを補足して入力操作を禁止(ついでにWM_ENABLEも捕まえて淡色表示をあるていど防止)することで、文字入力した部分は表示のみのときでもコピーができるようにした。
以下ソースコード。
Imports System.Runtime.InteropServices Imports System.Security Imports System.Security.Permissions Imports System.ComponentModel ''' <summary> ''' 配置したコントロールについて一括でReadOnly制御ができるパネル。 ''' </summary> ''' <remarks></remarks> Public Class ReadOnlyPanel Inherits Panel '本パネルのReadOnlyプロパティ値保持用 Private _readonly As Boolean = True '本パネルで管理するコントロールと、メッセージ処理用リスナを保持する辞書 Private _control_list As New Dictionary(Of Control, ReadOnlyMessageListenr) ''' <summary> ''' 本パネルに配置したコントロールを読み出し専用にするかを設定/取得します。 ''' </summary> <DefaultValue(False)> _ Public Property [ReadOnly] As Boolean Get Return _readonly End Get Set(ByVal value As Boolean) '値を保存 _readonly = value '本パネルでReadOnly管理するコントロールのReadOnlyを処理 For Each ctrl_and_listener As KeyValuePair(Of Control, ReadOnlyMessageListenr) In _control_list If TypeOf ctrl_and_listener.Key Is ReadOnlyPanel Then '子がEditorPanelなら、そのReadOnlyで制御 DirectCast(ctrl_and_listener.Key, ReadOnlyPanel).ReadOnly = value ElseIf TypeOf ctrl_and_listener.Key Is TextBoxBase Then 'TextBox系なら、ReadOnlyで制御 'まずFalseにして、 DirectCast(ctrl_and_listener.Key, TextBoxBase).ReadOnly = False If value Then 'Trueなら背景色もあわせて制御 DirectCast(ctrl_and_listener.Key, TextBoxBase).ReadOnly = True DirectCast(ctrl_and_listener.Key, TextBoxBase).BackColor = ctrl_and_listener.Value.BackColor End If End If Next End Set End Property ''' <summary> ''' 任意のコントロールをコンテナとして扱うかを調べて返します。 ''' </summary> Private Function IsContainer(ByRef aControl As Control) As Boolean If TypeOf aControl Is IContainerControl Then Return True ElseIf TypeOf aControl Is Panel Then Return True ElseIf TypeOf aControl Is GroupBox Then Return True Else Return False End If End Function ''' <summary> ''' 本パネルにコントロールを追加したときに、ReadOnly制御を差し込む処理を追加します。 ''' </summary> Protected Overrides Sub OnControlAdded(ByVal e As ControlEventArgs) MyBase.OnControlAdded(e) If Not Me.DesignMode Then DoControlAddedHander(Me, e) End Sub '#-- 内部処理 Private Sub DoControlAddedHander(ByVal sender As Object, ByVal e As ControlEventArgs) Dim hook As ReadOnlyMessageListenr = Nothing If Not TypeOf e.Control Is ReadOnlyPanel Then If TypeOf e.Control Is TabControl Then AddHandler e.Control.ControlAdded, AddressOf DoControlAddedHander AddHandler e.Control.ControlRemoved, AddressOf DoControlRemovedHander ElseIf IsContainer(e.Control) Then AddHandler e.Control.ControlAdded, AddressOf DoControlAddedHander AddHandler e.Control.ControlRemoved, AddressOf DoControlRemovedHander For Each ctrl In e.Control.Controls DoControlAddedHander(e.Control, New ControlEventArgs(ctrl)) Next End If If Not (TypeOf e.Control Is ReadOnlyPanel Or TypeOf e.Control Is TabControl) Then hook = New ReadOnlyMessageListenr(Me, e.Control) End If End If _control_list.Add(e.Control, hook) End Sub ''' <summary> ''' 本パネルからコントロールを削除したときに、ReadOnly制御を差し込む処理を削除します。 ''' </summary> Protected Overrides Sub OnControlRemoved(ByVal e As ControlEventArgs) If Not Me.DesignMode Then DoControlRemovedHander(Me, e) MyBase.OnControlRemoved(e) End Sub '#-- 内部処理 Private Sub DoControlRemovedHander(ByVal sender As Object, ByVal e As ControlEventArgs) If Not TypeOf e.Control Is ReadOnlyPanel Then If TypeOf e.Control Is TabControl Then RemoveHandler e.Control.ControlAdded, AddressOf DoControlAddedHander RemoveHandler e.Control.ControlRemoved, AddressOf DoControlRemovedHander ElseIf IsContainer(e.Control) Then RemoveHandler e.Control.ControlAdded, AddressOf DoControlAddedHander RemoveHandler e.Control.ControlRemoved, AddressOf DoControlRemovedHander For Each ctrl In e.Control.Controls DoControlRemovedHander(e.Control, New ControlEventArgs(ctrl)) Next End If End If _control_list.Remove(e.Control) End Sub #Region "ReadOnly制御用メッセージリスナクラス" Protected Class ReadOnlyMessageListenr Inherits NativeWindow Public Const WM_ENABLE As UInteger = &HA Public Const WM_SETFOCUS As UInteger = &H7 Public Const WM_KILLFOCUS As UInteger = &H8 Public Const WM_KEYDOWN As UInteger = &H100 Public Const WM_KEYUP As UInteger = &H101 Public Const WM_CHAR As UInteger = &H102 Public Const WM_CUT = &H300 Public Const WM_PASTE As UInteger = &H302 Public Enum WM_MOUSE As Integer WM_MOUSEFIRST = &H200 WM_MOUSEMOVE = &H200 WM_LBUTTONDOWN = &H201 WM_LBUTTONUP = &H202 WM_LBUTTONDBLCLK = &H203 WM_RBUTTONDOWN = &H204 WM_RBUTTONUP = &H205 WM_RBUTTONDBLCLK = &H206 WM_MBUTTONDOWN = &H207 WM_MBUTTONUP = &H208 WM_MBUTTONDBLCLK = &H209 WM_MOUSEWHEEL = &H20A End Enum <StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)> _ Public Structure ComboBoxInfo Public Size As Integer Public RectItem As Rectangle Public RectButton As Rectangle Public ButtonState As Integer Public ComboBoxHandle As IntPtr Public EditBoxHandle As IntPtr Public ListBoxHandle As IntPtr End Structure <SuppressUnmanagedCodeSecurity()> _ <DllImport("user32.dll", CharSet:=CharSet.Auto)> _ Public Shared Function GetComboBoxInfo(ByVal comboBoxHandle As IntPtr, ByRef pComboBoxInfo As ComboBoxInfo) As Boolean End Function Private _editor_panel As ReadOnlyPanel Private _control As New Control Private _control_backcolor As Color Private _is_textbox_base As Boolean Private _is_tabcontrol As Boolean ''' <summary> ''' リッスン対象コントロールの初期背景色を保持します。 ''' </summary> Public ReadOnly Property BackColor As Color Get Return _control_backcolor End Get End Property ''' <summary> ''' コンストラクタ ''' </summary> Public Sub New(ByRef aEditorPanel As ReadOnlyPanel, ByRef aControl As Control) AddHandler aControl.HandleCreated, AddressOf Me.OnHandleCreated AddHandler aControl.HandleDestroyed, AddressOf Me.OnHandleDestroyed _editor_panel = aEditorPanel _control = aControl _control_backcolor = aControl.BackColor _is_textbox_base = TypeOf _control Is TextBoxBase _is_tabcontrol = TypeOf _control Is TabControl End Sub ''' <summary> ''' ハンドル生成時のイベントハンドラ ''' </summary> Private Sub OnHandleCreated(ByVal sender As Object, ByVal e As EventArgs) If TypeOf sender Is ComboBox Then Dim cbi As ComboBoxInfo cbi.Size = Marshal.SizeOf(cbi) If GetComboBoxInfo(sender.Handle, cbi) Then AssignHandle(cbi.EditBoxHandle) End If Else AssignHandle(CType(sender, Control).Handle) End If End Sub ''' <summary> ''' ハンドル破棄時のイベントハンドラ ''' </summary> Private Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As EventArgs) ReleaseHandle() End Sub ''' <summary> ''' メッセージ処理 ''' </summary> Protected Overrides Sub WndProc(ByRef m As Message) '編集用パネルのReadOnlyがTrueのとき If _editor_panel.ReadOnly Then '淡色表示をさせないため、WM_ENABLEを処理しない If m.Msg = WM_ENABLE And m.WParam = 0 Then m.Result = 0 Exit Sub End If 'TextBox系以外はReadOnlyプロパティ制御できないので、 '特定のメッセージを無視することでReadOnly相当状態を実現する。 If Not _is_textbox_base Then Select Case (m.Msg) Case WM_SETFOCUS, WM_KILLFOCUS m.Result = 0 Exit Sub Case WM_KEYDOWN, WM_KEYUP, WM_CHAR, WM_CUT, WM_PASTE m.Result = 0 Exit Sub Case WM_MOUSE.WM_MOUSEFIRST, WM_MOUSE.WM_MOUSEMOVE, WM_MOUSE.WM_MOUSEMOVE, WM_MOUSE.WM_LBUTTONDOWN, WM_MOUSE.WM_LBUTTONUP, WM_MOUSE.WM_LBUTTONDBLCLK, WM_MOUSE.WM_RBUTTONDOWN, WM_MOUSE.WM_RBUTTONUP, WM_MOUSE.WM_RBUTTONDBLCLK, WM_MOUSE.WM_MBUTTONDOWN, WM_MOUSE.WM_MBUTTONUP, WM_MOUSE.WM_MBUTTONDBLCLK, WM_MOUSE.WM_MOUSEWHEEL m.Result = 0 Exit Sub End Select End If End If '通常のメッセージ処理を実行 MyBase.WndProc(m) End Sub End Class #End Region End Class
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"
これで実行時にユーザー名とパスワードを動的に設定できる。
S2Dao.NET -> OLEDB -> SQL Serverで、IDENTITY操作にハマったのでメモ
Quillでのお話。S2Containerでも同じかな。
app.configの
Provider=SQLOLEDB.1;Data Source=serverName;Initial Catalog=databaseName;User ID=userName;Password=userPassword;
と、Providerにバージョン番号を付けると、DB種類を認識できずにS2DaoがStandardDBとして扱ってしまう。
これは
Provider=SQLOLEDB;Data Source=serverName;Initial Catalog=databaseName;User ID=userName;Password=userPassword;
とプロバイダ識別名だけを記述すればOK。
DB種類が判別できない状態ではEntityのID属性が正しく働かない。
例えば、
<ID(IDType.IDENTITY)> _ Public Property Id() As Integer Get Return _id End Get Set _id = value End Set End Property
と書いてIDを自動発番に任せる。
ところがStandatdDBは当然ID属性をサポートしておらず、ほんとは"select @@identity"が必要なところでnullを返す。結果、Insert後のID取得処理で例外が発生する。
これで2時間もハマって悔しい!