none
form1からform2を開き、form2を閉じたときに、form1のあるメソッドを実行する方法は? RRS feed

  • 質問

  • いつもお世話になります。
    VisualC#2010、WindowsXPでの動作について質問があります。
    form1からform2を開き、form2を閉じたときに、form1のあるメソッドを実行する方法は?
    Form form2 = new Form();
    form2.Show();

    とかで、form2を表示できますが、このform2を閉じる(閉じた)ときに、form1のほうにあるメソッドを実行する方法を教えてください。

    form2からForm1に、値をもどす方法を知りたいです。
    こういうときには、なにを使うのでしょう?

    form1のメソッドをpublicにして、closingで実行する?
    private void form2_FormClosing(object sender, FormClosingEventArgs e) {
     Form form1 = new Form();//これだと新しいformを開く? 開かない方法は?
     form1.method(argments); //methodはform1のpublic method
    }

    2011年3月8日 6:27

回答

  • form2からForm1に、値をもどす方法を知りたいです。
    こういうときには、なにを使うのでしょう?

    ここだけみれば、form2.ShowDialog()で実現できそうです。ShowDialog()で開いたform2は閉じられても表示が消えるだけでform2のインスタンスは残っていますから、form2のpublicなプロパティで値を公開しておけば、それをform1から読み取ることが可能です。form1でform2.ShowDialog()でform2を開いた場合、form2を閉じるとform2.ShowDialog()の次の行から実行が再開されますから、そこで読み取れば良いです。
    なお、先に書きました通り、form2のインスタンスが残ったままになりますから、それが必要なくなったら必ずform2.Dispose()でform2のインスタンスを消して下さい。または、
    using (var from2 = new Form2())
    {
        form2.ShowDialog();
      メソッド(form2.publicなプロパティ);    //form1のメソッドの実行。引数はform2のpublicなプロパティから取得
           ・
           ・
           ・
    }
    とすれば、usingステートメントを抜ければ自動的にform2がDisposeされます。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月8日 13:40
    モデレータ
  • 依存関係を考えると、親(利用側)となるクラスのメソッドを具体的に呼ぶことは避けるべきです。
    (実装でチェックする・しないではなく、設計として避けるべき)

    この場合、イベントを外部に公開する、渡したい値をプロパティで公開するといった形をおすすめします。
    以下は、Form2 に Test プロパティを追加し、Form1 に渡したい値が入っていると言うことを想定したものです。

    private int _test;
    private Form2 _form2;
    private void Button1_Click(object sender, EventArgs e)
    {
     if (_form2 != null) return;
     _form2 = new Form2();
     form2.FormClosing += form2_FormClosing;
     form2.Show();
    }
    
    private void form2_FormClosing(object sender, FormClosingEventArgs e)
    {
     _test = _form2.Test;
     _form2 = null;
    }
    
    
    

    ところで、new Form と書かれていましたが、new Form2 で良いのですよね?

    # trapemiya さんが投稿されているように、ShowDialog で済むならそれが楽で良いと思います。
    # プロパティが必要なる点は変わりません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月8日 14:00
    モデレータ
  • 共通のメソッドは別クラスを作成して、そこでpublicにて公開したらいいと思いますよ。

    Utilityクラスとか名づけて、

    Utility util = new Utility();

    util.作成した共通メソッド();

    とかで呼び出しましょう。

    多分、これが一番単純です。

    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月9日 1:47
  • プロパティはすこし使っているのですが、設定がめんどうな気がしていて、それで聞いてみました。質問のときには、あまりにめんどうなので忘れていたのですが…。


    それはプロジェクトのプロパティから開いた画面の設定タブで設定する値のことであり、私が言っているプロパティはC#の言語の仕組みとして持っているプロパティのことです。例えば、以下などを一度読んでみて下さい。

    プロパティ
    http://ufcpp.net/study/csharp/oo_property.html

    form2に例えば科目コードというプロパティを設定することにより、以下のように記述できるようになります。

    form1のメソッド(form2.科目コード);    //form1のメソッドの実行。引数はform2のpublicなプロパティから取得


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月9日 1:56
    モデレータ
  • class Form2

    {

        Form1 form1;

         public Form2(Form form1)

       {

         this.form1=form1;

      }

    }

    form1をform2のconstructor参数をとして こうすると public methodを開ける。



    山西.net俱乐部
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月9日 5:11
  • 既に色々な人が書かれていますが、arguments をプロパティとして公開して、イベントを使うのが作り方としては手軽かな、と思います。最初の投稿に書かれている部分でいえば、form2 は新規に new するのではなく、sender を使用します。sender はそのイベントを発生させたものが入っています。

    たとえば、ボタンが3個あって、すべての Click イベントに同じメソッドを割り当てたとき、そのイベントの sender には、押されたボタンがはいっています。同様に、フォームの Closing や Closed といったイベントが発生するときは、sender は閉じようとしているフォームや閉じられたフォームが入っています。

    // ---- Form1.cs ----
    
    private void Form1_Button1Click(object sender, EventArgs e)
    {
     // Form2 を作成
     var form2 = new Form2();
    
     // Form2 が閉じた時、自分の Form2_FormClosed を呼ぶ
     form2.FormClosed += this.Form2_FormClosed;
    
     // Form2 を表示
     form2.Show();
    }
    
    private void Form2_FormClosed(object sender, EventArgs e)
    {
     // sender の型を Form2 に
     var form2 = sender as Form2;
    
     // argument プロパティを使用してメソッドを呼び出す
     this.method(form2.argument);
    }
    
    // ---- Form2.cs ----
    
    // Form2 以外に argument を公開するプロパティ
    public int argument { get; private set; }
    
    private void Form2_Closing(object sender, FormClsingEventArgs e)
    {
     // 閉じる前に argument を設定しておく
     // このイベントに限らず、閉じる前ならいつでもよい
     this.argument = 1;
    }
    
    
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月10日 3:50
  • ・Properties.Settings.Default.mailaddress.ToString();と書かなくてすむ?

    申し訳ないですが、「書かなくて済む?」という質問は、何を聞きたいのかがよくわかりません。
    Properties.Setting は Settings クラスの名前、Settings クラスの Default プロパティは Settings クラスのインスタンスを指し示すプロパティ、mailaddress は Settings クラスにあるプロパティ、ToString メソッドはあらゆる型から文字通り String にするためのメソッドです。
    このように分解して考えたときに残る疑問は何でしょうか。

    ・プロパティを設定画面でGUIで設定しなくてよい?

    自分でコードとして書いたわけですから、GUI には依存しません。
    しかし、GUI が面倒といっておられるようですが、後述するように Settings クラスの保存・読み込み機能を捨てる方が面倒だと思いますよ。

    ・okButtonでの保存は自動なの?

    自分で作り出したクラスなのですから、ファイルやレジストリへの保存の仕組みも自分で作らないといけません。
    保存先をレジストリにする、XML にするのも自分で決められますし、逆に言うと自分でそういった保存処理、読み込み処理を実装しなければなりません。(RegistryKey クラスとか、XmlWriter クラスとかそういったものを使うことになる)

    ・なぜclassをわける必要がある? 複数のFormなどから呼び出すため? もし呼び出さないとしたら、わけなくてもよい?

    データを共有するデータクラスとして書いています。
    分けなければならないかどうかは要件・設計などによりますので、一律には言えません。
    ただ、Form2 から Form1 のプロパティや変数を見るということは避けるべきです。
    (書いといて難ですが、データを持つだけのクラスはあまり良くない設計と言われています)


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけ
    • 回答としてマーク d-kot 2011年3月20日 11:13
    2011年3月20日 9:32
    モデレータ

