【C#】WindowsFormsアプリで秒針が0に来た時にイベントを実行する(カスタムイベント版)

様々なタイマーイベントに対応できるようにイベントをカスタムにしてみましょう

基本的な動作の事前確認

まず、単純なTimerイベントの練習を確認しておいてください

カスタムイベントのサンプル

 実行結果

評価のため、1秒おきにイベントによって更新されるようにしています
コードを確認して、コメントになっているところをコメント解除することで長針が0の時にのみLabelが更新されます

C#学習用にコードを作成しています
実行内容はシンプルです
これは、仕組みについて学習するためです
カスタムイベントなんて使わなくてもできちゃうよ〜と考えずにコーディングスキルの向上のためのシンプルなサンプルと捉えてください

構成

フォームのデザイン

Labelコントロール x1
Timerコントロール x1

Timerコントロールのプロパティとイベント登録

コード

using System;
using System.Windows.Forms;

namespace JihoSample
{
    public partial class Form1 : Form
    {
        // イベントハンドラを格納するイベント宣言
        public static event EventHandler<DateTimeEventArgs> Changed;

        public Form1()
        {
            InitializeComponent();
            
            // MyClassのインスタンスを生成
            new MyClass();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            // タイマーがトリガーされたときにイベントを発生させる
            OnChanged(DateTime.Now);

            // 毎秒のごとにイベントを発生させるためのコード(コメントアウトされている)
            // if (DateTime.Now.Second == 0)
            // {
            //     OnChanged(DateTime.Now);
            // }
        }

        protected virtual void OnChanged(DateTime currentTime)
        {
            // イベントを呼び出す
            Changed?.Invoke(this, new DateTimeEventArgs(currentTime));
        }

        public void ShowTimer(string msg)
        {
            // ラベルにメッセージを表示する
            label1.Text = msg;
        }
    }
}
using System;

namespace JihoSample
{
    // JihoSample ネームスペース内に DateTimeEventArgs クラスを定義しています。
    public class DateTimeEventArgs : EventArgs
    {
        // DateTimeEventArgs クラスには、現在の日時を格納する CurrentTime プロパティがあります。
        public DateTime CurrentTime { get; }

        // DateTimeEventArgs クラスのコンストラクタ。CurrentTime プロパティを初期化します。
        public DateTimeEventArgs(DateTime currentTime)
        {
            CurrentTime = currentTime;
        }
    }
}
namespace JihoSample
{
    internal class MyClass
    {
        public MyClass()
        {
            // Form1.Changed イベントに TimerChanged メソッドをイベントハンドラとして登録します。
            Form1.Changed += TimerChanged;
        }

        // TimerChanged メソッドは Form1.Changed イベントが発生したときに呼び出されます。
        private void TimerChanged(object sender, DateTimeEventArgs e)
        {
            // イベントの発生元である Form1 オブジェクトの ShowTimer メソッドを呼び出して、
            // DateTimeEventArgs から取得した現在の時刻を表示します。
            (sender as Form1).ShowTimer(e.CurrentTime.ToString());
        }
    }
}

解説

コードの各要素について説明します

  1. JihoSample名前空間: 名前空間は、関連するクラスと型をグループ化し、コードを整理するのに役立ちます
  2. MyClassクラス: MyClassinternal修飾子で定義されたクラスで、他のクラスからのアクセスが制限されています。このクラスは、タイマーのイベントを処理します。コンストラクタで、Form1.Changedイベントに TimerChanged メソッドをイベントハンドラとして登録します。
    • TimerChangedメソッド(イベントハンドラ): TimerChanged メソッドは、Form1.Changed イベントが発生したときに呼び出されるメソッドです。このメソッドは、受け取ったイベントのデータを使用して、Form1 クラスの ShowTimer メソッドを呼び出します。
  3. DateTimeEventArgsクラス: DateTimeEventArgs クラスは、EventArgs クラスを継承したカスタムのイベント引数クラスです。このクラスは、イベントに関連する追加のデータを提供するために使用されます。イベントハンドラの引数として渡されるものです。具体的には、CurrentTime プロパティを持ち、そのプロパティには DateTime オブジェクトが格納されます。
  4. Form1クラス: Form1 クラスは、System.Windows.Forms 名前空間内で定義されています。これはWindowsフォームアプリケーションのメインフォームを表します。
    • Changedイベント: Form1 クラス内には、public static event EventHandler<DateTimeEventArgs> Changed イベントが定義されています。このイベントは、タイマーが変更されたときに通知するために使用されます。
    • コンストラクタ: Form1 クラスのコンストラクタは、フォームの初期化と MyClass クラスの新しいインスタンスを作成します。MyClass のコンストラクタ内でイベントハンドラが登録されています。
    • timer1_Tickメソッド: このメソッドは、タイマーコントロール(timer1)の Tick イベントのハンドラです。タイマーが発生するたびに、現在の日時を引数として OnChanged メソッドを呼び出します。
    • OnChangedメソッド: このメソッドは、Changed イベントを発生させるための保護された仮想メソッドです。イベントを発生させる際に、DateTimeEventArgs オブジェクトを作成して渡します。
    • ShowTimerメソッド: このメソッドは、フォーム上のラベル(label1)にメッセージを表示するために使用されます。ShowTimer メソッドは、MyClass クラス内の TimerChanged メソッドから呼び出されます。

このコードは、タイマーを使用してフォーム上のラベルに現在の日時を表示する基本的なWindowsフォームアプリケーションを示しています。Form1 クラス内で定義された Changed イベントは、タイマーが変更されたときに他の部分で処理できるように通知するための仕組みです。

クラス図

シーケンス図

参考

VisualStudioで自動作成されるコード

namespace JihoSample
{
    partial class Form1
    {
        /// <summary>
        /// 必要なデザイナー変数です。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 使用中のリソースをすべてクリーンアップします。
        /// </summary>
        /// <param name="disposing">マネージド リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows フォーム デザイナーで生成されたコード

        /// <summary>
        /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディターで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.timer1 = new System.Windows.Forms.Timer(this.components);
            this.label1 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // timer1
            // 
            this.timer1.Enabled = true;
            this.timer1.Interval = 1000;
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(252, 162);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(67, 24);
            this.label1.TabIndex = 0;
            this.label1.Text = "label1";
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(13F, 24F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Controls.Add(this.label1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Timer timer1;
        private System.Windows.Forms.Label label1;
    }
}