質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

スレッドセーフ

マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

1回答

2754閲覧

別スレッドからメインWindowsフォームテキストボックスの値を取得する。

Dally

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

スレッドセーフ

マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

0クリップ

投稿2021/08/28 06:58

編集2021/08/28 07:55

始めまして。初心者です。
どうしても解決できないことがあり、投稿させていただきました。

前提・実現したいこと

WindowsFormにてシリアル通信アプリケーションを作成しています。
データの送受信処理はTimerスレッドを用いて一定時間間隔でデータの送受信を行います。
(実現したいこと)、
Timerスレッドを開始したのち、メインスレッドのWindowsFORMにあるテキストボックスから値
を取得したい。
具体的には、以下の手順で処理をしたい(当該部の詳細はソースコードを参照下さい)
(0) ボタンクリックするとTimerスレッドが開始(btnConnect_Clickイベント)
(1) TimerスレッドからMyGUIfunctionクラスで定義したDoGetSlaveID()をコール。
(2) DoGetSlaveID()は、
・別スレッドからメインスレッドへのアクセスがあるとき、
myFormControl1.doGetGUIByteDataDelegeteを渡す。
(3) doGetGUIByteDataDelegeteに登録されたGetSlaveIDを呼ぶ。
doGetGUIByteDataDelegete = new GetGUIByteData(GetSlaveID);
(4) テキストぼっくの値をByte型で変数に取得。
byte slaveID = myGUIFuncClassObject.DoGetSlaveID();

発生している問題・エラーメッセージ

error CS0029: 型 'void' を 'byte' に暗黙的に変換できません。

該当のソースコード