すべての返信

  • public partial class Form1 : Form
    {
     public Form1()
     {
      InitializeComponent();
     }
     private void button1_Click(object sender, EventArgs e)
     {
      Form2 frm = new Form2();
      frm.Show(this);
     }
     public void HogeMethod(string arg)
     {
      MessageBox.Show(arg);
     }
    }
    public partial class Form2 : Form
    {
     public Form2()
     {
      InitializeComponent();
     }
     private void Form2_FormClosing(object sender, FormClosingEventArgs e)
     {
      ((Form1)this.Owner).HogeMethod("ほげほげ");
     }
    }
    
    

    おそらくは、こういうことでしょうか?

     

    追記:

    上記の例の場合、Form2は、必ずForm1の子である必要があり、汎用的ではない事に

    ご注意ください。汎用的なForm2にする場合は、Ownerの有無チェックや、存在する場合は

    Form1かどうかなどをチェックし、Form1であれば実行する、といった条件を入れるとよい

    かと思います。

    • 編集済み honefai 2011年3月8日 6:48 追記
    2011年3月8日 6:40
  • form2からForm1に、値をもどす方法を知りたいです。
    こういうときには、なにを使うのでしょう?

    ここだけみれば、form2.ShowDialog()で実現できそうです。ShowDialog()で開いたform2は閉じられても表示が消えるだけでform2のインスタンスは残っていますから、form2のpublicなプロパティで値を公開しておけば、それをform1から読み取ることが可能です。form1でform2.ShowDialog()でform2を開いた場合、form2を閉じるとform2.ShowDialog()の次の行から実行が再開されますから、そこで読み取れば良いです。
    なお、先に書きました通り、form2のインスタンスが残ったままになりますから、それが必要なくなったら必ずform2.Dispose()でform2のインスタンスを消して下さい。または、
    using (var from2 = new Form2())
    {
        form2.ShowDialog();
      メソッド(form2.publicなプロパティ);    //form1のメソッドの実行。引数はform2のpublicなプロパティから取得
           ・
           ・
           ・
    }
    とすれば、usingステートメントを抜ければ自動的にform2がDisposeされます。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月8日 13:40
    モデレータ
  • 依存関係を考えると、親(利用側)となるクラスのメソッドを具体的に呼ぶことは避けるべきです。
    (実装でチェックする・しないではなく、設計として避けるべき)

    この場合、イベントを外部に公開する、渡したい値をプロパティで公開するといった形をおすすめします。
    以下は、Form2 に Test プロパティを追加し、Form1 に渡したい値が入っていると言うことを想定したものです。

    private int _test;
    private Form2 _form2;
    private void Button1_Click(object sender, EventArgs e)
    {
     if (_form2 != null) return;
     _form2 = new Form2();
     form2.FormClosing += form2_FormClosing;
     form2.Show();
    }
    
    private void form2_FormClosing(object sender, FormClosingEventArgs e)
    {
     _test = _form2.Test;
     _form2 = null;
    }
    
    
    

    ところで、new Form と書かれていましたが、new Form2 で良いのですよね?

    # trapemiya さんが投稿されているように、ShowDialog で済むならそれが楽で良いと思います。
    # プロパティが必要なる点は変わりません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月8日 14:00
    モデレータ
  • honefaiさん
    ありがとうございます。まさにこれです。
    これから試してみます。

    trapemiyaさん、ありがとうございます。
    プロパティはすこし使っているのですが、設定がめんどうな気がしていて、それで聞いてみました。質問のときには、あまりにめんどうなので忘れていたのですが…。
    ひょっとしてプロパティって、わたしは、
    (1)プロジェクトのプロパティ-設定で表で名前と型と値の項目を設定する。
    たとえばIDとPWを保存するならその名前を設定し、型をstringとかにして、デフォルト値を入れる。

    (2)読み込むときにはFormで読み込む。
    string ID = Properties.Settings.Default.ID.ToString();
    string PW = Properties.Settings.Default.PW.ToString();

    (3)終了時や値の変更時には書き戻す。
    private void application_FormClosing(object sender, FormClosingEventArgs e){
    Properties.Settings.Default.ID = this.ID;
    Properties.Settings.Default.PW = this.PW;
    Properties.Settings.Default.Save();
    }
    としているのですが、これってもっとかんたんにならないでしょうか?
    かんたんというのは、つまり、IDとPWの値を変更したら、自動的に保存されるとか、値の設定の手間がGUIでなくてもうすこし楽にならないかとかってことです。作業の手間が多くて使いにくいと感じていて、プロパティを使ったことがほとんどないというか、できれば使いたくない、というのが最初の質問の自分でも気づかなかった意図でした。
    それで、honefaiさんがお応えくださったような単に値のやりとりをしたいと考えたわけです。

    Azuleanさん、ありがとうございます。
    依存関係で親のメソッドを避けるべき、というのは言葉としてはわからないではないですが、以上の理由(つまりプロパティの設定がめんどう)から、単に値のやりとりですむのなら、親のメソッドを呼ぶほうがすんなりくる、と考えています。
    というか、クラスやFormの分け方をよく理解していないのです。おかげでわけたことがなく、メインのFormは1万行…。

    ShowDialogではすみそうにないと思いますが、それも検討します。

    2011年3月9日 0:32
  • >実装でチェックする・しないではなく、設計として避けるべき

     

    同意ですね~、返信するときに思ってはいたんですが・・・、やはり指摘が来ましたか(汗

    私も、親子関係になるようなフォームであっても、子の拡張性・多様性を損なわないために親に依存した

    実装はせず、極力独立性の高い(親が別のフォームでも、親がなくとも)ものであるべきと考えます。

     

    Azuleanさんの方法は確かに独立性は高くなりますが、Form2のイベントをForm2では定義しないことに

    なるため、コードの可読性が低下するかな~と、考え方の違いはありますが、個人的に思いました。

    ほかの方法として、Form2のClosingイベントでOwnerに対してWindowsメッセージを送り、

    親フォームでメッセージを受け取って処理するという手もあるかな~と思います。

    2011年3月9日 1:30
  • 共通のメソッドは別クラスを作成して、そこでpublicにて公開したらいいと思いますよ。

    Utilityクラスとか名づけて、

    Utility util = new Utility();

    util.作成した共通メソッド();

    とかで呼び出しましょう。

    多分、これが一番単純です。

    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月9日 1:47
  • プロパティはすこし使っているのですが、設定がめんどうな気がしていて、それで聞いてみました。質問のときには、あまりにめんどうなので忘れていたのですが…。


    それはプロジェクトのプロパティから開いた画面の設定タブで設定する値のことであり、私が言っているプロパティはC#の言語の仕組みとして持っているプロパティのことです。例えば、以下などを一度読んでみて下さい。

    プロパティ
    http://ufcpp.net/study/csharp/oo_property.html

    form2に例えば科目コードというプロパティを設定することにより、以下のように記述できるようになります。

    form1のメソッド(form2.科目コード);    //form1のメソッドの実行。引数はform2のpublicなプロパティから取得


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月9日 1:56
    モデレータ
  • class Form2

    {

        Form1 form1;

         public Form2(Form form1)

       {

         this.form1=form1;

      }

    }

    form1をform2のconstructor参数をとして こうすると public methodを開ける。



    山西.net俱乐部
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月9日 5:11
  • Azuleanさんの方法は確かに独立性は高くなりますが、Form2のイベントをForm2では定義しないことに
    なるため、コードの可読性が低下するかな~と、考え方の違いはありますが、個人的に思いました。

    この論法だと、Button クラスの Click イベントが Button クラスの外側で利用されると、可読性が下がるってことになっちゃいますよ!

    すでに公開されているイベントが利用されることで、そのクラスの実装に問題が出るのは、そのクラスの設計・実装としてよくありません。
    そういったイベントが存在している状況で影響の排除を徹底するのであれば、new キーワードをつけて利用できないイベントにしてしまうというところでしょうか。
    最も、そこまで徹底すべき状況が多いとは思えませんが…。

    ほかの方法として、Form2のClosingイベントでOwnerに対してWindowsメッセージを送り、
    親フォームでメッセージを受け取って処理するという手もあるかな~と思います。

    自分で独自にイベント用意すれば良いと思いますよ。
    (ウィンドウメッセージに頼るやり方は、.NET 以前やネイティブコードではよくやりますが、その前にイベントがありますので)

    public event EventHandler Form2Closing;
    protected override OnFormClosing(FormClosingEventArgs e)
    {
     base.OnFormClosing(e);
     if (!e.Cancel)
     {
     if (Form2Closing != null) Form2Closing(this, EventArgs.Empty);
     }
    }
    
    

    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年3月9日 13:39
    モデレータ
  • 既に色々な人が書かれていますが、arguments をプロパティとして公開して、イベントを使うのが作り方としては手軽かな、と思います。最初の投稿に書かれている部分でいえば、form2 は新規に new するのではなく、sender を使用します。sender はそのイベントを発生させたものが入っています。

    たとえば、ボタンが3個あって、すべての Click イベントに同じメソッドを割り当てたとき、そのイベントの sender には、押されたボタンがはいっています。同様に、フォームの Closing や Closed といったイベントが発生するときは、sender は閉じようとしているフォームや閉じられたフォームが入っています。

    // ---- Form1.cs ----
    
    private void Form1_Button1Click(object sender, EventArgs e)
    {
     // Form2 を作成
     var form2 = new Form2();
    
     // Form2 が閉じた時、自分の Form2_FormClosed を呼ぶ
     form2.FormClosed += this.Form2_FormClosed;
    
     // Form2 を表示
     form2.Show();
    }
    
    private void Form2_FormClosed(object sender, EventArgs e)
    {
     // sender の型を Form2 に
     var form2 = sender as Form2;
    
     // argument プロパティを使用してメソッドを呼び出す
     this.method(form2.argument);
    }
    
    // ---- Form2.cs ----
    
    // Form2 以外に argument を公開するプロパティ
    public int argument { get; private set; }
    
    private void Form2_Closing(object sender, FormClsingEventArgs e)
    {
     // 閉じる前に argument を設定しておく
     // このイベントに限らず、閉じる前ならいつでもよい
     this.argument = 1;
    }
    
    
    • 回答としてマーク 山本春海 2011年3月22日 5:37
    2011年3月10日 3:50
  • みなさまありがとうございます。
    プロパティについて勉強してみているのですが、プロパティの書き方は、メソッドの書き方に較べて独特で、メソッドの特別なものという説明も読みましたし、見ていると、簡単そうに見えるのですが、簡単すぎて何がどう省略されているか理解できず、まだすんなりふに落ちていません。
    手がかりがなくて、なにを質問したらよいのか混乱していて、たぶん、プロパティについて質問すればよいのですが、それをどう整理するか、もうすこし時間が必要です。
    たぶん直感的には、get; set;だけで取得と設定はできるとして、設定をしたらすぐに反映されるのか、プログラム中の任意の位置で再設定するにはどうしたらよいか、設定した値は保存されるのか、というあたりが疑問点です。整理してまたご相談します。
    2011年3月19日 4:09
  • たぶん直感的には、get; set;だけで取得と設定はできるとして、設定をしたらすぐに反映されるのか、プログラム中の任意の位置で再設定するにはどうしたらよいか、設定した値は保存されるのか、というあたりが疑問点です。

    自動実装プロパティという仕組みあたりでこんがらかっているのかな?
    C# の言語仕様にも言及されていますが、以下の 2 つのクラス Point1 と Point2 は、同じ意味を持ちます。
    (単純に代入、取得、記憶しておくだけのコードであれば、あえて自分で変数を書かなくても、コンパイラが勝手に生成してくれる便利機能です)

    public class Point1 {
      public int X { get; set; }
      public int Y { get; set; }
    }
    
    public class Point2 {
      private int x;
      private int y;
      public int X { get { return x; } set { x = value; } }
      public int Y { get { return y; } set { y = value; } }
    }
    
    
    (念のため)プロパティの基本的な動き
    この Point2 クラスでは p.X = 1; とやると X の set アクセサの x = value; が、
    int b = p.Y; とやると、Y の get アクセサの return y; が実行されます。
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年3月19日 6:02
    モデレータ
  • Azuleanさん、ありがとうございます。
    え~とですね。たとえば、いちばんひんぱんに保存しておきたいのは、メールアドレスとパスワードだったりします。
    で、それはテキストボックスに入力して保存します。

    namespace MailSender
    {
     public partial class config : Form
     {
      public config()
      {
       InitializeComponent();
       this.mailAddress.Text = Properties.Settings.Default.mailaddress.ToString();
       this.mailPassword.Text = Properties.Settings.Default.mailpassword.ToString();
      }

      private void okButton_Click(object sender, EventArgs e)
      {
       Properties.Settings.Default.mailaddress = this.mailAddress.Text;
       Properties.Settings.Default.mailpassword = this.mailPassword.Text;
       Properties.Settings.Default.Save();
      }
     }
    }

    というようなコードを書いています。
    これだと、手順として、
    ・プロパティにmailaddressとmailpasswordの項目をstringとして用意する。
    ・テキスト枠をふたつ用意し、mailaddressとmailpasswordとする。
    ・このように起動時に値をプロパティから読み込んでいる。
    ・(OK)ボタンを押したら、データを保存している。
    のように使用しています。

    これならFormが増える度に、
    Properties.Settings.Default.mailaddress.ToString();
    Properties.Settings.Default.mailpassword.ToString();
    のふたつの値を読めば、Form間でデータを共有できます。

    この手純はただ値を共有するためだけに使うには、設定項目が多すぎて、めんどうだな~、と感じています。特にGUIの設定や、設定した項目の入力や、保存のタイミングなどを考えるのがめんどうくさくて、つい、
    this.mailaddress.Text = "mailaddress@mail.com";
    this.mailpassword.Text = "password";
    みたいに書いてしまいがちです。自分用のプログラムだと、とくにその傾向が強いです。
    それで最初の質問のように、かんたんにForm間で値を共有する方法をお尋ねしました。

    この設定を(自動実装?)プロパティを使うと楽にできるのでしょうか?
    というのが疑問点です。
    これを、下記のように書くことができるってことでしょうか?

    namespace MailSender
    {
     public partial class config : Form
     {
      public string mailaddress { get; set; }
      public string mailpassword { get; set; }
      public config()
      {
       InitializeComponent();
       this.mailAddress.Text = mailaddress;//これだけでOK?
       this.mailPassword.Text = mailpassword;//これだけでOK?
      }

      private void okButton_Click(object sender, EventArgs e)
      {
       //ここでmailaddress/mailpasswordの値を保存するには、どのようなコードを書けばよいでしょう?
      }
     }
    }
    それとも、このプロパティ(get/setするもの)と、あのプロパティ(プロパティ画面で設定するもの)は、そもそもぜんぜん違うものなのでしょうか?

    2011年3月19日 7:42
  • public partial class config : Form
    {
    public string mailaddress { get; set; }
    public string mailpassword { get; set; }
    public config()
    {
    InitializeComponent();
    this.mailAddress.Text = mailaddress;//これだけでOK?
    this.mailPassword.Text = mailpassword;//これだけでOK?
    }

    このコードではだめです。
    mailaddress も mailpassword もインスタンスが持つプロパティ(変数みたいなもの)なので、コンストラクタの時点では空であることが明白です。
    従って、それを参照してもダメです。

    やり方としては、設定データを持ったクラスを別途用意し、それを config という名前のフォームクラスに渡してやることでしょうか。
    Settings.Default にコードが近くなりますが、どこからでも参照できる static 変数にしていないので、コンストラクタでそのインスタンスを渡していることになります。
    興味があれば、Settings のソースを読んでみると良いでしょう。(プロジェクト内に存在するはずです)

    public class MailConfig
    {
     public string mailaddress { get; set; }
     public string mailpassword { get; set; }
    }
    
    public partial class ConfigForm : Form
    {
     private MailConfig _configStore;
     public ConfigForm(MailConfig configStore)
     {
      InitializeComponent();
      mailAddress.Text = configStore.mailaddress;
      mailPassword.Text = configStore.mailpassword;
      _configStore = configStore;
     }
    
     private void okButton_Click(object sender, EventArgs e)
     {
      _configStore.mailaddress = mailAddress.Text;
      _configStore.mailpassword = mailPassword.Text;
      Close();
     }
    }
    
    
    private MailConfig _mailConfig = new MailConfig();
    public void ShowConfigForm()
    {
     using (ConfigForm configForm = new ConfigForm(_mailConfig))
     {
      configForm.ShowDialog();
     }
    }
    
    

    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年3月19日 11:17
    モデレータ
  • Azuleanさん、ありがとうございます。
    Setting.csを見てみました。

    あといただいたソースだと、
    Properties.Settings.Default.mailaddress.ToString();
    というように書かなくてすむ? のと、プロパティを設定画面でGUIで設定しなくてよい? ので、楽そうな気がします。
    GUIの設定はともかくめんどうなので。

    このソースの場合、okButton_Clickで、値を保存していないように見えるのですが、それは自動的に行われるのですか?


    public class MailConfig {
     public string mailaddress { get; set; }
     public string mailpassword { get; set; }
    }

    public partial class ConfigForm : Form {
     private MailConfig mailconfigsetting;
     public ConfigForm(MailConfig mailConfig)  {
      InitializeComponent();
      mailAddress.Text = mailConfig.mailaddress;
      mailPassword.Text = mailConfig.mailpassword;
      mailconfigsetting = mailConfig;
     }

     private void okButton_Click(object sender, EventArgs e) {
      mailconfigsetting.mailaddress = mailAddress.Text;
      mailconfigsetting.mailpassword = mailPassword.Text;
      Close();
     }
    }

    private MailConfig mailconfig = new MailConfig();
    public void ShowConfigForm(){
     using (ConfigForm configForm = new ConfigForm(mailconfig)){
      configForm.ShowDialog();
     }
    }

    あと、_は見えにくいので、上のようにしてみました。
    疑問点は次のとおりです。
    ・Properties.Settings.Default.mailaddress.ToString();と書かなくてすむ?
    ・プロパティを設定画面でGUIで設定しなくてよい?
    ・なぜclassをわける必要がある? 複数のFormなどから呼び出すため? もし呼び出さないとしたら、わけなくてもよい?
    ・okButtonでの保存は自動なの?
    疑問点ばかりで恐縮です。

    2011年3月20日 0:35
  • ・Properties.Settings.Default.mailaddress.ToString();と書かなくてすむ?

    申し訳ないですが、「書かなくて済む?」という質問は、何を聞きたいのかがよくわかりません。
    Properties.Setting は Settings クラスの名前、Settings クラスの Default プロパティは Settings クラスのインスタンスを指し示すプロパティ、mailaddress は Settings クラスにあるプロパティ、ToString メソッドはあらゆる型から文字通り String にするためのメソッドです。
    このように分解して考えたときに残る疑問は何でしょうか。

    ・プロパティを設定画面でGUIで設定しなくてよい?

    自分でコードとして書いたわけですから、GUI には依存しません。
    しかし、GUI が面倒といっておられるようですが、後述するように Settings クラスの保存・読み込み機能を捨てる方が面倒だと思いますよ。

    ・okButtonでの保存は自動なの?

    自分で作り出したクラスなのですから、ファイルやレジストリへの保存の仕組みも自分で作らないといけません。
    保存先をレジストリにする、XML にするのも自分で決められますし、逆に言うと自分でそういった保存処理、読み込み処理を実装しなければなりません。(RegistryKey クラスとか、XmlWriter クラスとかそういったものを使うことになる)

    ・なぜclassをわける必要がある? 複数のFormなどから呼び出すため? もし呼び出さないとしたら、わけなくてもよい?

    データを共有するデータクラスとして書いています。
    分けなければならないかどうかは要件・設計などによりますので、一律には言えません。
    ただ、Form2 から Form1 のプロパティや変数を見るということは避けるべきです。
    (書いといて難ですが、データを持つだけのクラスはあまり良くない設計と言われています)


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけ
    • 回答としてマーク d-kot 2011年3月20日 11:13
    2011年3月20日 9:32
    モデレータ
  • Azuleanさん、ありがとうございます。
    ・Properties.Settings.Default.mailaddress.ToString();と書かなくてすむ?

    え~と、最初のソースはたしか
    mailAddress.Text = Properties.Settings.Default.mailaddress.ToString();
    だったのに対して、
    mailAddress.Text = mailConfig.mailaddress;
    と書けるのなら、
    Properties.Settings.Default
    .ToString()
    の部分を省略できると考えました。

    ただ、後半のいろいろを拝読すると、classをわけたうえに、保存も自前で書く必要があるとなると、ということは読み込みも自前で書く必要があるわけで、そのくらいなら、プロパティを設定画面でGUIで設定するほうがまだ楽な気もしますし、それもめんどうなら(めんどうなのですが)、やはり最初の疑問のように、Form間でメソッドを呼び出すのが、いちばん手軽にわたしには思えます。
    プロパティにしろなんか別のものにしろ、値を変更する度に保存が必要ということは、ディスクアクセスが増えて速度が低下しますし。Form間でちょっとした値をやりとりするのに、ディスクアクセスしてどうするという気持ちもあります。
    それがオブジェクト思考的にどうかとか、設計がどうかといわれても、そもそもこのプログラム自分でしか使っていないし、だから設計がなくてもいいとはいわないのですが、わざわざめんどうなことを導入するのには、いまいち説得されてない感じです。
    するっと説得してくださると、おおおと思える気もします。

    2011年3月20日 11:13
  • mailAddress.Text = Properties.Settings.Default.mailaddress.ToString();
    だったのに対して、
    mailAddress.Text = mailConfig.mailaddress;
    と書けるのなら、
    Properties.Settings.Default
    .ToString()
    の部分を省略できると考えました。

    mailaddress が string 型であるならば、ToString メソッドを呼ぶ出す必要はありません。(意味がないため)
    ただし、Properties.Setting.Default.mailaddress までは書かないとダメでしょう。どこの mailaddress か特定できませんので。
    先の投稿中にも書きましたが、Properties は名前空間、Setting はクラス名、Default はプロパティ名と意識して、もう一度ソースコードを読み直してください。

    やはり最初の疑問のように、Form間でメソッドを呼び出すのが、いちばん手軽にわたしには思えます。
    その場では楽に見えるかもしれませんが、再利用性は失われますし、良い設計とは言えません。
    影響を受けるのが自分だけ、つまり個人の趣味の範囲であるならば、こだわらなくても困らないかもしれませんね。
    プロパティにしろなんか別のものにしろ、値を変更する度に保存が必要ということは、ディスクアクセスが増えて速度が低下しますし。Form間でちょっとした値をやりとりするのに、ディスクアクセスしてどうするという気持ちもあります。

    Settings.Save は毎回呼ばないとダメということはありませんよ?
    アプリケーション終了時に一度呼べば十分です。

    それがオブジェクト思考的にどうかとか、設計がどうかといわれても、そもそもこのプログラム自分でしか使っていないし、だから設計がなくてもいいとはいわないのですが、わざわざめんどうなことを導入するのには、いまいち説得されてない感じです。
    するっと説得してくださると、おおおと思える気もします。

    興味があれば、「リファクタリング―プログラムの体質改善テクニック」などの書籍をお読みください。
    この場で説明するのは大変ですし、今の段階で必須とは言えないので、私の拙い説明は差し控えておきます。(申し訳ありませんが)


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年3月20日 13:58
    モデレータ
  • やはり最初の疑問のように、Form間でメソッドを呼び出すのが、いちばん手軽にわたしには思えます。
    その場では楽に見えるかもしれませんが、再利用性は失われますし、良い設計とは言えません。
    影響を受けるのが自分だけ、つまり個人の趣味の範囲であるならば、こだわらなくても困らないかもしれませんね。

     個人の趣味の範囲でなくても、今回のプロジェクトの経験を次回のプロジェクトに活かすような風土が企業/部門になければ、static public で宣言する方が手軽でしょう。単に「再利用性が失われる」だけでなく、どのように再利用できるか/するのか。そういうところこそ、伝えるためには重要だと思います。


    わざわざめんどうなことを導入するのには、いまいち説得されてない感じです。

     明日の楽のために、今日苦労する。それがシステム エンジニアという職業だと思います。趣味でしかされていない/する予定がないのでしたら、好きにしてください。ただし、趣味でも、継続的に行うつもりがあるのなら、今苦労しておくことを勧めます。


    Jitta@わんくま同盟
    2011年3月21日 5:15
  • Azuleanさんありがとうございます。
    リファクタリングは探してみます。
    ちなみに、いま読んでいるのは、『C#ショートコードプログラミング』と、『Effective C#4.0』、『More Effective C#4.0』です。わからないところも多いですが、参考になる部分もあります。

    Jittaさん、ありがとうございます。
    わたしはいますぐ楽するためになら、苦労はいとわないと自分では考えています。システムエンジニアではないので、苦労のための苦労(あしたの楽は遠すぎる)と思います。だってコードを自動生成するだけなら、コードの補完みたいに、もっと開発環境が救けてくれてもいい気がするのです。
    好きにします。もっと楽できる方法を見つけたいと思います。

    2011年3月26日 14:32