000

Index Labels

PaletteSet/Modeless Form And Non-Drawing Document Window

.
Since AutoCAD 2015, Autodesk added non-document window in AutoCAD. It was called "New" tab, in AutoCAD 2015, and then was changed to "Start" tab. Further more, one or more custom non-drawing document windows can be added through custom code. My work place still uses AutoCAD 2015 and for certain reason our default setup is to disable "New" tab, and we does not have any non-drawing document window created by our customization code. So, it was only recently I found out the new AutoCAD feature of non-drawing document window causes trouble to some of our existing CAD applications, namely those using custom PaletteSet or modeless form.

As we know, when using floating window (PaletteSet/modeless form) with AutoCAD, if the content showing on the UI is tied to drawing, the content should be updated whenever user switch active drawing (Application.DocumentManager.MdiActiveDocument). When user closes all drawing in AutoCAD, the UI should disappear. Below is the code that has been working well when AutoCAD did not have "New" or "Start" tab/window (i.e. pre-AutoCAD 2015 versions):

Class MyPaletteSet:
using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Windows;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace HidePaletteSet
{
    public class MyPaletteSet : PaletteSet
    {
        private MyPalette _palette;
        private string _dwgName = "";
        private bool _preZeroDocVisible = false;

        public MyPaletteSet():base(
            "My PaletteSet",""new Guid("593F9149-F6F7-4771-BDF0-552A3BF6C4F0"))
        {
            MinimumSize = new System.Drawing.Size(500, 300);

            _palette = new HidePaletteSet.MyPalette();
            Add("My Palette", _palette);

            CadApp.DocumentManager.DocumentBecameCurrent += 
                DocumentManager_DocumentBecameCurrent;
            CadApp.DocumentManager.DocumentDestroyed += 
                DocumentManager_DocumentDestroyed;

        }

        public void Show()
        {
            if (!Visible)
            {
                var name = CadApp.DocumentManager.MdiActiveDocument.Name;
                if (name.ToUpper()!=_dwgName.ToUpper())
                {
                    UpdateMyPaletteView();
                }
            }

            Visible = true;
            Size = new System.Drawing.Size(500, 300);
            DockEnabled = DockSides.None;
            Dock = DockSides.None;
        }

        #region private methods

        private void DocumentManager_DocumentDestroyed(
            object sender, DocumentDestroyedEventArgs e)
        {
            if (CadApp.DocumentManager.Count <= 1)
            {
                _preZeroDocVisible = Visible;
                Visible = false;
                _dwgName = "";
            }        
        }

        private void DocumentManager_DocumentBecameCurrent(
            object sender, DocumentCollectionEventArgs e)
        {
            if (string.IsNullOrEmpty(_dwgName) && _preZeroDocVisible)
            {
                // A document is added/opened from 0 document status
                // and since the paletteset is visible before
                // entering 0 document status, thus make it visible.
                Visible = true;
            }

            if (Visible)
            {
                if (e.Document.Name.ToUpper() != _dwgName.ToUpper())
                {
                    _dwgName = e.Document.Name;
                    UpdateMyPaletteView();
                }
            }
        }

        private void UpdateMyPaletteView()
        {
            var fileName = CadApp.DocumentManager.MdiActiveDocument.Name;
            _palette.DrawingFileName = fileName;
        }

        #endregion
    }
}

The UserControl as palette is a simple UserControl with one Label and one read-only TextBox on it:
using System.Windows.Forms;

namespace HidePaletteSet
{
    public partial class MyPalette : UserControl
    {
        public MyPalette()
        {
            InitializeComponent();
        }

        public string DrawingFileName
        {
            set { txtFileName.Text = value; }
        }
    }
}

And here is the command class:
using Autodesk.AutoCAD.Runtime;

[assemblyCommandClass(typeof(HidePaletteSet.Commands))]

namespace HidePaletteSet
{
    public class Commands
    {
        private static MyPaletteSet _myPS = null;

        [CommandMethod("MyPS"CommandFlags.Session)]
        public static void RunSessionCommand()
        {
            if (_myPS==null)
            {
                _myPS = new HidePaletteSet.MyPaletteSet();
            }

            _myPS.Show();
        }
    }
}

This video clip shows how the code runs as expected when there is no "New"/"Start" window in AutoCAD. Because I use AutoCAD 2017, I simply set the system variable "STARTMODE" to 0 to disable "START" window.

