c# - detect command input to set correct current layer

c# - detect command input to set correct current layer

stefanveurink68AXD
Advocate Advocate
1,892 Views
8 Replies
Message 1 of 9

c# - detect command input to set correct current layer

stefanveurink68AXD
Advocate
Advocate

Very simplified, what i've got is the following:

 

A userform:
At one place in the form you can set the layer for lines. 

At another place in the form you can set the layer for circles. 
At another place in the form you can set the for blocks. 

and so on.... 

 

Now, what I want is: (when a certain checkbox is checked so the userform should be active) the form detecting when the Autocad-user is clicking the 'line' button or the 'circle'-button from the standard Autocad Toolbars, or maybe types "insert" to insert a block, so the current layer can be set to wanted layer.

 

So I created a while loop which is active as long as the checkbox is checked. In this while-loop I get the last inserted command (by AutoCADAppServices.Application.GetSystemVariable("CMDNAMES"), convert it to a string, and do the 'switch' lines on the different cases (last command is _line then set layer to a, last command is _circle then set layer to b, last command is _insert then set layer to c).  

 

2 questions: 

1) is the 'switch'way the right way to do this?

2) (maybe not fully autocad-related): how can i prevent the code from getting stuck in the while-loop, so I cant click any commands anymore (nor uncheck the checkbox or do anything else). 

 

Any help would be appreciated, I'm a little stuck on this the last days, can't get it to work nor I can check if at least i'm getting closer (because of while-loop getting stuck (which by the way makes perfect sense to me but I don't know how to prevent it)). 

 

Thanks!

 

 

0 Likes
Accepted solutions (2)
1,893 Views
8 Replies
Replies (8)
Message 2 of 9

_gile
Consultant
Consultant

Hi,

 

Maybe you can handle the Editor.CommandWillStart event to set the layer according to the CommandEventArgs.GlobalCommandName value and handle the Editor.CommandEnded / CommandCancelled / CommandFailed to restore the previuous current layer.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 9

stefanveurink68AXD
Advocate
Advocate

Seems very helpfull, including this topic a found as well as the code that's referred to by Norman Yuan

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(CommandWillStartHandler.Commands))]
[assembly: ExtensionApplication(typeof(CommandWillStartHandler.Commands))]

namespace CommandWillStartHandler
{
    public class Commands : IExtensionApplication
    {
        private static string _savedLayer = null;
        private const string LINE_LAYER = "MyLine";

        #region IExtensionApplication Interface

        public void Initialize()
        {
            Document dwg = CadApp.DocumentManager.MdiActiveDocument;
            Editor ed = dwg.Editor;

            try
            {
                ed.WriteMessage("\nInitialising custom add-in...");
                AddCommandHandler();
                ed.WriteMessage("\nInitializing custom add-in completed.");
            }
            catch
            {
                ed.WriteMessage("\nInitializing custom add-in failed");
            }
            finally
            {
                Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
            }
        }

        public void Terminate()
        {

        }

        private void AddCommandHandler()
        {
            CadApp.DocumentManager.DocumentCreated += DocumentManager_DocumentCreated;

            foreach (Document d in CadApp.DocumentManager)
            {
                d.CommandWillStart += Document_CommandWillStart;
                d.CommandEnded += Document_CommandEnded;
                d.CommandCancelled += Document_CommandCancelled;
            }
        }

        private void DocumentManager_DocumentCreated(object sender, DocumentCollectionEventArgs e)
        {
            e.Document.CommandWillStart += Document_CommandWillStart;
            e.Document.CommandEnded += Document_CommandEnded;
            e.Document.CommandCancelled += Document_CommandCancelled;
        }

        private void Document_CommandEnded(object sender, CommandEventArgs e)
        {
            Document doc = CadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            ed.WriteMessage("\nCommand {0} ended.", e.GlobalCommandName);

            if (!string.IsNullOrEmpty(_savedLayer))
            {
                CadApp.SetSystemVariable("CLAYER", _savedLayer);
                _savedLayer = null;
            }
        }

        private void Document_CommandCancelled(object sender, CommandEventArgs e)
        {
            Document doc = CadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            ed.WriteMessage("\nCommand {0} cancelled.", e.GlobalCommandName);

            if (!string.IsNullOrEmpty(_savedLayer))
            {
                CadApp.SetSystemVariable("CLAYER", _savedLayer);
                _savedLayer = null;
            }
        }

        private void Document_CommandWillStart(object sender, CommandEventArgs e)
        {
            Document doc = CadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            ed.WriteMessage("\nCommand {0} will start.", e.GlobalCommandName);

            //Whenever "LINE" command starts, the active layer is set to
            //LINE_LAYER so that the line is drawn on that layer
            if (e.GlobalCommandName.ToUpper() == "LINE")
            {
                _savedLayer = CadApp.GetSystemVariable("CLAYER").ToString();
                CadApp.SetSystemVariable("CLAYER", LINE_LAYER);
            }
        }

        #endregion
    }
}

 

However when I literally insert this code into a new project and start debugging, nothing happens, saying, when I draw a line its not on the asked layer. 

 

Any idea what could be wrong?

0 Likes
Message 4 of 9

