Implementing task dialogs inside AutoCAD using .NET - Part 2

In this previous post we looked at a basic task dialog inside AutoCAD and exercised its various capabilities without showing how they might be used in a real application. This post goes beyond that to show how you might make use of the TaskDialog class to provide your users with relevant information at runtime that helps them decide how best to proceed in certain situations, effectively increasing your application's usability.

The specific scenario is this: if the user selects a lot of entities - too many for our command to handle quickly - we want to show a dialog that allows the user to decide whether to proceed anyway, to select fewer entities or to cancel completely from the command. For the sake of argument we're going to set a threshold of 1,000 entities being "a lot", although it may well be that for your various operations 100 or 100,000 is a better number).

Here's some C# code that asks the user to select entities and then either performs an operation on them or presents a number of options to the user:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.Windows;

namespace TaskDialogs

{

  public class Commands

  {

    // In a real application we would retrieve this

    // persistent setting from somewhere

    static bool neveragain = false;

    enum DecisionOptions

    {

      DoOperation,

      Reselect,

      Cancel

    };

    [CommandMethod("Task2")]

    public static void MoreRealisticTask()

    {

      Editor ed =

        Application.DocumentManager.MdiActiveDocument.Editor;

      bool done = false;

      while (!done)

      {

        PromptSelectionResult psr = ed.GetSelection();

        if (psr.Status != PromptStatus.OK)

          done = true;

        else

        {

          DecisionOptions decision = DecisionOptions.DoOperation;

          if (psr.Value.Count > 1000 && !neveragain)

          {

            TaskDialog td = new TaskDialog();

            td.Width = 200;

            td.WindowTitle =

              "Many objects selected";

            td.MainInstruction =

              psr.Value.Count.ToString() +

              " objects have been selected, " +

              "which may lead to a time-consuming operation.";

            td.UseCommandLinks = true;

            td.Buttons.Add(

              new TaskDialogButton(

                0,

                "Perform the operation on the selected objects."

              )

            );

            td.Buttons.Add(

              new TaskDialogButton(

                1,

                "Reselect objects to edit"

              )

            );

            td.Buttons.Add(

              new TaskDialogButton(

                2,

                "Do nothing and cancel the command"

              )

            );

            td.VerificationText =

              "Do not ask me this again";

            td.Callback =

              delegate(

                ActiveTaskDialog atd,

                TaskDialogEventArgs e,

                object sender

              )

              {

                if (e.Notification ==

                      TaskDialogNotification.ButtonClicked)

                {

                  switch (e.ButtonId)

                  {

                    case 0:

                      decision = DecisionOptions.DoOperation;

                      break;

                    case 1:

                      decision = DecisionOptions.Reselect;

                      break;

                    case 2:

                      decision = DecisionOptions.Cancel;

                      break;

                  }

                }

                if (e.Notification ==

                      TaskDialogNotification.VerificationClicked)

                {

                  neveragain = true;

                }

                return false;

              };

            td.Show(Application.MainWindow.Handle);

          }

          switch (decision)

          {

            case DecisionOptions.DoOperation:

              // Perform the operation anyway...

              ed.WriteMessage(

                "\nThis is where we do something " +

                "with our {0} entities.",

                psr.Value.Count

              );

              done = true;

              break;

            case DecisionOptions.Reselect:

              done = false;

              break;

            // Includes DecisionOptions.Cancel...

            default:

              done = true;

              break;

          }

        }

      }

      // This is where we would store the value of neveragain

      // in our persistent application settings

    }

  }

}

Here's what happens when we run the TASK2 command and select 2,500 entities:

A real-world task dialog example

The behaviour should be pretty predictable - you can reselect again and again, until you either:

  • Go ahead and perform the operation (action 1)
  • Reselect fewer than the threshold of 1000 entities (action 2)
  • Give up and cancel the command (action 3)
  • Decide not to be asked the question again (the checkbox at the bottom)

If you select the checkbox and reselect (action 2), for instance, you won't then be asked the question again during that session, even if you go ahead and select 100,000 entities. One thing the application doesn't do is to save the value of this setting - you would need to store it somewhere in your application settings (probably in the Registry or a configuration file of some kind), and ideally provide the user with some ability to re-enable the task dialog, should they decide it's a good idea to have it, after all.

Update

In AutoCAD 2010 the TaskDialogEventArgs class was renamed to TaskDialogCallbackArgs, apparently to be more consistent with .NET naming conventions. If you receive an error such as "The type or namespace name 'TaskDialogEventArgs' could not be found (are you missing a using directive or an assembly reference?)" when building your application, updating the name to be TaskDialogCallbackArgs will resolve it.

  1. Kean,

    I work for Autodesk and have some questions about the Task Dialog posting. Would you mind sending me an email to my address?

    Thanks,
    Matt

  2. Kean,
    I have been using your example to create and display my own Task Dialogs and been delighted with the results. However, I have noticed with migrating the code to 2010 that the AutoCAD icon in the top LH corner of the does not display. This is not important, just wondered if you might have any ideas?

    Steve

    AutoCAD 2009/2010 on XP Pro

  3. Kean Walmsley Avatar

    Steve,

    I have to admit I haven't looked. It could well be a change in style between 2009 and 2010. Have you checked any standard task dialogs, to see what they look like?

    Cheers,

    Kean

  4. Hi Kean,

    Although 2009 is OK, the "core" 2010 Task Dialogs don't appear to show the AutoCAD icon either. They must have changed (or forgotten to do) something in this release.

    Cheers, Steve.

  5. Kean Walmsley Avatar

    Hi Steve,

    At least it's consistent. 🙂

    My bet is that this is by design: it'd be very surprising if a detail like this was changed by mistake.

    Cheers,

    Kean

  6. Hi Kean,

    This all works great for me, with one exception. When I call a TaskDialog from a windows form, it seems to open modeless. Outside of a windows form, it works fine (modal).

    Do you have any idea how I can fix this?

    Thanks!
    Brent

  7. Ahhh, I figured it out- I was calling taskdialog.show without properly passing an owner argument. Thanks anyways!

Leave a Reply to Brent McAnney Cancel reply

Your email address will not be published. Required fields are marked *