public partial class Form1 : Form { //Define Timer for TimerElapsedEventHandler System.Timers.Timer timer = new System.Timers.Timer();     // Byteの戻り値を持つ関数のDelegateの宣言 public delegate byte GetGUIByteData(); public GetGUIByteData doGetGUIByteDataDelegete; public Form1() { InitializeComponent();              // Byte戻り値を持つ関数をデリゲート登録 doGetGUIByteDataDelegete = new GetGUIByteData(GetSlaveID);       //ボタンクリックイベントを登録 btnConnect.Click += new EventHandler(btnConnect_Click); }     // ボタンクリック時の処理関数 private void btnConnect_Click(object sender, EventArgs e) {       //タイマー時間の設定 if (lbxSampleRate.Text != "") timer.Interval = Convert.ToDouble(lbxSampleRate.Text); // Set Default Time Period else timer.Interval = 1000; // Allow periodic timer events timer.AutoReset = true; // Hook up the Elapsed Event for the timer timer.Elapsed += new ElapsedEventHandler(timer_Elapsed); // Timer Thread Start timer.Start(); }     //Timerスレッドの処理関数 void timer_Elapsed(object sender, ElapsedEventArgs e) { MyGUIFunctionClass myFuncClassObject = new MyGUIFunctionClass(this); //byte slaveID = Convert.ToByte(txtSlaveID.Text); ★ byte slaveID = myGUIFuncClassObject.DoGetSlaveID();               ↑この文法でエラーが出ます。 } //テキストボックスから値をbyte型で取得 public byte GetSlaveID() { byte val = Convert.ToByte(txtSlaveID.Text); return val; } // ユーザフォームにアクセスする関数類はMyGUIFunctionClassに登録する public class MyGUIFunctionClass { Form1 myFormControl1; public MyGUIFunctionClass(Form1 myForm) { myFormControl1 = myForm; } public void DoGetSlaveID() { myFormControl1.Invoke(myFormControl1.doGetGUIByteDataDelegete); } }

試したこと

戻り値のない(void)処理関数の場合はエラーは出ません。
例:ボタンEnableをTrue、Falseにする
MyGUIFunctionクラスで
Public void DoButtonCont()

myFormControl1.Invoke(myFormControl1.doButtonContDelegete);       

FORM1クラスで
public void ButtonControl()

Button1.Enable = True;

また、エラー発生箇所で直接値を設定すると
Timetスレッドは正常に動作しています。
↑カウンタの動作なども含め24時間では問題ありません。
slaveID=(byte)2;

補足情報(FW/ツールのバージョンなど)

Microsoft Visual Studio Enterprise 2017
Version 15.9.37
VisualStudio.15.Release/15.9.37+28307.1585
Microsoft .NET Framework
Version 4.8.04084

MyGUIfunctionクラスを設けた理由は
・ GUIのボタンなど各種フォームの追加に対し柔軟に対応したいため。
特に、Timerスレッドにて処理し、その結果をフォーム上に表示する
逆に、フォーム上の情報と受信したデータの情報比較をTimerスレッドで
行う必要があるため。

以上、宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/08/28 07:14

コードは ``` と ``` で囲ってください(``` はバッククォート 3 つ)。インデントされて見やすくなるので。インデントされてなおコードは質問者さんも読む気がしないのでは? あ他の他人の閲覧者・回答者はなおさらです。見てもらえないと話が始まらないのですから見てもらえる努力をしませんか?
退会済みユーザー

退会済みユーザー

2021/08/28 07:19

> 別スレッドからメインWindowsフォームテキストボックスの値を取得する。 質問者さんのいう「別スレッド」とは何ですか? 上記の言葉だけから想像すると、何かのメソッドを Task.Run とかでスレッドプールスレッドで動かして、そのメソッドから UI スレッドの TextBox にアクセスするということですが、パッと見そうは見えないのですが・・・
Dally

2021/08/28 07:34

Surfer On Wwwさんへ 早速の連絡有難うございます。 初めての投稿なので```なるものが必要と思いませんでした。 コードの初めと最後につければいいのでしょうか? 次に、別スレッドとは、 System.Timers.Timer timer = new System.Timers.Timer(); timer.Elapsed += new ElapsedEventHandler(timer_Elapsed); に登録した timer_Elapsedメソッドのことを意味しています。 このメソッド内でスレッドIDを確認したところ、メインスレッドIDとは 異なる値でしたので、メインスレッドとは別のスレッドと表現しました。 表現上の混乱があるようでした連絡をお願いします。
退会済みユーザー

退会済みユーザー

2021/08/28 07:42

``` コードの一行目 ・・・ コードの最後の行 ``` 上記のようにすれば質問欄ではインデントされるはずです。
Dally

2021/08/28 07:47

SurferOnWwwさんへ ありがとうございます。 以下の当該ソースコードを再度投稿します。 (該当のソースコード)★印箇所が文法エラーとなります。 ``` public partial class Form1 : Form { //Define Timer for TimerElapsedEventHandler System.Timers.Timer timer = new System.Timers.Timer(); // Byteの戻り値を持つ関数のDelegateの宣言 public delegate byte GetGUIByteData(); public GetGUIByteData doGetGUIByteDataDelegete; public Form1() { InitializeComponent();        // Byte戻り値を持つ関数をデリゲート登録 doGetGUIByteDataDelegete = new GetGUIByteData(GetSlaveID); //ボタンクリックイベントを登録 btnConnect.Click += new EventHandler(btnConnect_Click); } // ボタンクリック時の処理関数 private void btnConnect_Click(object sender, EventArgs e) { //タイマー時間の設定 if (lbxSampleRate.Text != "") timer.Interval = Convert.ToDouble(lbxSampleRate.Text); // Set Default Time Period else timer.Interval = 1000; // Allow periodic timer events timer.AutoReset = true; // Hook up the Elapsed Event for the timer timer.Elapsed += new ElapsedEventHandler(timer_Elapsed); // Timer Thread Start timer.Start(); } //Timerスレッドの処理関数 void timer_Elapsed(object sender, ElapsedEventArgs e) { MyGUIFunctionClass myFuncClassObject = new MyGUIFunctionClass(this); //byte slaveID = Convert.ToByte(txtSlaveID.Text); ★ byte slaveID = myGUIFuncClassObject.DoGetSlaveID(); ↑この文法でエラーが出ます。 } //テキストボックスから値をbyte型で取得 public byte GetSlaveID() { byte val = Convert.ToByte(txtSlaveID.Text); return val; } // ユーザフォームにアクセスする関数類はMyGUIFunctionClassに登録する public class MyGUIFunctionClass { Form1 myFormControl1; public MyGUIFunctionClass(Form1 myForm) { myFormControl1 = myForm; } public void DoGetSlaveID() { myFormControl1.Invoke(myFormControl1.doGetGUIByteDataDelegete); } } ```
退会済みユーザー

退会済みユーザー

2021/08/28 07:50

「質問欄ではインデントされる」と言ったはずですが? コメント欄ではインデントされません。そもそもコメント欄は「質問への追記・修正の依頼」をする場所です。質問欄は編集できるので質問欄でやってください。
Dally

2021/08/28 07:56

申し訳ないです。 質問欄を編集しました。
gentaro

2021/08/28 08:09

> (4) テキストぼっくの値をByte型で変数に取得。 「テキストぼっく」って何やねんと思ってしまったのと、単純にvoid戻り値のメソッドからどうやったらbyteが取得できると思ってるのか、単純に勘違いしてるだけなのかが疑問。 質問文もソースも、もう一回ちゃんと自分で読んで見たほうが良さそう。
退会済みユーザー

退会済みユーザー

2021/08/28 11:31

さすがに戻り値が判らないレベルだと、普通に入門書から始めた方がいいのでは。
guest

回答1

0

ベストアンサー

byte slaveID = myGUIFuncClassObject.DoGetSlaveID();
'void' を 'byte' に暗黙的に変換できません。

質問者さんのコードで DoGetSlaveID の定義は以下のようになっており void を返すので当たり前の結果です。

public void DoGetSlaveID() { myFormControl1.Invoke(myFormControl1.doGetGUIByteDataDelegete); }

基本のキのところができてないようです。全体的に見直す必要があるのでは?

【追記】

下の 2021/08/28 20:21 の私のコメントで「あとで全体を見直したコードを回答欄に書いておきます」と書いた件です。

(1) デザイン画面で Form1 に TextBox, Button, Label をドラッグ&ドロップ

イメージ説明

(2) Form1.cs に以下のコードを実装

using System; using System.Windows.Forms; namespace WinFormsApp2 { public partial class Form1 : Form { private System.Timers.Timer timer; public Form1() { InitializeComponent(); this.textBox1.Text = "10"; this.timer = new System.Timers.Timer(); this.timer.Elapsed += Timer_Elapsed; this.label1.Text = ""; } private void button1_Click(object sender, EventArgs e) { this.timer.Interval = 3000d; this.timer.Start(); } private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { // TextBox.Text から値を取得するのは Invoke を使う必要はなく //byte slaveId = (byte)this.Invoke((Func<byte>)(() => Convert.ToByte(this.textBox1.Text))); // これで良い byte slaveId = Convert.ToByte(this.textBox1.Text); // 書き込む場合は Invoke を使う必要がある this.Invoke((Action)(() => this.label1.Text += $"{slaveId} ")); } } }

(3) 実行して Button1 をクリックすると Timer.Interval の間隔で TextBox.Text から文字列を取得し、それを byte に変換して Label に書き込み

イメージ説明

投稿2021/08/28 08:03

編集2021/08/28 14:11
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Dally

2021/08/28 08:53

もう少し基本構文を教えてもらえないでしょうか? ご指摘の変更をすると戻り値の設定が必要になると思います。 戻り値xxxにdoGetGUIByteDataDelegete で委譲しているGetSlaveIDメソッドの戻り値を を使いたい方針でいます。   public byte DoGetSlaveID() { myFormControl1.Invoke(myFormControl1.doGetGUIByteDataDelegete); return xxx; ← この戻り値xxxをどのように得るのか? }
退会済みユーザー

退会済みユーザー

2021/08/28 11:21

全体的に基本ができてないようで、そこだけ見直してもダメだと思います。あとで全体を見直したコードを回答欄に書いておきます。
Dally

2021/08/28 13:03

連絡が遅れ申し訳ありません。 親切な解答を頂き助かりました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問