- ベストアンサー
子Formからの値を表示する方法
- 初心者が.NET C#で開発をしている場合、親FormのReadOnlyのtextBox1をダブルクリックすると子Form2が表示されます。
- 子Form2ではラジオボタンなどを使用して各項目を選択し、選択した結果の文字列が子Form2のReadOnlyのtextBox1に表示されます。
- 決定ボタンであるButton1を押すと、子Form2が閉じられ、その時に親Form1のtextBox1に子Form2で決定した文字列が表示されます。
- みんなの回答 (11)
- 専門家の回答
質問者が選んだベストアンサー
あー、すみません、そこ間違ってました。 親フォームの「オブジェクト」が必要なので、こんな感じになります。 便宜上、親フォームのクラス名をparentForm、子フォームのクラス名をchildFormとしますので適宜読み替えてください。 子フォーム側: class childForm { ... parentForm parent; // 親フォームの参照 public void setParent(parentForm parent) { // 親フォームから参照を受け取って保持する this.parent = parent; } ... { // 親フォームの関数を呼び出す parent.ctlFromChild("文字列"); } ... } 親フォーム側: class parentForm { ... childForm child; { child = new childForm(); // 子フォーム作成 // 子フォームに自分のオブジェクト参照を渡す child.setParent(this); } ... } 本当はコールバック関数をデリゲートで渡してやる方が筋はいいと思うんですが、今回はこれでOKかと。 上記では親フォームのオブジェクトを登録する関数を作っていますが、コンストラクタで実装してもOKです。 あと、申し訳ないのですがこれは動作試験してないので、これで駄目なら上記の「コールバック関数をデリゲートで渡す」方を紹介します。
その他の回答 (10)
- D-Matsu
- ベストアンサー率45% (1080/2394)
んー、#9でもタイプミスを指摘してるんですからそれを疑ってほしかった。 正直このレベルの確認を怠って「何故?」と聞かれるのは非常に悲しいです。 > new T"h"readStart です。hが足らない。
お礼
大変お恥ずかしい限りでございます。 わたしも悲しくなってきました。 hを足した事で、親フォームのエラーはなくなりました。 最初の頃に頂きましたご回答で >子フォームからは任意のタイミング(質問の場合は子フォームの >OnCloseイベントハンドラ中)でparentForm.changeTextBox1を >呼び出すことで親のtextBox1が書き換わります。 こうありましたが、、 子フォームから「 親フォーム名.changeTextBox1」 を呼び出して もエラー(「静的でないフィールド、メソッド、・・・・で、 オブジェクトが必要です。」)になるのは、 今では記述内容が変わってしまったからでしょうか。
- D-Matsu
- ベストアンサー率45% (1080/2394)
……って違う。 自力でタイプするのはいいんですが、間違いなくやるようにしてください。 カッコのエラーは、こちらで提示したコードが > Invoke((ctlFromChild)delegate であるのに対して、エラーが出ているのは > Invoke((ctlFromChild)(delegate となると、delegate前の(を取るのが正しいです。
お礼
大変失礼いたしました。 delegate前の(は取りました。 > 型または名前空間名 'TreadStart' が見つかりませんでした で何が足りないかは、「using System.Threading;」は追加しましたし、 何が足りないんだろう。 すいません、分かりません。
- D-Matsu
- ベストアンサー率45% (1080/2394)
カッコの不足分についてはそれであってます。 というか欠けてましたか、すみません。 > 型または名前空間名 'TreadStart' が見つかりませんでした 先の回答で提示した該当部分は > new ThreadStart です。さて何が足りないでしょう?
- D-Matsu
- ベストアンサー率45% (1080/2394)
お待たせしました。別解です。 System.Threadingを使うので、別途using宣言してください。 デリゲート宣言からやりなおします。 private delegate void ctlFromChild(); public void changeTextBox1(string str) { new Thread(new ThreadStart( delegate { Invoke((ctlFromChild)delegate { textBox1.Text = str; }); })).Start(); } 動いているコードから引っ張ってきたものなので、これならたぶん大丈夫じゃないかと。
お礼
いつもお世話になっております。 「 )がありません。」とエラーが出ていましたので、下記記述 「Invoke((ctlFromChild)(delegate { textBox8.Text = str; });」 の中の最後に「}));」付け足しました。合っていますでしょうか。 また、 「new Thread(new TreadStart(delegate」の「TreadStart」部分に 赤い下波線が有り、「型または名前空間名 'TreadStart' が見つかりません でした。using ディレクティブまたはアセンブリ参照が不足しています。」 と出ています。 今回「using System.Threading;」は追加しております。 どこが悪いでしょうか。
- D-Matsu
- ベストアンサー率45% (1080/2394)
難しいっつーか面倒なだけなんですけどね。 アクセス制限ということなら関数にpublic宣言が入ってないせいかとも思いますが、昨日別解を掘り起こしたので帰宅したらそちらのコードも提示しますね。 まぁ別解とは言っても、デリゲートを使ってるという点では一緒なんですが。
- D-Matsu
- ベストアンサー率45% (1080/2394)
えーと、私も最近C#を使ってないので色々抜けてるようです。 静的関数ではないためにオブジェクトが要るので、引数changeTextBox1delの頭にthis.を付けてみてください。 それで駄目ならthisの代わりに親フォームの名前を。
お礼
お世話になっております。 すみません。先程の「静的な・・・」と言うエラーメッセージ内容は、 子Formの呼び出し側の方でした。 呼び出すメソッド名の頭に、親フォーム名を付けました。そうしましたら、 おそらく親Formの下記記述部分でエラーが出ている為に、 「アクセスできない保護レベルになっています。」と出ました。 親Formの 「Invoke(new ctlFromChild(changeTextBox1del(str)));」 のchangeTextBox1del(str)に赤い下波線が出ていたエラー内容は、 「メソッド名が必要です。」でした。 メソッドと思われていないと言う事でしょうか。 デリゲートって難しいですね。
- D-Matsu
- ベストアンサー率45% (1080/2394)
あー、すみません、型を忘れてました。 delegate void ctlFromChild(string str); でどうでしょうか?
お礼
お世話になります。今度は、 「Invoke(new ctlFromChild(changeTextBox1del(str)));」 のchangeTextBox1del(str)に赤い下波線が出ていまして、 エラー内容が「静的でないフィールド、メソッド、・・・・で、 オブジェクトが必要です。」と出ています。 私の何かがいけないのでしょうか・・。
- D-Matsu
- ベストアンサー率45% (1080/2394)
ctlFromChildは「親フォーム内」に定義する「デリゲート」であってクラスではありませんから、「子フォーム名」に置き換えてはいけません。まぁ同じにしてあれば何かと被らない限りはどんな名前にしてもいいんですが。 #2での提示部分はそのまま使えるように書いたつもりなので、とりあえずは書き換えせずにやってみてください。 一方で「parentForm」については親フォーム名に置き換えてもらっていいというか、置き換えてもらわなければいけません。
お礼
お世話になっております。 何度もすみません。 そのまま記述追加致しましたが、 「delegate ctlFormChild(string str);」の「(」カッコの部分と、 「Invoke(new ctlFormChild(change・・・)」の「ctlFormChild」の 部分に赤い下波線が出てモジュールエラーとなってしまいました。
- D-Matsu
- ベストアンサー率45% (1080/2394)
まず子フォームのクラスメンバ変数にTextbox型の変数を追加します。 で、子フォームの作成時にでも親フォームから自身のtextBox1を渡してやり、子フォームでは上記メンバ変数に格納します。 上記で受け渡したものは参照として機能し、子フォームから親フォームのtextBox1を任意のタイミングで操作出来るようになります。 ……って思ったんですが、よくよく考えると今回は別にtextBox1の参照持ってる必要はないですね。失礼しました。 親フォーム側に文字列型を投げるとtextBox1を変更するパブリックメンバ関数を用意しておいて、その中でデリゲートで処理を委譲するようにして子フォームからこのパブリックメンバ関数を呼べばいいです。 親フォーム側: class parentForm { // 記述追加 delegate ctlFromChild(string str); public void changeTextBox1(string str) { Invoke(new ctlFromChild(changeTextBox1del(str))); } void changeTextBox1del(string str) { this.textBox1.text = str; } }; 上記処理を追加しておいて、子フォームからは任意のタイミング(質問の場合は子フォームのOnCloseイベントハンドラ中)でparentForm.changeTextBox1を呼び出すことで親のtextBox1が書き換わります。 なんでこう書く必要があるのかは先に提示したURLを読んでください。 なお、複数のテキストボックスを汎用的に扱いたい場合は、最初に言ったように操作対象のコントロールの参照を持っておくとコードが共通化できて見通しが良くなります。
お礼
ご丁寧に有難うございます。 しかし、私のスキル不足のよりモジュールエラーが出ており、 何度も申し訳ございませんが、再度ご確認させて頂きたく、 宜しくお願い致します。 確認1 「delegate ctlFromChild(string str);」と 「Invoke(new ctlFromChild(changeTextBox1del(str)));」に 出てくる「ctlFromChild」は、実際の子フォーム名に置き換えて 良いのですよね。 確認2 「Invoke(new ctlFromChild(changeTextBox1del(str)));」 の「(changeTextBox1del(str)」の部分に赤い下波線が出ており、 メソッド名が必要です。と言うモジュールエラーが出てしまっています。 何かが間違い又は不足でしょうか。 確認3 子フォームの呼び出しのコードを下記の様に書いたのですが、 間違ってますでしょうか。「Form1.changeTextBox8(mojiretu)」 と言う所に赤い下波線が出てしまっていて、 「静的でないフィールド、メソッド、またはプロパティに含まれていないため、 コードの解析または生成をサポートしません。」と言うモジュールエラー が出てしまっているのですが。 string mojiretu; mojiretu = textBox1.Text; Form1.changeTextBox8(mojiretu); ↑実際の親フォーム名 ↑実際の親フォームテキストボックス
- D-Matsu
- ベストアンサー率45% (1080/2394)
・親フォームのtextBox1の参照を子フォームに持たせておく ・子フォームが閉じられた、あるいはButton1を押したら参照を使って内容を更新 という流れですね。 なお、普通にこれだけ書くと通常設定ではエラーになります。 設定で回避することも不可能ではありませんが、デリゲートを使って親Formのスレッドで書くようにするのが普通です。 http://www.atmarkit.co.jp/fdotnet/dotnettips/312ctrlinvoke/ctrlinvoke.html
お礼
ご回答頂きありがとうございます。 「参照を子フォームに持たせる」、「参照を使って内容を更新」とは 具体的にどの様にすれば良いのでしょうか。 差し支えなければお教え頂きたく宜しくお願いします。
お礼
長い間この初心者の私にお付き合い下さり、 誠に感謝致します。 おかげさまで、 >// 親フォームの関数を呼び出す > parent.ctlFromChild("文字列"); 部分を parent.changeTaxtBo1("文字列"); に変えたらエラーが解消され、 子フォームのテキストボックスに書いた文字列が、 親フォームのテキストボックスに反映される事が 出来ました。 ただThreadや、Invokeなどの意味はまだ今一分からない のでゆっくり勉強しようと思います。 本当に有難うございました。 今後とも宜しくお願い致します。