前置き
今年リリースされた「.NET 5」。なんと Windows Forms に新しいコントロールが追加されていました。
本記事ではそのうちの1つ「System.Windows.Forms.TaskDialog」をご紹介したいと思います。
タスクダイアログ(TaskDialog)とは・・・
こちらの記事に詳しく書かれていますが、Vista 時点で Windows に搭載された機能のようです。
.NET Framework 時代でも Win32API を介せば使用できる機能だったようです。
Win32API での使用例はこちらのページで詳しく紹介されています。
.NET 5 で、フレームワークの標準機能として搭載されたということですね。
実例
TaskDialog のサンプルコードが公開されていたので、動作を確認してみました。
※ 以下、掲載しているソースコードは上記のサンプルコードから引用しています
従来のMessageBox
従来のMessageBoxです。
TaskDialogでMessageBox
もちろん TaskDialog でも MessageBox と同様の表現が行えます。
タスクダイアログ上のコントロールは 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にすると、このメッセージを今後表示しない」という機能をもった、よく見かけるタイプのダイアログですね。
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 であればわざわざデザイナーでダイアログを作成せずとも、表現できます。
選択肢のある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();
により、ボタンクリックをコードで発火させることで、ダイアログを閉じることができるようです。
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
ページ2
ページ2の「詳細の表示」をクリックした状態
ページ3
UAC(ユーザーアカウント制御)の確認画面を表示するTaskDialog
「Restart now」をクリックすると、Windows のUAC(ユーザーアカウント制御)の確認画面が表示され、
「はい」をクリックすると TaskDialog は閉じられコマンドプロンプトが起動されます。
「いいえ」をクリックすると TaskDialog は表示されたままの状態でいます。
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
イベントをはじめ、配置したコントロールのイベントを補足することが可能です。
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フォーム自体の案件も少なくなってきているのかな・・・とは思います・・・