Now, let me run the same code with "START" window enabled. See this video clip. As the video clip shows, with the PaletteSet is visible when I switch AutoCAD's active window from drawing document window to a non-drawing document window, an "null object" exception is raised, which crashes AutoCAD.

It turns out that when AutoCAD's active window switches from drawing window to non-drawing window (be it AutoCAD built-in "Start" window, or a custom non-drawing window), the event DocumentCollection_DocumentBecameCurrent still fires, but the Document property if the event argument is null, thus the not handled exception crashing AutoCAD. So, in the DocumentCollection.DocumentBecameCurrent event handler, I modified the code (actually added a few lines of code, in red color) to handle the case of Document being null:

private void DocumentManager_DocumentBecameCurrent(
    object sender, DocumentCollectionEventArgs e)
{
    if (e.Document==null)
    {
        _preZeroDocVisible = Visible;
        _dwgName = "";
        Visible = false;
        return;
    }


    if (string.IsNullOrEmpty(_dwgName) && _preZeroDocVisible)
    {
        // A document is added/opened from 0 document status
        // and since the paletteset is visible before
        // entering 0 document status, thus make it visible.
        Visible = true;
    }

    if (Visible)
    {
        if (e.Document.Name.ToUpper() != _dwgName.ToUpper())
        {
            _dwgName = e.Document.Name;
            UpdateMyPaletteView();
        }
    }
}

Now see this video clip that shows the PaletteSet now shows and hides correctly.

Obviously, when new features being added into AutoCAD, it could break existing custom applications. In this particular case, Autodesk chose to still fire an DocumentCollection event - DocumentBecameCurrent, which was meant for a drawing document, when a non-drawing document becomes active, and oddly enough, the document that is supposed to become current is null.

Of course, my modified code works with pre-2015 AutoCAD where no non-document window available, because the Document property in the event argument would never be null, so the added code (in red) would never be executed.





Blog Archive

Labels

3D Modeling 3D Sketch Inventor AI Design AI in Manufacturing AI Tools Architecture Artificial Intelligence AutoCAD AutoCAD advice AutoCAD Basics AutoCAD Beginners AutoCAD Civil3D AutoCAD commands AutoCAD efficiency AutoCAD features AutoCAD File Management AutoCAD Layer AutoCAD learning AutoCAD print settings AutoCAD productivity AutoCAD Teaching AutoCAD Techniques AutoCAD tips AutoCAD training. AutoCAD tricks AutoCAD Tutorial AutoCAD workflow AutoCAD Xref Autodesk Autodesk 2025 Autodesk AI Tools Autodesk AutoCAD Autodesk Fusion 360 Autodesk Inventor Autodesk Inventor Frame Generator Autodesk Inventor iLogic Autodesk Recap Autodesk Revit Autodesk Software Autodesk Video Automation Automation Tutorial Basic Commands Basics Beginner Beginner Tips BIM BIM Implementation Block Editor ByLayer CAD comparison CAD Design CAD File Size Reduction CAD line thickness CAD Optimization CAD Productivity CAD software clean CAD file cleaning command Cloud Collaboration command abbreviations Construction Technology Contraints Create resizable blocks CTB STB Data Reference Data Shortcut design software Design Workflow Digital Design Digital Twin Drafting Standards Drawing Automation Dref Dynamic Block Dynamic Block AutoCAD Dynamic Blocks Dynamic doors Dynamic windows eco design editing commands energy efficiency Engineering Engineering Design Engineering Innovation Engineering Technology engineering tools Excel Express Tools External Reference Fast Structural Design Fusion 360 Generative Design green building Grips heavy CAD file Heavy CAD Files iLogic Industry 4.0 Insight Inventor API Inventor Drawing Template Inventor Frame Generator Inventor Graphics Issues Inventor IDW Inventor Tips Keyboard Shortcuts Learn AutoCAD Machine Learning in CAD maintenance command Management Manufacturing Innovation Metal Structure ObjectARX .NET API Organization OVERKILL OVERKILL AutoCAD Palette PDF Plot Style AutoCAD Practice Drawing Printing Quality professional printing Professional Tips PTC Creo PURGE PURGE AutoCAD ReCap reduce CAD file size Resizable Block Revit Revit Best Practices Revit Workflow Ribbon screen shortcut keys Shortcuts Siemens NX Sketch Small Firms Smart Block Smart Factory SolidWorks Steel Structure Design sustainability Sustainable Manufacturing toolbar Tutorial User Interface (UI) Workbook Workspace XLS Xref