Friday, March 3, 2017

Handling Document.UnknownCommand Event, 2 of 2

In previous article I showed how to write a simple on demand application loader by handling Document.UnknownCommand event. We have seen that AutoCAD acts differently from other Document/Document event when it is handling: after running the code in the event handler, AutoCAD try to execute the previously unknown command again. That is, the first time AutoCAD executes an unknown command, Document.UnknownCommand event fires, which allows a chance for custom application to do something - here is how a custom on demand loading process could be plugged in; then AutoCAD tries to execute the same command again; if the command is still not defined, then AutoCAD spills "Unknown command" message at command line; only this time, no UnknownCommand event is fired.

During my exploration of handling UnknownCommand event, I came across another interesting behaviour of this event, which is quite similar to the notorious behaviour of IExtensionApplication.Initialize(): the code in the event handler must make sure any possible exception being handled. If an exception occurs inside the event handler, instead of breaking AutoCAD process, AutoCAD simply silently swallow the exception and keeps going, but the event handler will stop working, as if it is removed.

Here is the code to show this behaviour:
using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;
 
[assemblyCommandClass(typeof(UnknownCommandException.MyCommands))]
 
namespace UnknownCommandException
{
    public class MyCommands 
    {
        private bool _handled = false;
 
        [CommandMethod("HandleUkCm")]
        public void HandleUnknownCommandEvent()
        {
            var doc = CadApp.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
 
            if (!_handled)
            {
                doc.UnknownCommand += Doc_UnknownCommand;
                _handled = true;
                ed.WriteMessage("\nUnknownCommand event handler has been added.");
            }
            else
            {
                doc.UnknownCommand -= Doc_UnknownCommand;
                _handled = false;
                ed.WriteMessage("\nUnknownCommand event handler has been removed.");
            }
        }
 
        private void Doc_UnknownCommand(object sender, UnknownCommandEventArgs e)
        {
            var msg = "This is custom UnknowCommand event handler." +
                "\n\nClick \"Yes\" to suppress ths event handler" +
                "\nClick \"No\" to keep it" +
                "\n\n Do you want to suppress this event handler?";
            var res = System.Windows.Forms.MessageBox.Show(
                msg, "Custom UnknownCommand Handler",
                System.Windows.Forms.MessageBoxButtons.YesNo,
                System.Windows.Forms.MessageBoxIcon.Question,
                System.Windows.Forms.MessageBoxDefaultButton.Button2);
            if (res== System.Windows.Forms.DialogResult.Yes)
            {
                throw new ApplicationException(
                    "Stop custom UnknownCommand event handler.");
            }
        }
    }
}

As the code logic in the event handler shows, as long as the user does not click "Yes" button in the message box, the event handler gets execution each time an unknown command is entered. Once user clicks "Yes", an exception is raised and left not handled, AutoCAD continues in spite of the exception not being handled. However, from that point on, the UnknownCommand event handler is no longer executed when unknown command is entered. This video clip shows this behaviour.

As we see, unless the code in custom UnknownCommand event handler is very simple and no chance to raise any exception, we'd better always wrap up the code in UnknownCommand event handler in try...catch... block, just as we do in IExtensionApplication.Initialize().