HeyCHのブログ

慢性疲労のへいちゃんです

【C#】進捗状況ダイアログを表示しよう その2

heych.hatenablog.com
前回のはちょっと例が悪かったため、改めて進捗状況を表示するダイアログを作ってみたいと思います。

時間のかかる処理を作成する

  • 新しいプロジェクトの作成
    f:id:HeyCH:20200406233659p:plain
    新しいプロジェクトの作成
  • Windows フォームアプリケーション(.NET Framework)を選択
    f:id:HeyCH:20200406233757p:plain
    Windows フォームアプリケーション(.NET Framework
  • 作成
    f:id:HeyCH:20200406233859p:plain
    作成
  • TextBoxとButtonを配置し、ButtonのTextを「処理開始」に書き換える
    f:id:HeyCH:20200406234248p:plain
    Form1
  • Buttonをダブルクリックし、コードを記述
        BackgroundWorker bw = new BackgroundWorker();
        public Form1() {
            InitializeComponent();
            bw.WorkerSupportsCancellation = true;
            bw.WorkerReportsProgress = true;
            bw.DoWork += Bw_DoWork;
            bw.ProgressChanged += Bw_ProgressChanged;
            bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
        }

        private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
            if (e.Cancelled) {
                MessageBox.Show("キャンセルしました。");
            } else {
                MessageBox.Show("処理が完了しました。");
            }
        }

        private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e) {
            //今は何もしない
        }

        private void Bw_DoWork(object sender, DoWorkEventArgs e) {
            var sum = 0;
            for (int i = 0; i <= 100; i++) {
                sum += i;
                if (bw.CancellationPending) {
                    e.Cancel = true;
                    break;
                }
                System.Threading.Thread.Sleep(100);
                bw.ReportProgress(i);
                this.Invoke((MethodInvoker)delegate () { textBox1.Text = sum.ToString(); });
            }
        }

        private void button1_Click(object sender, EventArgs e) {
            bw.RunWorkerAsync();
        }

しれっと使ってますが、MessageBoxというのは様々なメッセージダイアログを表示するクラスです。

プログレスバーダイアログを作成する

  • フォームを追加
    f:id:HeyCH:20200407001212p:plain
    フォームを追加
  • 追加
    f:id:HeyCH:20200407001327p:plain
    追加
  • LabelとProgreassBarとButtonを追加してButtonのTextを「キャンセル」に設定
    f:id:HeyCH:20200407001802p:plain
    Form2
  • Form2のプロパティ「ControlBox」を「False」に「StartPosition」を「CenterParent」に「FormBorderStyle」を「FixedDialog」に設定する
    f:id:HeyCH:20200407002339p:plain
    Form2のプロパティ
  • Buttonをダブルクリックしてコードを書く
        public string Title {
            get { return this.Text; }
            set {
                if (InvokeRequired) {
                    this.Invoke((MethodInvoker)delegate () { this.Text = value; });
                } else {
                    this.Text = value;
                }
            }
        }
        public string Message {
            get { return label1.Text; }
            set {
                if (InvokeRequired) {
                    this.Invoke((MethodInvoker)delegate () { label1.Text = value; });
                } else {
                    label1.Text = value;
                }
            }
        }
        public int Value {
            get { return progressBar1.Value; }
            set {
                if (InvokeRequired) {
                    this.Invoke((MethodInvoker)delegate () { progressBar1.Value = value; });
                } else {
                    progressBar1.Value = value;
                }
            }
        }
        public BackgroundWorker Worker {
            get;
            set;
        }
        public Form2() {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e) {
            Worker.CancelAsync();
        }

InvokeRequiredはそのままで、Invokeが必要な場合Trueになります。

再びForm1のコードを書く

        BackgroundWorker bw = new BackgroundWorker();
        Form2 progressBarDialog;
        public Form1() {
            InitializeComponent();
            bw.WorkerSupportsCancellation = true;
            bw.WorkerReportsProgress = true;
            bw.DoWork += Bw_DoWork;
            bw.ProgressChanged += Bw_ProgressChanged;
            bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
        }

        private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
            progressBarDialog.Close();
            if (e.Cancelled) {
                MessageBox.Show("キャンセルしました。");
            } else {
                MessageBox.Show("処理が完了しました。");
            }
        }

        private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e) {
            progressBarDialog.Value = e.ProgressPercentage;
            progressBarDialog.Message = e.ProgressPercentage + "% 完了しました。";
        }

        private void Bw_DoWork(object sender, DoWorkEventArgs e) {
            var sum = 0;
            for (int i = 0; i <= 100; i++) {
                sum += i;
                if (bw.CancellationPending) {
                    e.Cancel = true;
                    break;
                }
                System.Threading.Thread.Sleep(100);
                bw.ReportProgress(i);
                this.Invoke((MethodInvoker)delegate () { textBox1.Text = sum.ToString(); });
            }
        }

        private void button1_Click(object sender, EventArgs e) {
            progressBarDialog = new Form2();
            progressBarDialog.Worker = bw;
            progressBarDialog.Title = "処理中";
            progressBarDialog.Message = "処理を開始しました。";
            progressBarDialog.Value = 0;
            progressBarDialog.Show();
            bw.RunWorkerAsync();
        }

このようにすることで、進捗状況の表示や処理のキャンセルを行う事ができます。