【やりたいこと】
Form1: メインフォーム。ボタンがひとつあり、Form2から取得した内容を表示する。
Form2: テキスト入力用フォーム。テキスト入力欄とOKボタンがある。
やりたいフローは以下のとおりです。
Form1内部にあるボタンをクリック→Form2がモーダルで開く→Form2内にテキストを入力
→Form2内にあるOKボタンクリック→Form2が閉じる→Form1に先ほど入力したテキストが表示される
最後のForm2で入力した値をForm1へと渡す方法が分かりません。
今日はじめてC#プログラムをさわったので、基本的な質問かもしれません。
どうしてもすぐに出来る必要があるのですが、この部分で躓いてしまいました。
C/C++の基本は出来ます。
C#に詳しい方がいれば、是非教えて頂きたいです。
よろしくお願いします!
C# 複数フォームでのやりとり(メインフォームとテキスト入力用フォーム)
Re: C# 複数フォームでのやりとり(メインフォームとテキスト入力用フォーム)
解決となっていますが,方法が書かれていませんし,往々にしてまずい解決方法を採ることがあるので……。
・大きなプログラムで通常推奨される方法
Form2が必要とする情報や設定する情報をクラスにまとめ,そのクラスのインスタンスをForm1とForm2の間でやりとりする。
現実的にはModelに属するクラスを渡すことになるかと思います。
設定系などでキャンセル可能な場合は一度複製したものにデータを設定しておき,ApplyやOKのタイミングで複製したデータを有効化することになります。
・小さなプログラムで推奨される方法
個々のデータ毎にForm2にプロパティを作成します。
多くの情報を渡そうとすると設定項目が増えるため,あまりに増えた場合は先の方法の方がよいでしょう。
・ほとんど全ての場合において,推奨されない方法
Form2のTextBox1をinternalやpublicにして,Form1からアクセスを行う
この方法を使ってしまうと,例えばForm2の一部をユーザーコントロールとして切り出した場合などに,コードの修正がややこしくなります。
そもそも,他のクラスの内部実装をしらないと使えない時点でクラスとして失格です。
・大きなプログラムで通常推奨される方法
Form2が必要とする情報や設定する情報をクラスにまとめ,そのクラスのインスタンスをForm1とForm2の間でやりとりする。
現実的にはModelに属するクラスを渡すことになるかと思います。
設定系などでキャンセル可能な場合は一度複製したものにデータを設定しておき,ApplyやOKのタイミングで複製したデータを有効化することになります。
class ProgramSettings
{
public ProgramSettings ()
{
Title = "";
}
public ProgramSettings (ProgramSettings other)
{
if (other == null) throw new ArgumentNullException(nameof other); // C# 6.0以降。C# 5.0かそれ以前ではnameofが使えないので"other"とする
this.Title = other.Title;
}
public string Title { get; set; } // やりとりする情報。とりあえずはひとつだけ。
}
public partial class Form2
{
private ProgramSettings _settings = new ProgramSettings();
public ProgramSettings Settings
{
get { return _settings; }
set
{
if (value == null) throw new ArgumentNullException(nameof Settings);
_settings = value;
}
}
protected override void OnLoad (EventArgs e)
{
base.OnLoad(e);
TextBox1.Text = _settings.Title;
}
private void TextBox1_TextChanged (object sender, EventArgs e)
{
_settings.Title = TextBox1.Text;
}
}
public partial class Form1
{
private ProgramSettings _settings; // どこかで代入済み
private void Button1_Click (object sender, EventArgs e)
{
using (var form2 = new Form2())
{
var temporarySettings = new ProgramSettings(_settings)
form2.Settings = temporarySettings ;
if (form2.ShowDialog(this) != DialogResult.OK) return;
_settings.Title = temporarySettings.Title; // 目的次第で_settings = temporarySettings;でもよい。
Label1.Text = _settings.Title;
}
}
}
個々のデータ毎にForm2にプロパティを作成します。
多くの情報を渡そうとすると設定項目が増えるため,あまりに増えた場合は先の方法の方がよいでしょう。
public partial class Form2
{
public string TitleSetting
{
get { return TextBox1.Text; }
set
{
if (value == null) throw new ArgumentNullException(nameof TitleSetting);
TextBox1.Text = value;
}
}
}
public partial class Form1
{
private void Button1_Click (object sender, EventArgs e)
{
using (var form2 = new Form2())
{
form2.TitleSetting = "" ;
if (form2.ShowDialog(this) != DialogResult.OK) return;
Label1.Text = form2.TitleSetting;
}
}
}
Form2のTextBox1をinternalやpublicにして,Form1からアクセスを行う
public partial class Form1
{
private void Button1_Click (object sender, EventArgs e)
{
using (var form2 = new Form2())
{
form2.TextBox1.Text = "" ;
if (form2.ShowDialog(this) != DialogResult.OK) return;
Label1.Text = form2.TextBox1.Text;
}
}
}
そもそも,他のクラスの内部実装をしらないと使えない時点でクラスとして失格です。