private async Task RunSimulatorAsync()
        {
            btnStart.IsEnabled = false;
            btnStop.IsEnabled = true;
            btnLoad.IsEnabled = false;
            if (quickActionButtons != null)
                foreach (var bt in quickActionButtons)
                    bt.IsEnabled = false;


            // Run the simulator in another task so it is not executed in the GUI thread.
            // However, we then await that new task so we are notified when it is finished.
            Simulator sim = simulator = new Simulator(currentQuickAction != null ? currentQuickAction.Action 
                : project.Configuration.MainAction, TTRWindowsEnvironment.Instance);
            sim.AsyncRetryHandler = async (ex) => !closeWindowAfterStop && await HandleSimulatorRetryAsync(sim, ex);

            Exception runException = null;
            simulatorStartAction?.Invoke();
            await Task.Run(async () =>
            {
                try
                {
                    await sim.RunAsync();
                }
                catch (Exception ex)
                {
                    runException = ex;   
                }
            });
            simulatorStopAction?.Invoke();

            // Don't show a messagebox if we need to close the window.
            if (!closeWindowAfterStop && runException != null && !(runException is SimulatorCanceledException))
            {
                TaskDialog dialog = new TaskDialog()
                {
                    Title = AppName,
                    MainInstruction = "Simulator stopped!",
                    Content = runException.Message,
                    ExpandedInformation = GetExceptionDetailsText(runException),
                    MainIcon = TaskDialog.TaskDialogIcon.Stop,
                    CommonButtons = TaskDialog.TaskDialogButtons.OK
                };
                dialog.Flags |= TaskDialog.TaskDialogFlags.ExpandFooterArea;
                dialog.Show(this);
            }

            HandleSimulatorCanceled();
        }
        private async Task<bool> HandleSimulatorRetryAsync(Simulator sim, ExceptionDispatchInfo ex)
        {
            // Show a TaskDialog.
            bool result = false;
            await Dispatcher.InvokeAsync(new Action(() =>
            {
                if (!closeWindowAfterStop)
                {
                    TaskDialog dialog = new TaskDialog()
                    {
                        Title = AppName,
                        MainInstruction = "Simulator interrupted!",
                        Content = ex.SourceException.Message,
                        ExpandedInformation = GetExceptionDetailsText(ex.SourceException),
                        MainIcon = TaskDialog.TaskDialogIcon.Warning,
                        CommonButtons = TaskDialog.TaskDialogButtons.Cancel
                    };
                    dialog.Flags |= TaskDialog.TaskDialogFlags.UseCommandLinks |
                            TaskDialog.TaskDialogFlags.ExpandFooterArea;

                    var buttonTryAgain = dialog.CreateCustomButton("Try again\n" 
                        + "The Simulator will try to run the current action again.");
                    var buttonStop = dialog.CreateCustomButton("Stop the Simulator");

                    dialog.CustomButtons = new TaskDialog.ICustomButton[] { buttonTryAgain, buttonStop };
                    dialog.DefaultCustomButton = buttonStop;

                    dialog.Show(this);

                    if (dialog.ResultCustomButton == buttonTryAgain)
                        result = true;
                }
            }));

            return result;
        }
        private void btnLoad_Click(object sender, RoutedEventArgs e)
        {
            if (openFileDialog.ShowDialog(this) == true)
            {
                // Try to load the given project.
                try
                {
                    using (FileStream fs = new FileStream(openFileDialog.FileName, FileMode.Open,
                        FileAccess.Read, FileShare.Read))
                    {
                        XmlProjectDeserializer deser = new XmlProjectDeserializer();
                        project = deser.Deserialize(fs);
                    }
                }
                catch (Exception ex)
                {
                    TaskDialog dialog = new TaskDialog()
                    {
                        Title = AppName,
                        MainInstruction = "Could not load the selected project.",
                        Content = ex.Message,
                        ExpandedInformation = GetExceptionDetailsText(ex),
                        MainIcon = TaskDialog.TaskDialogIcon.SecurityErrorBar,
                        MainUpdateIcon = TaskDialog.TaskDialogIcon.Stop,
                        CommonButtons = TaskDialog.TaskDialogButtons.OK
                    };
                    dialog.Flags |=  TaskDialog.TaskDialogFlags.SizeToContent |
                        TaskDialog.TaskDialogFlags.ExpandFooterArea;

                    dialog.Show(this);
                    return;
                }


                if (quickActionButtons != null)
                {
                    foreach (var b in quickActionButtons)
                        gridProjectControls.Children.Remove(b);
                    quickActionButtons = null;
                }

                RefreshProjectControls();

                // For each quick action, create a button.
                quickActionButtons = new Button[project.Configuration.QuickActions.Count];
                for (int idx = 0; idx < project.Configuration.QuickActions.Count; idx++)
                {
                    int i = idx;
                    var quickAction = project.Configuration.QuickActions[i];

                    Button b = quickActionButtons[i] = new Button();
                    b.Height = 21;
                    b.HorizontalAlignment = HorizontalAlignment.Left;
                    b.VerticalAlignment = VerticalAlignment.Top;
                    b.Margin = new Thickness(0, 2 + 23 * i, 0, 0);
                    b.Content = "  " + quickAction.Name + "  ";
                    gridProjectControls.Children.Add(b);
                    Grid.SetRow(b, 1);

                    b.Click += async (_s, _e) =>
                    {
                        currentQuickAction = quickAction;
                        RefreshProjectControls();

                        await RunSimulatorAsync();
                    };
                }
            }
        }
        public static TaskDialogResult Show(IntPtr hwndOwner, string content, string instruction = null, string caption = null,
            TaskDialogButtons buttons = TaskDialogButtons.OK, TaskDialogIcon icon = 0)
        {
            TaskDialog dialog = new TaskDialog()
            {
                Content = content,
                MainInstruction = instruction,
                Title = caption,
                CommonButtons = buttons,
                MainIcon = icon
            };
            dialog.Show(hwndOwner);

            return dialog.ResultCommonButtonID;
        }