none
Windows Forms から様々な値を返す方法 RRS feed

  • 質問

  • 恐れ入ります。

    Windows Forms から値を返す方法は、
    http://social.msdn.microsoft.com/Forums/ja-JP/vsgeneralja/thread/04f72ef0-107c-4a72-9fa5-9ceb5da7207c
    で解決しました。

    そして、次の問題にぶつかりました。
    return で返す値は、int にしろstring にしろ、一つになるのですが、
    textBox.Text の値をstring型で返す他に、
    たとえば、int型の合計値を返したり、ListBoxのSelectionModeが、MultiSimpletだった場合のこの値も返すなど、いくつかの値を同時に返す場合には、どうしたらよいのでしょうか?

    質問の繰り返しで大変申し訳ありませんが、どうぞよろしくお願いいたします。
    2010年2月6日 10:24

回答

  • 入力の条件が整ったときに、DialogResult = DialogResult.OK とすることで、
    Form2 を閉じるのですが、DialogResult = DialogResult.OK の1行がないと、閉じません。
    これは、DialogResult がNone の間は、「返す値がないので閉じない」ということなのでしょうか?

    Form の実装が、Button_Click イベントを抜けたとき、DialogResult プロパティが None 以外に変わっていれば自動的に Close するようになっているからです。(大まかに言うとであって、正確な表現ではない)
    DialogResult プロパティに代入するのが嫌であれば、Close メソッドを呼べば良いでしょう。

    ところで、なぜ、OK や Cancel を返したくないのでしょうか。

    なお、現在は、以下のように、GetDialog という名前に変えました。

    GetDialog は Dialog を Get するという主旨が伺える名称ですので、Dialog を 表示する(Show する) ようなメソッドに見えません。
    命名される際には、そのメソッドの意味が分かるような名称をつけましょう。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    • 回答としてマーク yasheeki 2010年2月7日 9:59
    2010年2月7日 4:50
    モデレータ

