トップ回答者
すべてのフォームのChangeイベントの監視

質問
-
回答
-
ユーザーが再度変更して元の値に戻したら適用ボタンを再度Enabled=falseにしないといけないんですよね。たぶん・・・
こういった場合(というかほとんどいつも)、私はUIバインドオブジェクトを用意し、それとデーターテーブルの値を比較することによって実現しています。
このようにしておくと、ユーザーが値を変更して更新ボタンを押さずに画面を閉じようとした時のみ、「本当に閉じてもいいですか?」というメッセージも出せるようになります。
UIバインドオブジェクトは以下を参考にして下さい。Part 2. スマートクライアントにおける単体入力データ検証
http://blogs.msdn.com/b/nakama/archive/2009/02/26/part-2.aspx
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク 山本春海 2011年4月1日 5:46
-
相性というのは特に無いと思います。例えばデーターテーブルをDataGridViewに直接バインドする代わりにUIオブジェクトを作成し、それをDataGridViewにバインドさせます。このUIオブジェクトとデーターテーブルの差異を見れば、ユーザーが変更したかとうかがわかります。
もしくは、ユーザーが変更したかどうかだけに的を絞れば、バインドした直後の各値を覚えておき、それとデーターテーブルの値を比較してもユーザーによる変更を知ることができます。うろ覚えですが、データーテーブルは同じ値で更新してもDataRowVersionが変わらなかったと思いますので、そうであればDataRowVersionによる判断もできそうです。
以上とSelectedChangedなどと組み合わせてチェックすれば良いと思います。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク 山本春海 2011年4月1日 5:46
-
>親のクラスをつくって、そこでコントロールの管理はできないでしょうか。
>各コントロールの差分は子供のクラスに書くってことは無理でしょうか。
親クラスというか、コントロールを継承したユーザコントロールをつくり、そのコントロール
それぞれの値変更と思われる動作に対して、コントロールが配置されるフォームオブジェクト
に対してWindowsメッセージを送り、フォーム側ではそのメッセージを受け取ったら
変更が行われたとみなす、というような感じはどうでしょう。
イメージとしては、以下のようなものです。
' Form1.vb Public Class Form1 Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) MyBase.WndProc(m) If m.Msg = WM_APP_CHANGEDATA Then Console.WriteLine("変更処理をここに書く") End If End Sub End Class ' Module1.vb Module Module1 Public Const WM_APP_CHANGEDATA As Integer = &H8000 Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _ (ByVal hwnd As Integer, ByVal msg As Integer, _ ByVal wParam As Integer, ByVal lParam As Integer) As Integer Public Function GetFormHandle(ByRef ctrl As Control) As IntPtr Dim handle As IntPtr Dim wkctrl As Control = ctrl Do While wkctrl.Parent IsNot Nothing handle = wkctrl.Parent.Handle wkctrl = wkctrl.Parent Loop Return handle End Function End Module ' MyControls.vb Imports System.Windows.Forms Public Class MyTextBox : Inherits System.Windows.Forms.TextBox Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs) MyBase.OnTextChanged(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub End Class Public Class MyCheckBox : Inherits System.Windows.Forms.CheckBox Protected Overrides Sub OnCheckedChanged(ByVal e As System.EventArgs) MyBase.OnCheckedChanged(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub End Class Public Class MyComboBox : Inherits System.Windows.Forms.ComboBox Protected Overrides Sub OnSelectedIndexChanged(ByVal e As System.EventArgs) MyBase.OnSelectedIndexChanged(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub End Class Public Class MyDataGridView : Inherits System.Windows.Forms.DataGridView Protected Overrides Sub OnCellValueChanged(ByVal e As DataGridViewCellEventArgs) MyBase.OnCellValueChanged(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub Protected Overrides Sub OnColumnAdded(ByVal e As DataGridViewColumnEventArgs) MyBase.OnColumnAdded(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub Protected Overrides Sub OnColumnRemoved(ByVal e As DataGridViewColumnEventArgs) MyBase.OnColumnRemoved(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub Protected Overrides Sub OnRowsAdded(ByVal e As DataGridViewRowsAddedEventArgs) MyBase.OnRowsAdded(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub Protected Overrides Sub OnRowsRemoved(ByVal e As DataGridViewRowsRemovedEventArgs) MyBase.OnRowsRemoved(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub End Class
- 回答としてマーク 山本春海 2011年4月1日 5:46
-
フォームのロード時にフォーム上のコントロールを全て取得して、イベントをセットしてしまえば良いと思います。
ちなみに
private void CreateControlList( Control parent ) { foreach( Control control in parent.Controls ) { m_controlList.Add(control); // 再起処理(パネルやグループボックス用) CreateControlList(control); } }
こんなメソッドを用意して、ロード時に読んであげる事でコントロール一覧を取得して、
foreach( Control control in m_controlList ) { if (control is TextBox) { control.KeyDown += new System.Windows.Forms.KeyEventHandler(Common_KeyDown); } }
こんな感じでコントロールが何なのかを判断しながらハンドリングするってのはどうでしょう。- 回答としてマーク 山本春海 2011年4月1日 5:46
すべての返信
-
統一的に管理をしたいということですが、コントロールの種類単位で、たとえばテキストボックス、
チェックボックス、コンボボックスといった単位での統括管理であれば、以下でどうでしょうか。
一つのイベント処理に対して、複数のコントロールのイベントを割り当てることが出来ます。
Handlesの後に、カンマ区切りで指定します。
' テキストボックス Private Sub TextBox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged, TextBox2.TextChanged ButtonEnabledTrue() End Sub ' チェックボックス Private Sub CheckBox_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged, CheckBox2.CheckedChanged ButtonEnabledTrue() End Sub ' コンボボックス Private Sub ComboBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged, ComboBox2.SelectedIndexChanged ButtonEnabledTrue() End Sub ' 共通のボタンの有効処理 Private Sub ButtonEnabledTrue() Me.Button1.Enabled = True End Sub
-
ユーザーが再度変更して元の値に戻したら適用ボタンを再度Enabled=falseにしないといけないんですよね。たぶん・・・
こういった場合(というかほとんどいつも)、私はUIバインドオブジェクトを用意し、それとデーターテーブルの値を比較することによって実現しています。
このようにしておくと、ユーザーが値を変更して更新ボタンを押さずに画面を閉じようとした時のみ、「本当に閉じてもいいですか?」というメッセージも出せるようになります。
UIバインドオブジェクトは以下を参考にして下さい。Part 2. スマートクライアントにおける単体入力データ検証
http://blogs.msdn.com/b/nakama/archive/2009/02/26/part-2.aspx
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク 山本春海 2011年4月1日 5:46
-
相性というのは特に無いと思います。例えばデーターテーブルをDataGridViewに直接バインドする代わりにUIオブジェクトを作成し、それをDataGridViewにバインドさせます。このUIオブジェクトとデーターテーブルの差異を見れば、ユーザーが変更したかとうかがわかります。
もしくは、ユーザーが変更したかどうかだけに的を絞れば、バインドした直後の各値を覚えておき、それとデーターテーブルの値を比較してもユーザーによる変更を知ることができます。うろ覚えですが、データーテーブルは同じ値で更新してもDataRowVersionが変わらなかったと思いますので、そうであればDataRowVersionによる判断もできそうです。
以上とSelectedChangedなどと組み合わせてチェックすれば良いと思います。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク 山本春海 2011年4月1日 5:46
-
>親のクラスをつくって、そこでコントロールの管理はできないでしょうか。
>各コントロールの差分は子供のクラスに書くってことは無理でしょうか。
親クラスというか、コントロールを継承したユーザコントロールをつくり、そのコントロール
それぞれの値変更と思われる動作に対して、コントロールが配置されるフォームオブジェクト
に対してWindowsメッセージを送り、フォーム側ではそのメッセージを受け取ったら
変更が行われたとみなす、というような感じはどうでしょう。
イメージとしては、以下のようなものです。
' Form1.vb Public Class Form1 Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) MyBase.WndProc(m) If m.Msg = WM_APP_CHANGEDATA Then Console.WriteLine("変更処理をここに書く") End If End Sub End Class ' Module1.vb Module Module1 Public Const WM_APP_CHANGEDATA As Integer = &H8000 Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _ (ByVal hwnd As Integer, ByVal msg As Integer, _ ByVal wParam As Integer, ByVal lParam As Integer) As Integer Public Function GetFormHandle(ByRef ctrl As Control) As IntPtr Dim handle As IntPtr Dim wkctrl As Control = ctrl Do While wkctrl.Parent IsNot Nothing handle = wkctrl.Parent.Handle wkctrl = wkctrl.Parent Loop Return handle End Function End Module ' MyControls.vb Imports System.Windows.Forms Public Class MyTextBox : Inherits System.Windows.Forms.TextBox Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs) MyBase.OnTextChanged(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub End Class Public Class MyCheckBox : Inherits System.Windows.Forms.CheckBox Protected Overrides Sub OnCheckedChanged(ByVal e As System.EventArgs) MyBase.OnCheckedChanged(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub End Class Public Class MyComboBox : Inherits System.Windows.Forms.ComboBox Protected Overrides Sub OnSelectedIndexChanged(ByVal e As System.EventArgs) MyBase.OnSelectedIndexChanged(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub End Class Public Class MyDataGridView : Inherits System.Windows.Forms.DataGridView Protected Overrides Sub OnCellValueChanged(ByVal e As DataGridViewCellEventArgs) MyBase.OnCellValueChanged(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub Protected Overrides Sub OnColumnAdded(ByVal e As DataGridViewColumnEventArgs) MyBase.OnColumnAdded(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub Protected Overrides Sub OnColumnRemoved(ByVal e As DataGridViewColumnEventArgs) MyBase.OnColumnRemoved(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub Protected Overrides Sub OnRowsAdded(ByVal e As DataGridViewRowsAddedEventArgs) MyBase.OnRowsAdded(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub Protected Overrides Sub OnRowsRemoved(ByVal e As DataGridViewRowsRemovedEventArgs) MyBase.OnRowsRemoved(e) SendMessage(GetFormHandle(Me), WM_APP_CHANGEDATA, 0, 0) End Sub End Class
- 回答としてマーク 山本春海 2011年4月1日 5:46
-
フォームのロード時にフォーム上のコントロールを全て取得して、イベントをセットしてしまえば良いと思います。
ちなみに
private void CreateControlList( Control parent ) { foreach( Control control in parent.Controls ) { m_controlList.Add(control); // 再起処理(パネルやグループボックス用) CreateControlList(control); } }
こんなメソッドを用意して、ロード時に読んであげる事でコントロール一覧を取得して、
foreach( Control control in m_controlList ) { if (control is TextBox) { control.KeyDown += new System.Windows.Forms.KeyEventHandler(Common_KeyDown); } }
こんな感じでコントロールが何なのかを判断しながらハンドリングするってのはどうでしょう。- 回答としてマーク 山本春海 2011年4月1日 5:46