_gile
Consultant
Consultant

This works for me:

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;

using System;

using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;

namespace RegionToPolyline
{
    public class Initialization : IExtensionApplication
    {
        string prevLayer;
        const string LINE_LAYER = "MyLine";

        public void Initialize()
        {
            AcAp.Idle += OnIdle;
        }

        public void Terminate()
        { }

        private void OnIdle(object sender, EventArgs e)
        {
            AcAp.Idle -= OnIdle;
            var docs = AcAp.DocumentManager;
            foreach (Document doc in docs)
            {
                AddHandlers(doc);
            }
            docs.DocumentCreated += DocumentCreated;
        }

        private void AddHandlers(Document doc)
        {
            doc.CommandEnded += CommandEnded;
            doc.CommandCancelled += CommandEnded;
            doc.CommandFailed += CommandEnded;
            doc.CommandWillStart += CommandWillStart;
        }

        private void DocumentCreated(object sender, DocumentCollectionEventArgs e)
        {
            AddHandlers(e.Document);
        }

        private void CommandWillStart(object sender, CommandEventArgs e)
        {
            if (e.GlobalCommandName == "LINE")
            {
                prevLayer = AcAp.GetSystemVariable("clayer").ToString();
                AcAp.SetSystemVariable("clayer", LINE_LAYER);
            }
        }

        private void CommandEnded(object sender, CommandEventArgs e)
        {
            if (!string.IsNullOrEmpty(prevLayer))
            {
                AcAp.SetSystemVariable("clayer", prevLayer);
                prevLayer = null;
            }
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 9

stefanveurink68AXD
Advocate
Advocate

Must be something wrong with my C# skills then, I'm just starting to learn this language. 

 

What I did was put your code into a new class file in the project, with same namespace as the others. 

 

Then in the main function I create an instance of your class and call the instance.initialize(); function from your class. 

 

then at debugging, start autocad, netload to load the .dll, and startup the form. but nothing happens when drawing a line. layer stays zero. What am I forgetting?

Is this what I should do? Cause it still isn't working with me. Neither is just start an entire new project with your code because this give all kind of errors (expecting formload and stuff like that).  (By the way i also combined the initialize() and terminate() with the checkbox but didn't work either)

 

0 Likes
Message 6 of 9

_gile
Consultant
Consultant
Accepted solution

You do not have to create an instance of the class which implements IExtensionApplication. The Initialize() method of this class runs automatically when the application is loaded, i.e. it adds the handlers. Note thats this is not realted to your form.

 

Here's a more robust implementation in case the "MyLine" layer does not exists.

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;

using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;

namespace CommandWillStartHandler
{
    public class Initialization : IExtensionApplication
    {
        string prevLayer;
        const string LINE_LAYER = "MyLine";

        public void Initialize()
        {
            var docs = AcAp.DocumentManager;
            foreach (Document doc in docs)
            {
                AddHandlers(doc);
            }
            docs.DocumentCreated += DocumentCreated;
        }

        public void Terminate()
        { }

        private void DocumentCreated(object sender, DocumentCollectionEventArgs e)
        {
            AddHandlers(e.Document);
        }

        private void CommandWillStart(object sender, CommandEventArgs e)
        {
            if (e.GlobalCommandName == "LINE")
            {
                prevLayer = (string)AcAp.GetSystemVariable("clayer");
                try { AcAp.SetSystemVariable("clayer", LINE_LAYER); }
                catch { prevLayer = null; }
            }
        }

        private void CommandEnded(object sender, CommandEventArgs e)
        {
            if (!string.IsNullOrEmpty(prevLayer))
            {
                AcAp.SetSystemVariable("clayer", prevLayer);
                prevLayer = null;
            }
        }

        private void AddHandlers(Document doc)
        {
            doc.CommandEnded += CommandEnded;
            doc.CommandCancelled += CommandEnded;
            doc.CommandFailed += CommandEnded;
            doc.CommandWillStart += CommandWillStart;
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 9

stefanveurink68AXD
Advocate
Advocate

awesome! thanks a lot!

 

Indeed it seems like I don't have to create an instance of the class. One last short question therefore, if I want to put this into a checkbox, can I still do this by initialize when checked and terminate when not checked == false? Cause if I don't have to create an instance.... i don't see how it's turned on and off?

0 Likes
Message 8 of 9

_gile
Consultant
Consultant
Accepted solution

If you want to activate / deactivate the event handlers, you must not do all this stuff from the Initialze() method but from the handler of your CheckBox.

Something like this:

        private void CheckBox1_CheckedChanged(Object sender, EventArgs e)
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            if (checkBox1.Checked)
            {
                doc.CommandEnded += CommandEnded;
                doc.CommandCancelled += CommandEnded;
                doc.CommandFailed += CommandEnded;
                doc.CommandWillStart += CommandWillStart;
            }
            else
            {
                doc.CommandEnded -= CommandEnded;
                doc.CommandCancelled -= CommandEnded;
                doc.CommandFailed -= CommandEnded;
                doc.CommandWillStart -= CommandWillStart;
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 9

stefanveurink68AXD
Advocate
Advocate

Works Perfect. Thanks!

0 Likes