すべての返信

  • MSDN のこのページは参考になりますか?
    http://msdn.microsoft.com/ja-jp/library/56taefba.aspx
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年2月6日 11:25
    モデレータ
  • 関連のライブラリをご紹介頂き有難うございます。

    ただ、どこにどのコードを差し込んだらよいのか分からず、困ってしまいました。
    どこが理解できないのかが自分で分からぬままなのです。

    レベルが低すぎて理解できず、ごめんなさい。
    でも、理解したいです。
    2010年2月6日 12:14
  • Windows Forms から値を返す方法は、
    http://social.msdn.microsoft.com/Forums/ja-JP/vsgeneralja/thread/04f72ef0-107c-4a72-9fa5-9ceb5da7207c
    で解決しました。

    そして、次の問題にぶつかりました。
    return で返す値は、int にしろstring にしろ、一つになるのですが、
    textBox.Text の値をstring型で返す他に、
    たとえば、int型の合計値を返したり、ListBoxのSelectionModeが、MultiSimpletだった場合のこの値も返すなど、いくつかの値を同時に返す場合には、どうしたらよいのでしょうか?

    前の質問でコードを提示したとおり、C# で単に値を返すだけなら、「プロパティ」 でデータを返却するのが常套手段かと思います。
    例えばこんな感じ・・・

    Form2 form = new Form2();
    if (form.ShowDialog() == DialogResult.OK) {

        string a = form.MyProperty1;   // TextBox の値を返す
        int b = form.MyProperty2;      // ListBox のSelectIndex を返す
        decimal c = form.MyProperty3;  // その他コントロールの値を返す
    }
    form.Dispose();

    「プロパティ」に関してはこちらの記事を参考にどうぞ。

    http://msdn.microsoft.com/ja-jp/library/w86s7x04(VS.80).aspx
    http://ufcpp.net/study/csharp/oo_property.html
    http://www.atmarkit.co.jp/fdotnet/csharp_abc2/csabc2_012/cs2_012_01.html


    もっともこの程度のことでつまづいているなら、この先の開発は厳しいでしょう。
    一度、以下の記事に目を通されることをお勧めします。

    連載 改訂版 C#入門




    2010年2月6日 12:31
    モデレータ
  • ShowDialogで開いたフォームは、閉じただけではそのインスタンスは残ったままになっています。そのため、必要なくなった時点で後始末としてDisposeを行なうのがベストです。よくusingを使用してShowDialogでフォームを開いているのを見かけますが、目的は同じです。
    一方、Showで開いたフォームは、閉じただけでそのインスタンスが破棄されます。

    以上のShowDialogとShowの違いは何を意味しているのでしょうか? ShowDialogで開いたフォーム(親)は、ShowDialogで開かれたフォーム(子)のインスタンスを利用できるのです。ということは、親が子のプロパティにアクセスできるということです。

    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2010年2月6日 16:02
    モデレータ
  • 有難うございます。

    やっと、プロパティを使って様々な値を得ることができました。

            private List<string> list;

            public List<string> SelectItem
            {
                get
                {
                    return list;
                }
            }
    というです。

    ただ、問題があります。

    この子フォームを呼び出すときに、
    親フォームでは
            if (form.ShowDialog() == DialogResult.OK)
            {
                    for (int i = 0; i < form.SelectItem.Count; i++)
                    {
                        MessageBox.Show(form.SelectItem[i].ToString());
            }

    Form2には
            public DialogResult ShowDialog()
            {
                // ここで、処理をさせています。
                ...................

                // ここで、Form2を表示
                base.ShowDialog();
                // このコードのせいか入力に不備があっても閉じてしまいます。
                return DialogResult;
            }

    という風なコードにしました。

    Form2 でOKボタンをクリックしたときに、一定の必須条件を満たさないと、エラーメッセージを表示させ、
    条件を満たすか、キャンセルボタンをクリックするまで、Form2 を閉じないようにしたいのですが、出来ません。
    上記の方法では何が悪いのか分かりません。

    Form2 のOKボタンのイベントは
            private void okButton_Click(object sender, EventArgs e)
            {
                list = new List<string>();
                if (findBox.Text == "")
                {
                    MessageBox.Show("入力の不備があります。", "エラー!", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
                }
            }
    です。

    どうぞ、よろしくお願いします。
    2010年2月6日 17:29
  • Form2 のOKボタンのイベントは
            private void okButton_Click(object sender, EventArgs e)
            {
                list = new List<string>();
                if (findBox.Text == "")
                {
                    MessageBox.Show("入力の不備があります。", "エラー!", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
                }
            }
    です。

    ここに Close は出てきていませんが、どうやって閉じているのでしょうか。
    okButton の DialogResult プロパティで None 以外を設定しているのであれば、それを None に戻してください。

    その上で、okButton イベントでメッセージを表示した後は return で抜ける、チェックがすべて OK なら Form の DialogResult プロパティに DialogResult.OK を代入すれば良いでしょう。

    イメージ:
    if (/* 条件 */)
    {
        MessageBox.Show("Error");
        return;
    }
    // チェックOK
    this.DialogResult = DialogResult.OK;


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年2月6日 18:04
    モデレータ
  • 既に同様に回答を頂いているようですが、せっかく作成しましたので投稿します。


    表示しているForm2を閉じるには、Closeメソッドを使用します。
    this.Close();

    従って、Closeメソッドを呼び出す前にチェックを実行し、
    チェックの結果がNGなのであれば、Windowを閉じないようするのであれば、
    エラーメッセージを表示後、Closeメソッドを呼び出さなければ画面は閉じられません。

    そうなると、OKボタン押下時かつ必須条件を満たす場合と、
    キャンセルボタン押下時にCloseメソッドが呼び出されることになるのですが、
    Form2を呼び出したForm1において、Form2がどちらの状態で画面を閉じたかを判定する必要があります。

    現在は、
    if (form.ShowDialog() == DialogResult.OK)
    というように、ShowDialogメソッドの戻り値であるDialogResultで結果を見ていますので、
    OKボタン押下字は、Closeメソッドを呼び出す前に、
    DialogResult = DialogResult.OK;
    を実装して、戻り値にDialogResult.OKを設定します。

    これにより、OKボタンを押下して画面を閉じた場合は、DialogResult.OKが返り、
    キャンセルボタン押下で画面を閉じた場合は、DialogResult.Cancelが返ります。

    補足ですが、×ボタンやAlt+F4で閉じた場合も画面が閉じられ、Form1にはDialogResult.Cancelが返ります。
    このあたりの動作は実際にデバッグしながら確認すればわかると思います。

     

    private void okButton_Click(object sender, EventArgs e)
    {
        list = new List<string>();
        if (findBox.Text == "")
        {
            MessageBox.Show("入力の不備があります。", "エラー!", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
        }
        else
        {
            // 画面が条件を満たして終了したことを設定
            DialogResult = DialogResult.OK;
            
            // 画面を閉じる
            this.Close();
        }
    }
    
    private void cancelButton_Click(object sender, EventArgs e)
    {
        // 画面を閉じる
        this.Close();
    }
    


    また、Form2には、WindowクラスのShowDialogメソッドと同じ名前、引数を持つShowDialogメソッドが実装されています。
    public DialogResult ShowDialog()

    このままでは、継承されたメンバを暗黙的に非表示にする旨の警告が表示されていると思います。
    意図的にWindowクラスのShowDialogメソッドを隠したいのであれば、newをつけて
    public new DialogResult ShowDialog()
    とした方が良いです。

    ただし、今回のケースでは隠す必要がありませんので、別名のメソッドを用意するかした方が良いと思います。
    (ShowDialogの引数はもう不要になったのですね?)

    2010年2月6日 18:42
  • 度重なる質問にお答えいただき、感謝しております。

    みなさんのご指摘通り、
    okButton の DialogResult プロパティで None 以外を設定している(OK にしていました)のが、
    勝手に閉じる原因でした。(この辺が分かりづらさを拡げてしまいました)

    ShowDialog でForm2に値を渡すために、引数の代わりに、プロパティを作りました。

    親フォームで、
                private int theCase;
                // 処理------------

                Form2 form = new Form2();
                form.TableCase = i;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    for (int i = 0; i < form.SelectItem.Count; i++)
                    {
                        MessageBox.Show(form.SelectItem[i].ToString());
                    }
                }

    子フォームで、
            public int TableCase
            {
                set
                {
                    tableCase = value;
                }
            }
    という風にしました。
    今回フォームにこんな風に値を渡すことができるとは、驚きでした。

    また、継承されたメンバを暗黙的に非表示にする旨の警告が表示されているはずとの指摘通り、
    緑色で、その表示が出ていました。

    なお、現在は、以下のように、GetDialog という名前に変えました。
            public DialogResult GetDialog()
            {
                string tableName;

                //ここに処理を記述

                base.ShowDialog();
                return DialogResult;
            }

    ここでまた、分からないことが増えてしまいました。
    入力の条件が整ったときに、DialogResult = DialogResult.OK とすることで、
    Form2 を閉じるのですが、DialogResult = DialogResult.OK の1行がないと、閉じません。
    これは、DialogResult がNone の間は、「返す値がないので閉じない」ということなのでしょうか?

    また、「継承されたメンバを暗黙的に非表示にする」とは、どういったことを説明しているのでしょうか?

    引き続く質問で申し訳ありません。
    よろしくお願いいたします。

    2010年2月7日 2:19
  • 「継承されたメンバを暗黙的に非表示にする」とは、どういったことを説明しているのでしょうか?
    最初に提示されたコードの場合、Form クラスのメンバである ShowDialog メソッドを上書きしていたからです。
    この場合、コンパイルエラーにはなりませんが、以下の警告が発生します。

    コンパイラの警告 (レベル 2) CS0108

    でも

    > 現在は、以下のように、GetDialog という名前に変えました。

    であるなら、ShowDialog の上書きにならず、また同一のメソッドが Form のメンバにないため大丈夫です。

    この辺のことを理解するには 「継承」 ということをしっかり学んだ方が良さそうですね。
    以下の記事は、初心者にもわかりやすそうだと思いますのでリンク貼っておきます (全部読んでないので悪しからず)

    オブジェクト指向とは
    継承
    多態性

     
    2010年2月7日 4:20
    モデレータ
  • 入力の条件が整ったときに、DialogResult = DialogResult.OK とすることで、
    Form2 を閉じるのですが、DialogResult = DialogResult.OK の1行がないと、閉じません。
    これは、DialogResult がNone の間は、「返す値がないので閉じない」ということなのでしょうか?

    Form の実装が、Button_Click イベントを抜けたとき、DialogResult プロパティが None 以外に変わっていれば自動的に Close するようになっているからです。(大まかに言うとであって、正確な表現ではない)
    DialogResult プロパティに代入するのが嫌であれば、Close メソッドを呼べば良いでしょう。

    ところで、なぜ、OK や Cancel を返したくないのでしょうか。

    なお、現在は、以下のように、GetDialog という名前に変えました。

    GetDialog は Dialog を Get するという主旨が伺える名称ですので、Dialog を 表示する(Show する) ようなメソッドに見えません。
    命名される際には、そのメソッドの意味が分かるような名称をつけましょう。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    • 回答としてマーク yasheeki 2010年2月7日 9:59
    2010年2月7日 4:50
    モデレータ
  • 有難うございます。

    継承も学んでみます。
    Derive from ってものだそうですが、まだ真剣に取り組んで学んだことがありませんでした。
    2010年2月7日 9:46
  • 有難うございます。

    DialogResult プロパティが None 以外に変わっていれば自動的に Close するようになっている
    ということで、勉強になりました。

    また、名前は DisplayDialog に変更しました。

    最後に、
    なぜ、OK や Cancel を返したくないのでしょうか
    との問いですが、当初ボタンのDialogResult を変更してこちょこちょやってまして、
    そんな中で混乱の度合いが深くなって、いつの間にやらこんなコードになっていたというお粗末な結果です。

    不勉強が災いして、どんどん難しくしてしまったようです。

    今回は、みなさんのご協力によってかなり勉強になりましたが、基礎知識が弱すぎるようです。
    しっかり勉強してみます。

    皆様、今後もよろしくお願いいたします。
    2010年2月7日 9:58