November 14, 2008

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

{

publicclassCommands

{

// In a real application we would retrieve this

// persistent setting from somewhere

static bool neveragain = false;

enumDecisionOptions

{

DoOperation,

Reselect,

Cancel

};

[CommandMethod("Task2")]

publicstaticvoid 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 = newTaskDialog();

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(

newTaskDialogButton(

0,

"Perform the operation on the selected objects."

)

);

td.Buttons.Add(

newTaskDialogButton(

1,

"Reselect objects to edit"

)

);

td.Buttons.Add(

newTaskDialogButton(

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;

}

returnfalse;

};

td.Show(Application.MainWindow.Handle);

}

switch (decision)

{

caseDecisionOptions.DoOperation:

// Perform the operation anyway...

ed.WriteMessage(

"\nThis is where we do something " +

"with our {0} entities.",

psr.Value.Count

);

done = true;

break;

caseDecisionOptions.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:

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.