ラベル c# の投稿を表示しています。 すべての投稿を表示
ラベル c# の投稿を表示しています。 すべての投稿を表示

2019年10月18日金曜日

【.netFramework】フォーム継承利用時のイベントハンドラの処理順

ある程度のシステムになると、基底フォームを作成して共通処理を実装し、個別は継承先のフォームで実装する。というケースが多くなると思います。

キーボードイベントの処理順がうまくいかないと技術者から聞かれ、過去の記憶を確認すべく、サンプル書いて確認しました。(サンプルコード(zip)は記事の一番下に置いてあります)

【結果】

OnKey****の場合、継承先から順番に処理される。(上書き用途)
Key****のイベントハンドラの場合、基底から処理される

なお、本検証結果は「一般的な実装方法を用いた場合」の結果であり、色々とコードで工夫をなさった場合にはこの限りではありません。例)On***系の実装でbase.On***を呼ばない。とか、基底のイベントハンドラを登録するタイミングを継承先で指定するなど、振る舞いを変える方法はあると思います。

【検証した方法】

1.以下3つのフォームを用意する
  ・基底フォーム (TestBaseForm)
  ・基底を継承したフォーム (InheritForm1)
  ・さらに継承したフォーム(InheritInheritForm2)
2.それぞれに、同じメソッド、イベントを実装
3.プログラムを実行して、順番を把握

【実装イメージ】

【テストコード】


/// 同じコードを継承先のフォームにも記載
public partial class TestBaseForm : Form
{
    string _myFormName = "TestBaseForm"; // ここは実装するフォーム名にする
    public TestBaseForm()
    {
        InitializeComponent();
        this.KeyPreview = true;
        this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form_KeyDown);
        this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form_KeyPress);
        this.KeyUp += new KeyEventHandler(this.Form_KeyUp);
    }
    protected override void OnKeyDown(KeyEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("{0}:{1}", _myFormName, System.Reflection.MethodBase.GetCurrentMethod().Name));
        base.OnKeyDown(e);
    }
    protected override void OnKeyPress(KeyPressEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("{0}:{1}", _myFormName, System.Reflection.MethodBase.GetCurrentMethod().Name));
        base.OnKeyPress(e);
    }
    protected override void OnKeyUp(KeyEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("{0}:{1}", _myFormName, System.Reflection.MethodBase.GetCurrentMethod().Name));
        base.OnKeyUp(e);
    }
    private void Form_KeyDown(object sender, KeyEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("{0}:{1}", _myFormName, System.Reflection.MethodBase.GetCurrentMethod().Name));
    }
    private void Form_KeyUp(object sender, KeyEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("{0}:{1}", _myFormName, System.Reflection.MethodBase.GetCurrentMethod().Name));
    }
    private void Form_KeyPress(object sender, KeyPressEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("{0}:{1}", _myFormName, System.Reflection.MethodBase.GetCurrentMethod().Name));
    }
}

【実行ログ】

Log内容 Method 基底 継承1 継承2
InheritInheritForm2:OnKeyDown OnKeyDown    
InheritForm1:OnKeyDown OnKeyDown    
TestBaseForm:OnKeyDown OnKeyDown    
TestBaseForm:Form_KeyDown KeyDown    
InheritForm1:Form_KeyDown KeyDown    
InheritInheritForm2:Form_KeyDown KeyDown    
InheritInheritForm2:OnKeyPress OnKeyPress    
InheritForm1:OnKeyPress OnKeyPress    
TestBaseForm:OnKeyPress OnKeyPress    
TestBaseForm:Form_KeyPress KeyPress    
InheritForm1:Form_KeyPress KeyPress    
InheritInheritForm2:Form_KeyPress KeyPress    
InheritInheritForm2:OnKeyUp OnKeyUp    
InheritForm1:OnKeyUp OnKeyUp    
TestBaseForm:OnKeyUp OnKeyUp    
TestBaseForm:Form_KeyUp KeyUp    
InheritForm1:Form_KeyUp KeyUp    
InheritInheritForm2:Form_KeyUp KeyUp    

【まとめ】

フォームを継承して利用する際には、継承元に実装するロジックの用途、継承先での振る舞いを考慮したうえで実装を決めることをお勧めします。

【ソース】

20191018_KeyboardEventOrderTest_source.zip