🗿

[C#/WPF] Windowクラスのイベント全部、発生時にログ取ってみる

2021/09/09に公開

もくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f

やりたいこと

WPFを作っていてよく思うのが、ウインドウを起動したときにどのイベントが、どういう順番で、 発生しているのか、ということだった。

一度、全部のイベントでログを吐くようにしてみて、発生する順番をはっきりさせたい。

やったこと

試しに、Windowクラスの全イベントにログを仕込んで見ようと思った。

本当は、

Type type = typeof(MainWindow);
var methodInfos = type.GetEvents();

LogOnDesktop.WriteLogToDesktopLogFile("-----------------------イベント
foreach (var mi in methodInfos)
{
    //mi.AddEventHandler(this, ログを吐くメソッド・・・);
}

みたいな感じで、全イベントにログを仕込むようにしたかったのだが、AddEventHandler()の第二引数にどういうものを渡せばそれが実現できるのかが全然わからなかったので、いったんやめて、泥臭い方法で実現した。

具体的にやったこと

コード

下記のようなコードを作った。

MainWindow.xaml.cs
using System;
using System.IO;
using System.Windows;

namespace WpfApp48
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // すべてのイベント発生時に、自分のイベントの名前を出力するよう登録
            SourceInitialized += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("SourceInitialized"); });
            DpiChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("DpiChanged"); });
            Activated += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("Activated"); });
            Deactivated += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("Deactivated"); });
            StateChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StateChanged"); });
            LocationChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("LocationChanged"); });
            Closing += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("Closing"); });
            Closed += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("Closed"); });
            ContentRendered += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ContentRendered"); });
            PreviewMouseDoubleClick += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseDoubleClick"); });
            MouseDoubleClick += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseDoubleClick"); });
            TargetUpdated += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("TargetUpdated"); });
            SourceUpdated += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("SourceUpdated"); });
            DataContextChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("DataContextChanged"); });
            RequestBringIntoView += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("RequestBringIntoView"); });
            SizeChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("SizeChanged"); });
            Initialized += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("Initialized"); });
            Loaded += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("Loaded"); });
            Unloaded += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("Unloaded"); });
            ToolTipOpening += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ToolTipOpening"); });
            ToolTipClosing += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ToolTipClosing"); });
            ContextMenuOpening += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ContextMenuOpening"); });
            ContextMenuClosing += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ContextMenuClosing"); });
            PreviewMouseDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseDown"); });
            MouseDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseDown"); });
            PreviewMouseUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseUp"); });
            MouseUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseUp"); });
            PreviewMouseLeftButtonDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseLeftButtonDown"); });
            MouseLeftButtonDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseLeftButtonDown"); });
            PreviewMouseLeftButtonUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseLeftButtonUp"); });
            MouseLeftButtonUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseLeftButtonUp"); });
            PreviewMouseRightButtonDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseRightButtonDown"); });
            MouseRightButtonDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseRightButtonDown"); });
            PreviewMouseRightButtonUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseRightButtonUp"); });
            MouseRightButtonUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseRightButtonUp"); });
            PreviewMouseMove += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseMove"); });
            MouseMove += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseMove"); });
            PreviewMouseWheel += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewMouseWheel"); });
            MouseWheel += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseWheel"); });
            MouseEnter += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseEnter"); });
            MouseLeave += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("MouseLeave"); });
            GotMouseCapture += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("GotMouseCapture"); });
            LostMouseCapture += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("LostMouseCapture"); });
            QueryCursor += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("QueryCursor"); });
            PreviewStylusDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusDown"); });
            StylusDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusDown"); });
            PreviewStylusUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusUp"); });
            StylusUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusUp"); });
            PreviewStylusMove += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusMove"); });
            StylusMove += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusMove"); });
            PreviewStylusInAirMove += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusInAirMove"); });
            StylusInAirMove += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusInAirMove"); });
            StylusEnter += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusEnter"); });
            StylusLeave += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusLeave"); });
            PreviewStylusInRange += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusInRange"); });
            StylusInRange += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusInRange"); });
            PreviewStylusOutOfRange += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusOutOfRange"); });
            StylusOutOfRange += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusOutOfRange"); });
            PreviewStylusSystemGesture += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusSystemGesture"); });
            StylusSystemGesture += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusSystemGesture"); });
            GotStylusCapture += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("GotStylusCapture"); });
            LostStylusCapture += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("LostStylusCapture"); });
            StylusButtonDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusButtonDown"); });
            StylusButtonUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("StylusButtonUp"); });
            PreviewStylusButtonDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusButtonDown"); });
            PreviewStylusButtonUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewStylusButtonUp"); });
            PreviewKeyDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewKeyDown"); });
            KeyDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("KeyDown"); });
            PreviewKeyUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewKeyUp"); });
            KeyUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("KeyUp"); });
            PreviewGotKeyboardFocus += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewGotKeyboardFocus"); });
            GotKeyboardFocus += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("GotKeyboardFocus"); });
            PreviewLostKeyboardFocus += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewLostKeyboardFocus"); });
            LostKeyboardFocus += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("LostKeyboardFocus"); });
            PreviewTextInput += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewTextInput"); });
            TextInput += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("TextInput"); });
            PreviewQueryContinueDrag += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewQueryContinueDrag"); });
            QueryContinueDrag += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("QueryContinueDrag"); });
            PreviewGiveFeedback += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewGiveFeedback"); });
            GiveFeedback += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("GiveFeedback"); });
            PreviewDragEnter += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewDragEnter"); });
            DragEnter += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("DragEnter"); });
            PreviewDragOver += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewDragOver"); });
            DragOver += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("DragOver"); });
            PreviewDragLeave += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewDragLeave"); });
            DragLeave += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("DragLeave"); });
            PreviewDrop += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewDrop"); });
            Drop += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("Drop"); });
            PreviewTouchDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewTouchDown"); });
            TouchDown += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("TouchDown"); });
            PreviewTouchMove += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewTouchMove"); });
            TouchMove += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("TouchMove"); });
            PreviewTouchUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("PreviewTouchUp"); });
            TouchUp += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("TouchUp"); });
            GotTouchCapture += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("GotTouchCapture"); });
            LostTouchCapture += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("LostTouchCapture"); });
            TouchEnter += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("TouchEnter"); });
            TouchLeave += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("TouchLeave"); });
            IsMouseDirectlyOverChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsMouseDirectlyOverChanged"); });
            IsKeyboardFocusWithinChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsKeyboardFocusWithinChanged"); });
            IsMouseCapturedChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsMouseCapturedChanged"); });
            IsMouseCaptureWithinChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsMouseCaptureWithinChanged"); });
            IsStylusDirectlyOverChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsStylusDirectlyOverChanged"); });
            IsStylusCapturedChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsStylusCapturedChanged"); });
            IsStylusCaptureWithinChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsStylusCaptureWithinChanged"); });
            IsKeyboardFocusedChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsKeyboardFocusedChanged"); });
            LayoutUpdated += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("LayoutUpdated"); });
            GotFocus += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("GotFocus"); });
            LostFocus += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("LostFocus"); });
            IsEnabledChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsEnabledChanged"); });
            IsHitTestVisibleChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsHitTestVisibleChanged"); });
            IsVisibleChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("IsVisibleChanged"); });
            FocusableChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("FocusableChanged"); });
            ManipulationStarting += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ManipulationStarting"); });
            ManipulationStarted += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ManipulationStarted"); });
            ManipulationDelta += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ManipulationDelta"); });
            ManipulationInertiaStarting += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ManipulationInertiaStarting"); });
            ManipulationBoundaryFeedback += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ManipulationBoundaryFeedback"); });
            ManipulationCompleted += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ManipulationCompleted"); });
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {

            // すべてのイベントの名前を表示
            Type type = typeof(MainWindow);
            var methodInfos = type.GetEvents();

            LogOnDesktop.WriteLogToDesktopLogFile("-----------------------イベントの一覧--------------------------");
            foreach (var mi in methodInfos)
            {
                LogOnDesktop.WriteLogToDesktopLogFile(mi.Name);

                // 本当はここでイベント登録までやりたかったが、できなかった...
                // ※第二引数のイベントの型を動的に変える方法がわからなかった。
                //mi.AddEventHandler(this, a);
            }
        }
    }

    // ログをデスクトップに残すためのクラス
    static class LogOnDesktop
    {
        public static void WriteLogToDesktopLogFile(string line)
        {
            var logPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\log.log";

            File.AppendAllText(logPath, DateTime.Now.ToString("hh:mm:ss.fff") + "  " + line);
            File.AppendAllText(logPath, Environment.NewLine);
        }
    }
}

