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

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

ただいまの
回答率

88.80%

[C#][Windows Forms]コンボボックスの変更後の無駄なデータ取得をまとめたい

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 666

S.Oda

score 13

前提・実現したいこと

初めて質問させていただきます。
質問に関して不備等ありましたら、申し訳ありません。

[環境: Windows10, Visual Studio 2017, .net framework 4.7.2]

現在、Windows Formでアプリケーションを作成しているのですが、
以下の処理は通常、どのように実装するべきなのか教えていただきたいです。

画面上、
学年の開始を指定するコンボボックス(cmbGradeFrom)
学年の終了を指定するコンボボックス(cmbGradeTo)、
クラスの開始を指定するコンボボックス(cmbClassFrom)
クラスの終了を指定するコンボボックス(cmbClassTo)
があります。

それぞれのコンボボックスは、選択した内容が変更されたタイミングで
イベントが[該当のソースコード]のように発生するようになっており、
setEachFeeList()内では、学年の開始-終了、クラスの開始-終了で絞り込みを行い
データ取得をして、データグリッドに対象データを表示しています。

それぞれのコンボボックスが変更したら、データ取得処理に入るようになっているのですが、
一つのコンボボックスの選択変更がほかのコンボボックスの変更に影響を与えているため、
一つのコンボボックスを変更しただけでも複数のイベントが発生してしまい、
複数回データ取得処理を行ってしまいます。

一つのコンボボックスを変更したら、ほかのコンボボックスの値変更をすべて終わったあとに
データ取得を1度だけ実行するような作りにしたいのですが、それは可能でしょうか。
以上、よろしくお願いいたします。

該当のソースコード

        /// 学年FROMが変更されたときの処理
        protected void cmbGradeFrom_TextChanged(object sender, EventArgs e)
        {
            if (cmbGradeFrom.Items.Count == 0 || cmbGradeTo.Items.Count == 0) return;

            //学年の開始が終了より大きい場合、終了と開始を一致させる
            if (cmbGradeFrom.SelectedIndex > cmbGradeTo.SelectedIndex) 
            {
                cmbGradeTo.SelectedIndex = cmbGradeFrom.SelectedIndex;
            }

            //学年の開始と終了が同じ場合、クラスの最小と最大をクラスの開始と終了に設定
            if (cmbGradeTo.SelectedIndex == cmbGradeFrom.SelectedIndex)
            {
                setClassFromTo();
            }
            else
            {
                setEachFeeList(); //画面表示データ取得&表示処理
            }
        }

        /// 学年TOが変更されたときの処理
        protected void cmbGradeTo_TextChanged(object sender, EventArgs e)
        {
            if (cmbGradeFrom.Items.Count == 0 || cmbGradeTo.Items.Count == 0) 
            return;

            //学年の開始が終了より大きい場合、開始を終了に一致させる
            if (cmbGradeFrom.SelectedIndex > cmbGradeTo.SelectedIndex)
            {
                cmbGradeFrom.SelectedIndex = cmbGradeTo.SelectedIndex;
            }

            //学年の開始と終了が同じ場合、クラスの最小と最大をクラスの開始と終了に設定
            if (cmbGradeFrom.SelectedIndex == cmbGradeTo.SelectedIndex)
                setClassFromTo(); 
            }
            else
            {
                setEachFeeList(); //画面表示データ取得&表示処理
            }
        }
        /// クラスFromが変更されたときの処理
        protected void cmbClassFrom_TextChanged(object sender, EventArgs e)
        {
            if (cmbClassFrom.Items.Count == 0 || cmbClassTo.Items.Count == 0) return;
            //クラスの開始が終了より大きい場合、終了を開始に一致させる
            if (cmbClassFrom.SelectedIndex > cmbClassTo.SelectedIndex) 
            {
                cmbClassTo.SelectedIndex = cmbClassFrom.SelectedIndex;
            }
            setEachFeeList();
        }
        /// クラスToが変更されたときの処理
        protected void cmbClassTo_TextChanged(object sender, EventArgs e)
        {
            if (cmbClassFrom.Items.Count == 0 || cmbClassTo.Items.Count == 0) return;
            //クラスの開始が終了より大きい場合、開始を終了に一致させる
            if (cmbClassFrom.SelectedIndex > cmbClassTo.SelectedIndex) 
            {
                cmbClassFrom.SelectedIndex = cmbClassTo.SelectedIndex;
            }
            setEachFeeList();
        }
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+1

TextChangedじゃなくてDropDownClosedを使うという手もありますが、
ドロップダウンを開いて閉じないとイベントが発生しない問題があります。
(キー操作で変更した場合に発生しない)

他にも、 Validatedイベントなんかも使えそうです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/22 19:54

    そうですね、確かに他のeventで試してませんでした。
    確認してみます。ありがとうございます。

    キャンセル

  • 2019/04/23 13:38

    結局DropDownClosedで実装することにしました。
    ご回答いただきありがとうございました。

    キャンセル

+1

データ取得処理

を行うべきか否かをフラグか何かで制御すればよいのではないでしょうか.
(各コンボボックスのイベントハンドラはフラグが立っていたら即returnする,的な)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/22 15:20

    そうですね、それは私も思いましたが、処理が煩雑になりそうでしたので、実装をためらっていました。
    他にいい方法がなければそうしようと思います。
    ありがとうございました。

    キャンセル

+1

イベントを一時的に外してしまうのはどうでしょうか?

        /// 学年FROMが変更されたときの処理
        protected void cmbGradeFrom_TextChanged(object sender, EventArgs e)
        {
            if (cmbGradeFrom.Items.Count == 0 || cmbGradeTo.Items.Count == 0) return;

            //学年の開始が終了より大きい場合、終了と開始を一致させる
            if (cmbGradeFrom.SelectedIndex > cmbGradeTo.SelectedIndex)
            {
                // イベントが呼ばれないように一時的に外す
                cmbGradeTo.TextChanged -= cmbGradeTo_TextChanged;

                cmbGradeTo.SelectedIndex = cmbGradeFrom.SelectedIndex;

                // イベントを元に戻す
                cmbGradeTo.TextChanged += cmbGradeTo_TextChanged;
            }

            //学年の開始と終了が同じ場合、クラスの最小と最大をクラスの開始と終了に設定
            if (cmbGradeTo.SelectedIndex == cmbGradeFrom.SelectedIndex)
            {
                setClassFromTo();
            }
            else
            {
                setEachFeeList(); //画面表示データ取得&表示処理
            }
        }

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/22 15:22

    イベントを一時的に外すほうが、おそらくフラグ管理よりはいいような気がします。(イベントを実行したくないという理由が一目でわかるため)
    ただ、これも処理が込み入りそうなので、ほかにいい方法はないかなーと考えていたところです。
    助言いただきありがとうございます。

    キャンセル

+1

各イベントハンドラでタイマー起動
タイマーでデータ取得処理を行いタイマー停止
というのはどうでしょう?

下記のような感じです。

        private void comboBox1_TextChanged(object sender, EventArgs e)
        {
            Console.WriteLine("comboBox1");
            comboBox2.Text += "1";
            timer1.Start();
        }

        private void comboBox2_TextChanged(object sender, EventArgs e)
        {
            Console.WriteLine("comboBox2");
            timer1.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Console.WriteLine("SetData");
            timer1.Stop();
        }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/22 16:08

    ちょっとイメージがわかないので調べてみます。
    ありがとうございました。

    キャンセル

  • 2019/04/22 19:55

    おー、わざわざサンプルコード記入していただきありがとうございます。
    確認します。

    キャンセル

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

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る