Skip to content

Instantly share code, notes, and snippets.

@htsign
Created May 8, 2021 21:17
Show Gist options
  • Save htsign/06a4a3bb2202b844dc4b22a0952c487a to your computer and use it in GitHub Desktop.
Save htsign/06a4a3bb2202b844dc4b22a0952c487a to your computer and use it in GitHub Desktop.
// required: FSharp.Control.AsyncSeq
open FSharp.Control
open System.Diagnostics
open System.Drawing
open System.Windows.Forms
let inline initCollectionWithCtor< ^a, 'b, 'c when ^a : (member Add : 'b -> 'c)> items collection =
let add xs x = (^a : (member Add : 'b -> 'c) (xs, x))
items |> List.fold (fun (xs : 'a) x -> add xs x |> ignore; xs) collection
let inline initCollection< ^a, 'b, 'c when ^a : (new : unit -> 'a) and ^a : (member Add : 'b -> 'c)> items =
initCollectionWithCtor items (new 'a())
type Form1() as self =
inherit Form(Text = "Task Dialog Demos", Size = Size(600, 400))
do
let currentButtonCount = ref 0
let addButtonForAction name action =
incr currentButtonCount
let nextButton = !currentButtonCount
let button =
new Button(
Text = name,
Size = Size(180, 33),
Location = Point(nextButton / 20 * 200 + 20, nextButton % 20 * 40))
button.Click.Add <| fun _ -> action()
self.Controls.Add button
addButtonForAction "Confirmation Dialog (3x)" self.ShowSimpleTaskDialog
addButtonForAction "Close Document Conformation" self.ShowCloseDocumentTaskDialog
addButtonForAction "Minesweeper Difficulty" self.ShowMinesweeperDifficultySelectionTaskDialog
addButtonForAction "Auto-Closing Dialog" self.ShowAutoClosingTaskDialog
addButtonForAction "Multi-Page Dialog (modeless)" self.ShowMultiPageTaskDialog
addButtonForAction "Elevation Required" self.ShowElevatedProcessTaskDialog
addButtonForAction "Events Demo" self.ShowEventsDemoTaskDialog
member private _.ShowSimpleTaskDialog () =
let messageBoxResult =
MessageBox.Show(
self,
text = "Stopping the operation might leave your database in a corrupted state. Are you sure you want to stop?",
caption = "Confirmation [Message Box]",
buttons = MessageBoxButtons.YesNo,
icon = MessageBoxIcon.Warning,
defaultButton = MessageBoxDefaultButton.Button2)
if messageBoxResult = DialogResult.Yes then
printfn "User confirmed to stop the operation."
let result =
TaskDialog.ShowDialog(
self,
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 = initCollection [TaskDialogButton.Yes; TaskDialogButton.No],
Icon = TaskDialogIcon.Warning,
DefaultButton = TaskDialogButton.No))
if result = TaskDialogButton.Yes then
printfn "User confirmed to stop the operation."
let page =
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 = TaskDialogVerificationCheckBox "Do not show again",
Buttons = initCollection [TaskDialogButton.Yes; TaskDialogButton.No],
DefaultButton = TaskDialogButton.No)
let resultButton = TaskDialog.ShowDialog(self, page)
if resultButton = TaskDialogButton.Yes then
printfn (if page.Verification.Checked
then "Do not show this confirmation again."
else "User confirmed to stop the operation.")
member private _.ShowCloseDocumentTaskDialog () =
let btnCancel = TaskDialogButton.Cancel
let btnSave = TaskDialogButton "&Save"
let btnDontSave = TaskDialogButton "Do&n't save"
let page =
TaskDialogPage(
Caption = "My Application",
Heading = "Do you want to save changes to Untitled?",
Buttons = initCollection [btnCancel; btnSave; btnDontSave])
let result = TaskDialog.ShowDialog(self, page)
printfn (if result = btnSave
then "Saving"
elif result = btnDontSave
then "Not saving"
else "Canceling")
member private _.ShowMinesweeperDifficultySelectionTaskDialog () =
let page =
TaskDialogPage(
Caption = "Minesweeper",
Heading = "What level of difficulty do you want to play?",
AllowCancel = true,
Footnote = TaskDialogFootnote "Note: You can change the difficulty level later by clicking Options on the Game menu.",
Buttons = initCollection [
TaskDialogCommandLinkButton("&Beginner", "10 mines, 9 x 9 tile grid", Tag = 10)
TaskDialogCommandLinkButton("&Intermediate", "40 mines, 16 x 16 tile grid", Tag = 40)
TaskDialogCommandLinkButton("&Advanced", "99 mines, 16 x 30 tile grid", Tag = 99)
])
let result = TaskDialog.ShowDialog(self, page)
printfn "%s" (
match result.Tag with
| :? int as resultingMines -> sprintf "Playing with %d mines..." resultingMines
| _ -> "User canceled.")
member private _.ShowAutoClosingTaskDialog () =
let format = sprintf "Reconnecting in %d seconds..."
let remainingTenthSeconds = ref 50
let reconnectButton = TaskDialogButton "&Reconnect now"
let cancelButton = TaskDialogButton.Cancel
let page =
TaskDialogPage(
Heading = "Connection lost; reconnecting...",
Text = format ((!remainingTenthSeconds + 9) / 10),
Icon = new TaskDialogIcon(self.Icon),
ProgressBar = TaskDialogProgressBar TaskDialogProgressBarState.Paused,
Buttons = initCollection [reconnectButton; cancelButton])
use timer = new Timer(Enabled = true, Interval = 100)
timer.Tick.Add <| fun _ ->
decr remainingTenthSeconds
if !remainingTenthSeconds > 0 then
page.Text <- format ((!remainingTenthSeconds + 9) / 10)
page.ProgressBar.Value <- 100 - !remainingTenthSeconds * 2
else
timer.Enabled <- false
reconnectButton.PerformClick()
let result = TaskDialog.ShowDialog(self, page)
printfn (if result = reconnectButton
then "Reconnecting."
else "Not reconnecting.")
member private _.ShowMultiPageTaskDialog () =
let initialButtonYes = TaskDialogButton.Yes
initialButtonYes.Enabled <- false
initialButtonYes.AllowCloseDialog <- false
let initialPage =
TaskDialogPage(
Caption = "My Application",
Heading = "Clean up database?",
Text = "Do you really want to do a clean-up?\nThis action is irreversible!",
Icon = TaskDialogIcon.ShieldWarningYellowBar,
AllowCancel = true,
AllowMinimize = true,
Verification = TaskDialogVerificationCheckBox "I know what I'm doing",
Buttons = initCollection [TaskDialogButton.No; initialButtonYes],
DefaultButton = TaskDialogButton.No)
let inProgressPage =
let inProgressCloseButton = TaskDialogButton.Close
inProgressCloseButton.Enabled <- false
let invisibleCancelButton = TaskDialogButton.Cancel
invisibleCancelButton.Visible <- false
invisibleCancelButton.AllowCloseDialog <- false
TaskDialogPage(
Caption = "My Application",
Heading = "Operation in progress...",
Text = "Please wait while the operation is in progress.",
Icon = TaskDialogIcon.Information,
AllowMinimize = true,
ProgressBar = TaskDialogProgressBar TaskDialogProgressBarState.Marquee,
Expander = TaskDialogExpander("Initializing...", Position = TaskDialogExpanderPosition.AfterFootnote),
Buttons = initCollection [inProgressCloseButton; invisibleCancelButton])
let showResultsButton = TaskDialogCommandLinkButton "Show &Results" :> TaskDialogButton
let finishedPage =
TaskDialogPage(
Caption = "My Application",
Heading = "Success!",
Text = "The operation finished.",
Icon = TaskDialogIcon.ShieldSuccessGreenBar,
AllowMinimize = true,
Buttons = initCollection [TaskDialogButton.Close; showResultsButton])
let checkBox = initialPage.Verification
checkBox.CheckedChanged.Add <| fun _ ->
initialButtonYes.Enabled <- checkBox.Checked
initialButtonYes.Click.Add <| fun _ ->
initialPage.Navigate inProgressPage
inProgressPage.Created.Add <| fun _ ->
let progressBar = inProgressPage.ProgressBar
let streamBackgroundOperationProgressAsync () =
asyncSeq {
do! Async.Sleep 2800
for i in seq { 0 .. 4 .. 100 } do
yield i
do! Async.Sleep 200 }
asyncSeq {
for progressValue in streamBackgroundOperationProgressAsync () do
if progressBar.State = TaskDialogProgressBarState.Marquee then
progressBar.State <- TaskDialogProgressBarState.Normal
progressBar.Value <- progressValue
inProgressPage.Expander.Text <- sprintf "Progress: %d %%" progressValue
inProgressPage.Navigate finishedPage }
|> AsyncSeq.iter ignore
|> Async.StartImmediate
let result = TaskDialog.ShowDialog initialPage
if result = showResultsButton then
printfn "Showing Results!"
member private _.ShowElevatedProcessTaskDialog () =
let page =
let restartNowButton = TaskDialogCommandLinkButton "&Restart now" :> TaskDialogButton
restartNowButton.ShowShieldIcon <- true
restartNowButton.Click.Add <| fun _ ->
restartNowButton.AllowCloseDialog <- true
restartNowButton.Enabled <- false
let psi =
ProcessStartInfo("cmd.exe", "/k echo Hi, this is an elevated command prompt.",
UseShellExecute = true,
Verb = "runas")
try
match Process.Start(psi) with
| null -> ()
| x -> x.Dispose()
with
| :? System.ComponentModel.Win32Exception as ex when ex.NativeErrorCode = 1223 ->
restartNowButton.AllowCloseDialog <- false
restartNowButton.Enabled <- true
TaskDialogPage(
Heading = "Settings saved - Service Restart required",
Text = "The service needs to be restarted to apply the changes.",
Icon = TaskDialogIcon.ShieldSuccessGreenBar,
Buttons = initCollection [TaskDialogButton.Close; restartNowButton])
TaskDialog.ShowDialog(self, page) |> ignore
member private _.ShowEventsDemoTaskDialog () =
let clicked sender _ = printfn "Button '%O' Click" sender
let page1 =
let buttonOk = TaskDialogButton.OK
let buttonHelp = TaskDialogButton.Help
let buttonCancelClose =
TaskDialogCommandLinkButton("C&ancel Close", allowCloseDialog = false) :> TaskDialogButton
let buttonShowInnerDialog =
TaskDialogCommandLinkButton("&Show (modeless) Inner Dialog", "(and don't cancel the Close") :> TaskDialogButton
let clickedHandler = System.EventHandler clicked
buttonOk.Click.AddHandler clickedHandler
buttonHelp.Click.AddHandler clickedHandler
buttonCancelClose.Click.AddHandler clickedHandler
buttonShowInnerDialog.Click.AddHandler <| System.EventHandler(fun sender e ->
clicked sender e
TaskDialog.ShowDialog(TaskDialogPage(Text = "Inner Dialog")) |> ignore
printfn "(returns) Button '%O' Click" sender)
TaskDialogPage(
Caption = self.Text,
Heading = "Event Demo",
Text = "Event Demo...",
Buttons =
initCollection
[
buttonOk
buttonHelp
buttonCancelClose
buttonShowInnerDialog
],
Expander = TaskDialogExpander("Expander", Position = TaskDialogExpanderPosition.AfterFootnote),
Verification = TaskDialogVerificationCheckBox "&CheckBox")
let buttonNavigate = TaskDialogCommandLinkButton("&Navigate", allowCloseDialog = false)
page1.Buttons.Add buttonNavigate
buttonNavigate.Click.AddHandler <| System.EventHandler(fun sender e ->
clicked sender e
let page2 = TaskDialogPage(Heading = "AfterNavigation.", Buttons = initCollection [TaskDialogButton.Close])
page2.Created.Add <| fun _ -> printfn "Page2 Created"
page2.Destroyed.Add <| fun _ -> printfn "Page2 Destoryed"
page1.Navigate page2)
page1.Created.Add <| fun _ -> printfn "Page1 Created"
page1.Destroyed.Add <| fun _ -> printfn "Page1 Destoroyed"
page1.HelpRequest.Add <| fun _ -> printfn "Page1 HelpRequest"
page1.Expander.ExpandedChanged.Add <| fun _ -> printfn "Expander ExpandedChanged: %b" page1.Expander.Expanded
page1.Verification.CheckedChanged.Add <| fun _ -> printfn "CheckBox CheckedChanged: %b" page1.Verification.Checked
let radioButton1 = page1.RadioButtons.Add "Radi&oButton 1"
let radioButton2 = page1.RadioButtons.Add "RadioB&utton 2"
radioButton1.CheckedChanged.Add <| fun _ -> printfn "RadioButton1 CheckedChanged: %b" radioButton1.Checked
radioButton2.CheckedChanged.Add <| fun _ -> printfn "RadioButton2 CheckedChanged: %b" radioButton2.Checked
let dialogResult = TaskDialog.ShowDialog page1
printfn "---> Dialog Result: %O" dialogResult
[<EntryPoint; System.STAThread>]
do
Application.SetHighDpiMode HighDpiMode.SystemAware |> ignore
Application.EnableVisualStyles()
Application.Run(new Form1())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment