LoginSignup
25
20

More than 3 years have passed since last update.

[.NET5 / Windows Forms] 新機能(!?) System.Windows.Forms.TaskDialog に触れてみた

Last updated at Posted at 2021-05-07

前置き

今年リリースされた「.NET 5」。なんと Windows Forms に新しいコントロールが追加されていました。

本記事ではそのうちの1つ「System.Windows.Forms.TaskDialog」をご紹介したいと思います。

タスクダイアログ(TaskDialog)とは・・・

こちらの記事に詳しく書かれていますが、Vista 時点で Windows に搭載された機能のようです。
.NET Framework 時代でも Win32API を介せば使用できる機能だったようです。

Win32API での使用例はこちらのページで詳しく紹介されています。

.NET 5 で、フレームワークの標準機能として搭載されたということですね。

実例

TaskDialog のサンプルコードが公開されていたので、動作を確認してみました。

※ 以下、掲載しているソースコードは上記のサンプルコードから引用しています

従来のMessageBox

従来のMessageBoxです。

msgbox.PNG

TaskDialogでMessageBox

もちろん TaskDialog でも MessageBox と同様の表現が行えます。

taskdialog.PNG

タスクダイアログ上のコントロールは TaskDialogPage クラスのプロパティとして設定するようです。

            TaskDialogButton result = TaskDialog.ShowDialog(this, new TaskDialogPage()
            {
                Text = "Stopping the operation might leave your database in a corrupted state.",
                Heading = "Are you sure you want to stop?",
                Caption = "Confirmation (Task Dialog)",
                Buttons =
                {
                    TaskDialogButton.Yes,
                    TaskDialogButton.No
                },
                Icon = TaskDialogIcon.Warning,
                DefaultButton = TaskDialogButton.No
            });

            if (result == TaskDialogButton.Yes)
            {
                Console.WriteLine("User confirmed to stop the operation.");
            }

確認用CheckBox付きTaskDialog

「 CheckBox をONにすると、このメッセージを今後表示しない」という機能をもった、よく見かけるタイプのダイアログですね。

taskveryify.PNG

TaskDialogVerificationCheckBox をプロパティとして設定することで実装できます。
ダイアログ上でチェックがONになったかはpage.Verification.Checkedで取得できます。


            var page = new TaskDialogPage()
            {
                Heading = "Are you sure you want to stop?",
                Text = "Stopping the operation might leave your database in a corrupted state.",
                Caption = "Confirmation (Task Dialog)",
                Icon = TaskDialogIcon.Warning,
                AllowCancel = true,

                Verification = new TaskDialogVerificationCheckBox()
                {
                    Text = "Do not show again"
                },

                Buttons =
                {
                    TaskDialogButton.Yes,
                    TaskDialogButton.No
                },

                DefaultButton = TaskDialogButton.No
            };

            var resultButton = TaskDialog.ShowDialog(this, page);

            if (resultButton == TaskDialogButton.Yes)
            {
                if (page.Verification.Checked)
                    Console.WriteLine("Do not show this confirmation again.");

                Console.WriteLine("User confirmed to stop the operation.");
            }

ボタンが3つあるTaskDialog

これもよく見かけるタイプですね。
入力画面から遷移する際に「保存する(保存して遷移)/保存しない(保存しないで遷移)/キャンセル(画面にとどまる)」と選択肢を表示し、ユーザーに編集中の内容をどう扱うか確認させる、といった機能で見かけます。
これが MessageBox だとボタン名をカスタムできないので、表現できないんですよね。
TaskDialog であればわざわざデザイナーでダイアログを作成せずとも、表現できます。

closedoc.PNG

選択肢のあるTaskDialog

TaskDialogCommandLinkButton を配置することで、選択肢のあるダイアログを表現することもできます。
ボタンのTagプロパティによって、どのボタンを選択したかを判定できます。


                Buttons =
                {
                    new TaskDialogCommandLinkButton("&Beginner", "10 mines, 9 x 9 tile grid")
                    {
                        Tag = 10
                    },
                    new TaskDialogCommandLinkButton("&Intermediate", "40 mines, 16 x 16 tile grid")
                    {
                        Tag = 40
                    },
                    new TaskDialogCommandLinkButton("&Advanced", "99 mines, 16 x 30 tile grid")
                    {
                        Tag = 99
                    }
                }

            TaskDialogButton result = TaskDialog.ShowDialog(this, page);

            if (result.Tag is int resultingMines)
                Console.WriteLine($"Playing with {resultingMines} mines...");
            else
                Console.WriteLine("User canceled.");
        }

プログレスバーを設置したTaskDialog

TaskDialogProgressBarを用いて、TaskDialog 上に プログレスバーを設置することも可能です。
このコードは一定時間経過後に自動で TaskDailog を閉じる実装になっています。
reconnectButton.PerformClick();により、ボタンクリックをコードで発火させることで、ダイアログを閉じることができるようです。