※一番下にあるLogOnDesktopクラスは、単にデスクトップにログを吐くだけのクラス。

コードをつくるときにやったこと

まず、上のコード中にもある下記ロジックで、Windowクラスが持つイベントを全部文字で吐き出させた。

// すべてのイベントの名前を表示
Type type = typeof(MainWindow);
var methodInfos = type.GetEvents();

LogOnDesktop.WriteLogToDesktopLogFile("-----------------------イベントの一覧
foreach (var mi in methodInfos)
{
    LogOnDesktop.WriteLogToDesktopLogFile(mi.Name);
}

次に、それをEXCELに貼り付けて、ログを吐くイベントを全部に登録できるコードが簡単にできるよううまいこと?やった。

↓こんな感じ

それで出来たコードをMainWindowのコンストラクタに貼り付けてできあがり。

結果

このアプリを起動し、その後ただ×ボタンを押して閉じる、という操作をすると、下記のようなイベントが出ていた。

11:01:48.115  IsVisibleChanged
11:01:48.214  SizeChanged
11:01:48.222  LayoutUpdated
11:01:48.231  SourceInitialized
11:01:48.737  Activated
11:01:48.787  PreviewGotKeyboardFocus
11:01:48.796  IsKeyboardFocusWithinChanged
11:01:48.809  IsKeyboardFocusedChanged
11:01:48.847  GotKeyboardFocus
11:01:48.886  LayoutUpdated
11:01:48.895  Loaded
11:01:48.922  ContentRendered
11:01:48.936  LayoutUpdated
11:01:49.120  LayoutUpdated
11:01:49.135  LayoutUpdated
11:01:49.223  LayoutUpdated
11:01:49.240  LayoutUpdated
11:01:49.267  LayoutUpdated
11:01:49.278  LayoutUpdated
11:01:49.287  LayoutUpdated
11:01:49.297  LayoutUpdated
11:01:49.307  LayoutUpdated
11:01:51.175  Closing
11:01:51.181  IsVisibleChanged
11:01:51.204  Deactivated
11:01:51.262  IsKeyboardFocusWithinChanged
11:01:51.271  IsKeyboardFocusedChanged
11:01:51.278  LostKeyboardFocus
11:01:51.294  Closed

これで、Windowが起動したときに、どういう順番でイベントが来ているかがわかった。
あとWindowの上でマウスを移動したりクリックしたりすると、またイベントが来てる様を見ることができる。(Spy++と見比べても面白そう?)

考察

Initializedイベントが来てない?
 ↓
下記のようにコードを変えると、来るようになった。
(来るようになったというか、元から来てたけどすでに来た後にハンドラ登録してたからログできてなかった)


       public MainWindow()
       {

           // ★★イベント登録を、InitializeComponent()より先に持ってくる
           SourceInitialized += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("SourceInitialized"); });
           DpiChanged += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("DpiChanged"); });
              ・
              ・
           ManipulationCompleted += ((obj, ev) => { LogOnDesktop.WriteLogToDesktopLogFile("ManipulationCompleted"); });

           InitializeComponent();
       }
              ・
              ・

これを、面倒だがWindow上に配置したいろんなコントロールに書いてやれば、ルーティングイベントの流れの勉強ができそうな気がする。

Discussion