Day After Day
tsurezure naru mamani...
ANOTHER DECADE

from 2022 when it's begining after/with CORONA Virus.

C#の開発環境もVSCodeで (DelegateとInvoke)

7月
26
2024
Back
Alt+HOME


長い仕事、待ち仕事は別のサブスレッドに任せて、メインスレッドはレスポンス良く反応してくれる・・為に記述せねばならないスレッド間通信が私には余りにも難解。取り敢えずメモって間違いに気づいたら直していこうと思う。
Delegate
ビジネスにおいて、マネージャやリーダが他の人に業務や責任を委譲する。
他のメソッドを代理で呼び出すための型のこと。
Invoke
措置の発動、権利の行使、策の実施など行動を起こす。
関数ポインタを別スレッドに投げる。コントロールのメソッドであるInvokeは、そのコントロールの属するスレッドで、投げられた関数を実行する。

サブスレッド起ち上げ時のスレッド間処理(Delegateを要する実例)


    private void StartKissThread()
    {
    	Thread kissThread = new Thread(() => 
    	{
    		// 接続情報チェックをした上でポートに接続を試みる処理
    		bool isConnected = TryConnectToPort();
    		bool isPortSet = PortCheck();
    		string msg =  isConnected ? "Connected to KISS Port." :
    				isPortSet ? "KISS Port is incorrect or TNC is not running." :
    					    "Setup the KISS Address and/or the Port.";
    		Color color = isConnected ? Color.Green :
    				isPortSet ? Color.Red :
    	    				    Color.Red;
    		UpdateLblMsgCallback(msg, color);
    
    		// サブスレッドで受信データの処理をする
    		if (isConnected)
    		{
    			StartClient();
    		}
    	});
    
    	kissThread.Start();
    }
    	

    このロジックはサブスレッドを起ち上げる過程において、ポート接続を試した上でその結果をUIスレッドのラベルにコールバック関数を使って書き込むもの。

  1. TryConnectToPort() を呼び出して接続完了したか否かを判定 isConnected = true or false

  2. PortCheck() を呼び出して、①接続情報が設定されているか、②設定はされいないかをチェック。
    ①isPortset = true ②isPortset = false

  3. この時の組合せの評価方法は・・
  4. 接続完了(isConnected:true)
    "Connected to KISS Port."
    Color.Green
    接続不可(isConnected:false)
    接続情報有り(isPortSet:true)
    "KISS Port is incorrect or TNC is not running."
    Color.Red
    接続不可(isConnected:false)
    接続情報無し(isPortSet:false)
    "Setup the KISS Address and/or the Port."
    Color.Red

    private bool TryConnectToPort()
    {
    	// Settingsからアドレスとポートのデータを読む
    	string addr = frmSettings.TxtKISS_Address.Text;
    	string port = frmSettings.TxtKISS_Port.Text;
    
    	// 接続に使用する情報を定義
    	string kissAddr;
    	int kissPort;
    
    	// 接続情報が設定されていたとき
    	if (addr.Length != 0 && port.Length != 0)
    	{
    		kissAddr = addr;				// string同士で代入の必要性は無い
    		kissPort = int.Parse(port);
    	}
    	else
    	{
    		return false;					// PortCheckと同じ結果だがあくまでこのメソッドの結果
    	}
    
       	// ポート接続のロジックを実装
    	try
       	{
    		client = new TcpClient(kissAddr, kissPort);
    		
    		return true;					// 接続された
    	}
       	catch (Exception)
     	{
    		return false;					// 接続情報以外の理由で失敗
    	}
    }
    	
    // Settingsの接続情報が設定されているかのチェック
    private bool PortCheck()
    {
    	string addr = frmSettings.TxtKISS_Address.Text;
    	string port = frmSettings.TxtKISS_Port.Text;
    
    	// アドレス・ポートのどちらか又は両方が設定されていない
    	if (addr.Length != 0 && port.Length != 0)
    	{
    		return true;			
    	}
    	else
    	{
    		return false;
    	}
    }
    	

  5. この評価結果に基づいてサブスレッドの状況をUIスレッドのラベルに色を変えてメッセージを表示する。 この時そのまま LblMsg.Text = "Message"; LblMsg.ForeColor = color; 等と記述しても、 この判定を行っているスレッドからラベルが定義されているUIスレッドへ直接アクセス出来ない。

Delegate型の宣言とDelegate型のコールバック関数


    public FrmMain()
    {
    	InitializeComponent();
    
    	// このフォーム自体のインスタンス
    	instance = this;
    }
    	

    // サブスレッドにおける代理メソッド
    public delegate void DelegateUpdateLblMsg(string msg, Color color);
    
    // ラベル変更に関するコールバック
    public static void UpdateLblMsgCallback(string msg, Color color)
    {
    	if (instance != null)
    	{
    		if (instance.InvokeRequired)
    		{
    			// Invoke処理が必要な場合
    			instance.Invoke(new DelegateUpdateLblMsg(instance.UpdateLblMsg), [msg, color]);
    		}
    		else
    		{
    			instance.UpdateLblMsg(msg, color);
    		}
    	}
    }
    
    // ラベルの変更
    private void UpdateLblMsg(string msg, Color color)
    {
    	if(LblMsg.InvokeRequired)
    	{
    		Invoke(new DelegateUpdateLblMsg(UpdateLblMsg));
    		return;
    	}
    	LblMsg.Text = msg;
    	LblMsg.ForeColor = color;
    }
    	


Back
Alt+HOME