autoclose.PNG


            var page = new TaskDialogPage()
            {
                Heading = "Connection lost; reconnecting...",
                Text = string.Format(textFormat, (remainingTenthSeconds + 9) / 10),
                // Display the form's icon in the task dialog.
                // Note however that the task dialog will not scale the icon.
                Icon = new TaskDialogIcon(this.Icon),
                ProgressBar = new TaskDialogProgressBar()
                {
                    State = TaskDialogProgressBarState.Paused
                },
                Buttons =
                {
                    reconnectButton,
                    cancelButton
                }
            };

            // Create a WinForms timer that raises the Tick event every tenth second.
            using (var timer = new Timer()
            {
                Enabled = true,
                Interval = 100
            })
            {
                timer.Tick += (s, e) =>
                {
                    remainingTenthSeconds--;
                    if (remainingTenthSeconds > 0)
                    {
                        // Update the remaining time and progress bar.
                        page.Text = string.Format(textFormat, (remainingTenthSeconds + 9) / 10);
                        page.ProgressBar.Value = 100 - remainingTenthSeconds * 2;
                    }
                    else
                    {
                        // Stop the timer and click the "Reconnect" button - this will
                        // close the dialog.
                        timer.Enabled = false;
                        reconnectButton.PerformClick();
                    }
                };

                TaskDialogButton result = TaskDialog.ShowDialog(this, page);
                if (result == reconnectButton)
                    Console.WriteLine("Reconnecting.");
                else
                    Console.WriteLine("Not reconnecting.");
            }

ページ遷移するTaskDialog

1つの TaskDialog 内で ページを切り替えることが可能です。
サンプルコードでは「処理の実行確認 → 処理実行中 → 処理完了」といったパターンの例が実装されていました。
initialPage.Navigate(inProgressPage);といった形でTaskDialogPage間で遷移させることができるようです。

            // When the user clicks "Yes", navigate to the second page.
            initialButtonYes.Click += (sender, e) =>
            {
                initialPage.Navigate(inProgressPage);
            };

ページ1

mulit1.PNG

ページ2

multi2.PNG

ページ2の「詳細の表示」をクリックした状態

multi4.PNG

ページ3

multi3.PNG

UAC(ユーザーアカウント制御)の確認画面を表示するTaskDialog

「Restart now」をクリックすると、Windows のUAC(ユーザーアカウント制御)の確認画面が表示され、
「はい」をクリックすると TaskDialog は閉じられコマンドプロンプトが起動されます。
「いいえ」をクリックすると TaskDialog は表示されたままの状態でいます。

elevated.PNG

            restartNowButton.Click += (s, e) =>
            {
                restartNowButton.AllowCloseDialog = true;
                restartNowButton.Enabled = false;

                // Try to start an elevated cmd.exe.
                var psi = new ProcessStartInfo("cmd.exe", "/k echo Hi, this is an elevated command prompt.")
                {
                    UseShellExecute = true,
                    Verb = "runas"
                };

                try
                {
                    Process.Start(psi)?.Dispose();
                }
                catch (Win32Exception ex) when (ex.NativeErrorCode == 1223)
                {
                    // The user canceled the UAC prompt, so don't close the dialog and
                    // re-enable the restart button.
                    restartNowButton.AllowCloseDialog = false;
                    restartNowButton.Enabled = true;
                    return;
                }
            };

TaskDialog 上のコントロールのイベント補足

TaskDialog 上に RadioButton ボタンを配置することも可能です。
RadioButton ボタンのCheckChangedイベントをはじめ、配置したコントロールのイベントを補足することが可能です。

event.PNG

event2.PNG

event3.PNG


            buttonNavigate.Click += (s, e) =>
            {
                Console.WriteLine($"Button '{s}' Click");

                // Navigate to a new page.
                var page2 = new TaskDialogPage()
                {
                    Heading = "AfterNavigation.",
                    Buttons =
                    {
                        TaskDialogButton.Close
                    }
                };
                page2.Created += (s, e) => Console.WriteLine("Page2 Created");
                page2.Destroyed += (s, e) => Console.WriteLine("Page2 Destroyed");

                page1.Navigate(page2);
            };

            page1.Verification = new TaskDialogVerificationCheckBox("&CheckBox");
            page1.Verification.CheckedChanged += (s, e) => Console.WriteLine("CheckBox CheckedChanged: " + page1.Verification.Checked);

            var radioButton1 = page1.RadioButtons.Add("Radi&oButton 1");
            var radioButton2 = page1.RadioButtons.Add("RadioB&utton 2");

            radioButton1.CheckedChanged += (s, e) => Console.WriteLine("RadioButton1 CheckedChanged: " + radioButton1.Checked);
            radioButton2.CheckedChanged += (s, e) => Console.WriteLine("RadioButton2 CheckedChanged: " + radioButton2.Checked);

あとがき

以上、「System.Windows.Forms.TaskDialog に触れてみた」でした。
TaskDialog を使用すれば、よくある機能のパターンを簡単に実装できそうですね。
数年前、Windowsフォームの案件に従事していた時代だったら、ぜひ使ってみたかったなと思います。

しかし、これから .NET5 + Windowsフォームの案件は果たして出てるくのでしょうか・・・
私感ですが、Windowsフォーム自体の案件も少なくなってきているのかな・・・とは思います・・・

25
20
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
20