.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Send Command Executes after exiting command method

25 REPLIES 25
Reply
Message 1 of 26
chockalingam
5970 Views, 25 Replies

Send Command Executes after exiting command method

Hi,

  I used send command for Export Layout

  But the line only executes after exiting command method.

 Can anyone help in this case.

 

thanks in advance.

25 REPLIES 25
Message 2 of 26

SendCommand is asynchronous, and works that way.

 

If you are on a version of AutoCAD that uses .NET 3.5 or later, you can use this wrapper for RunCommand

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using Autodesk.AutoCAD.ApplicationServices;
 
namespace Autodesk.AutoCAD.EditorInput
{
   public static class EditorInputExtensionMethods
   {
      public static PromptStatus Command( this Editor editor, params object[] args )
      {
         if( editor == null )
            throw new ArgumentNullException( "editor" );
         return runCommand( editor, args );
      }
 
      static Func<Editor, object[], PromptStatus> runCommand = GenerateRunCommand();
 
      static Func<Editor, object[], PromptStatus> GenerateRunCommand()
      {
         MethodInfo method = typeof( Editor ).GetMethod( "RunCommand", 
            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public );
         var instance = Expression.Parameter( typeof( Editor ), "instance" );
         var args = Expression.Parameter( typeof( object[] ), "args" );
         return Expression.Lambda<Func<Editor, object[], PromptStatus>>(
            Expression.Call( instance, method, args ), instance, args )
               .Compile();
      }
   }
}
 
 

 

With the above code, you can use this:

 

   Document doc = Application.DocumentManager.MdiActiveDocument;

   Editor editor = doc.Editor;

   editor.Command( "._EXPORTLAYOUT", "filename-goes-here" );

 

 

Message 3 of 26
chockalingam
in reply to: chockalingam

Included the wrapper. Even now it is not working.

 

Following is the code i'm using,

 

 

Document doc = Application.DocumentManager.MdiActiveDocument;
Database AcDb = doc.Database;
using (Transaction tr = AcDb.TransactionManager.StartTransaction())
{
LayoutManager AcLtMgr = LayoutManager.Current;
DBDictionary layoutDic = tr.GetObject(AcDb.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
ObjectId layoutId;
Layout layout;
foreach (DBDictionaryEntry entry in layoutDic)
{

layoutId = entry.Value;
layout = tr.GetObject(layoutId, OpenMode.ForRead) as Layout;
if (!layout.LayoutName.Equals("Model"))
{
LayoutManager.Current.CurrentLayout = layout.LayoutName;

string filename = Path.Combine(Path.GetTempPath(), layout.LayoutName + ".dwg");
Editor editor = doc.Editor;
editor.Command("._EXPORTLAYOUT", filename);
}
}
tr.Commit();
}

Message 4 of 26

Sorry, I'm not sure what "not working" means.

 

What exactly happens?

 

 

 

Message 5 of 26

HI,

  Sorry, for not explaining clearly.

  I am trying to export the layout to new drawing.

  So, I used ExpotLayout.

  But i'm not getting the output file.

Message 6 of 26

The Command() method shouldn't be used inside an active Transaction, so first, commit the transaction before you use the Command() method. You can also skip all of that code that gets the current layout name by just reading the CTAB system variable, and do away with the use of the transaction entirely.

When using the Command() method, you are basically using a managed wrapper for the LISP (command) function, so the CMDECHO system variable should be set to 0 under normal use, but should be set to 1 when you're debugging so that you can see the prompts issued by the commands. Try running the code with CMDECHO set to 1 and see what the command is doing.

Message 7 of 26

Just to be sure there wasn't a problem with my wrapper for RunCommand, I added your use case to the set of tests and examples I have for it.

 

Here's a working example:

 

/// ExportLayouts.cs  (c) 2013  Tony Tanzillo
/// 
/// AutoCAD.NET API sample that automates
/// the EXPORTLAYOUT command to export all
/// layouts in the current document.
/// 
/// This example requires EditorExtensions.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

namespace ExportLayoutsExample
{
   public static class ExportLayoutsCommands
   {
      /// 
      /// Automates the EXPORTLAYOUT command to export 
      /// all paper space layouts to .DWG files.
      /// 
      /// In this example, we export each layout to
      /// a drawing file in the same location as the
      /// current drawing, wherein each file has the
      /// name "_.dwg".
      /// 
      /// This is not a functionally-complete example:
      /// 
      /// No checking is done to see if any of the 
      /// files already exist, and existing files 
      /// are overwritten without warning or error.
      /// 
      /// No checking is done to detect if an existing
      /// file exists and is in-use by another user, or 
      /// cannot be overwritten for any other reason.
      /// 
      /// No checking is done to ensure that the user
      /// has sufficient rights to write files in the
      /// target location.
      /// 
      /// You can and should deal with any or all of
      /// the above as per your own requirements.
      /// 
      /// 

      [CommandMethod( "EXPORTLAYOUTS" )]
      public static void ExportLayoutsCommand()
      {
         var doc = Application.DocumentManager.MdiActiveDocument;
         var db = doc.Database;
         var editor = doc.Editor;
         try
         {
            if( (short) Application.GetSystemVariable( "DWGTITLED" ) == 0 )
            {
               editor.WriteMessage(
                  "\nCommand cannot be used on an unnamed drawing"
               );
               return;
            }
            string format =
               Path.Combine(
                  Path.GetDirectoryName( doc.Name ),
                  Path.GetFileNameWithoutExtension( doc.Name ) )
               + "_{0}.dwg";

            string[] layoutNames = null;

            using( Transaction tr = doc.TransactionManager.StartTransaction() )
            {
               // Get the localized name of the model tab:
               BlockTableRecord btr = (BlockTableRecord)
                  SymbolUtilityServices.GetBlockModelSpaceId( db )
                     .GetObject( OpenMode.ForRead );
               Layout layout = (Layout)
                  btr.LayoutId.GetObject( OpenMode.ForRead );
               string model = layout.LayoutName;
               // Open the Layout dictionary:
               IDictionary layouts = (IDictionary)
                  db.LayoutDictionaryId.GetObject( OpenMode.ForRead );
               // Get the names of all paper space layouts into a list:
               layoutNames = layouts.Keys.Cast()
                  .Where( name => name != model ).ToArray();

               tr.Commit();
            }

            int cmdecho = 0;
#if DEBUG
            cmdecho = 1;
#endif
            using( new ManagedSystemVariable( "CMDECHO", cmdecho ) )
            using( new ManagedSystemVariable( "CMDDIA", 0 ) )
            using( new ManagedSystemVariable( "FILEDIA", 0 ) )
            using( new ManagedSystemVariable( "CTAB" ) )
            {
               foreach( string name in layoutNames )
               {
                  string filename = string.Format( format, name );
                  editor.WriteMessage( "\nExporting {1}\n", name, filename );
                  Application.SetSystemVariable( "CTAB", name );
                  editor.Command( "._EXPORTLAYOUT", filename );
               }
            }
         }
         catch( System.Exception ex )
         {
#if DEBUG
            editor.WriteMessage( ex.ToString() );
#else
            throw ex;
#endif
         }
      }
   }

   public static class EditorInputExtensionMethods
   {
      public static PromptStatus Command( this Editor editor, params object[] args )
      {
         if( editor == null )
            throw new ArgumentNullException( "editor" );
         return runCommand( editor, args );
      }

      static Func<Editor, object[], PromptStatus> runCommand = GenerateRunCommand();

      static Func<Editor, object[], PromptStatus> GenerateRunCommand()
      {
         MethodInfo method = typeof( Editor ).GetMethod( "RunCommand",
            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public );
         var instance = Expression.Parameter( typeof( Editor ), "instance" );
         var args = Expression.Parameter( typeof( object[] ), "args" );
         return Expression.Lambda<Func<Editor, object[], PromptStatus>>(
            Expression.Call( instance, method, args ), instance, args )
               .Compile();
      }
   }


   /// 
   /// Automates saving/changing/restoring system variables
   /// 
   
   public class ManagedSystemVariable : IDisposable
   {
      string name = null;
      object oldval = null;

      public ManagedSystemVariable( string name, object value )
         : this( name )
      {
         Application.SetSystemVariable( name, value );
      }

      public ManagedSystemVariable( string name )
      {
         this.name = name;
         this.oldval = Application.GetSystemVariable( name );
      }

      public void Dispose()
      {
         if( oldval != null )
         {
            object temp = oldval;
            oldval = null;
            Application.SetSystemVariable( name, temp );
         }
      }
   }

}

 

Message 8 of 26
Hallex
in reply to: DiningPhilosopher

Press F1 and see about EXPORTLAYOUT command,
seems to me this will not working from comand line
Or I'm missed something again?
_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 9 of 26
DiningPhilosopher
in reply to: Hallex


@Hallex wrote:
Press F1 and see about EXPORTLAYOUT command,
seems to me this will not working from comand line
Or I'm missed something again?

In recent releases it is implemented in managed code, and can be called via LISP's (command) function.

Message 10 of 26

The above posted code will not compile as-is because the Autodesk discussion group server has mangled the code  (removing some angle braces).

 

A copy that actually compiles can be found here:

 

    http://www.theswamp.org/index.php?topic=44472.0

Message 11 of 26

hi DiningPhilosopher:

I run the command exportlayouts, but failed to export a dwg file.

Is there any contition to use the wrapper method?

the system?or vs version? i am in win7x64+vs2010+.net4.0+autocad2013

Regards

swaywood

Message 12 of 26
_gile
in reply to: swaywood

It works fine for me on Windows 7 64 bits, AutoCAD 2013 after compiling in VS 2010 (Any CPU).



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 13 of 26
swaywood
in reply to: _gile

it was NEXTFIBERWORLD confusing me a long time.
after change nextfiberworld value to 1, everything done well.
Message 14 of 26

thanks, It is truly a genius solution
Message 15 of 26
wshehada
in reply to: wshehada

It works fine for me on Windows 7 64 bits, AutoCAD 2014 after compiling in VS 2012 (Any CPU)
but in AutoCAD 2017 not works, any solution
Message 16 of 26
swaywood
in reply to: wshehada

in autocad 2016 not work too

Message 17 of 26
_gile
in reply to: swaywood


swaywood a écrit :

in autocad 2016 not work too


Since AutoCAD 2015 you have to use the Editor.Command() (or CommandAsync()) method instead of the wrapper of Editor.Runcommand() provided by tony Tanzillo.

See these threads:

http://through-the-interface.typepad.com/through_the_interface/2014/03/autocad-2015-calling-commands...

https://www.theswamp.org/index.php?topic=49124.msg542370#msg542370



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 18 of 26
ActivistInvestor
in reply to: _gile

@_gile wrote:

swaywood a écrit :

in autocad 2016 not work too


Since AutoCAD 2015 you have to use the Editor.Command() (or CommandAsync()) method instead of the wrapper of Editor.Runcommand() provided by tony Tanzillo.

See these threads:

http://through-the-interface.typepad.com/through_the_interface/2014/03/autocad-2015-calling-commands...

https://www.theswamp.org/index.php?topic=49124.msg542370#msg542370


 

Hi @_gile, regarding your swamp post:


The last shown behavior is interesting, for example, to pass a list of arguments to a command (e.g. a points list for LINE, PLINE, SPLINE).
This also requires the CommandAsync using.

 

public async void Cmd3()
{
   Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
   Point2d[] pts = 
   { 
       new Point2d(0.0, -10.0), 
       new Point2d(10.0, 0.0), 
       new Point2d(0.0, 10.0), 
       new Point2d(-10.0, 0.0) 
   };
   await ed.CommandAsync("_.PLINE");
   foreach (Point2d pt in pts)
   {
       await ed.CommandAsync(pt);
   }
   await ed.CommandAsync("_close");
   ZoomEntLast();
}


 


 

This is not true at all.

 

When a method takes a variable number of arguments of a specific type, you can pass individual arguments separated by commas, or you can pass all arguments in a single array of the same type as the params array.

 

 

   [CommandMethod("COMMANDARGS")]
   public static void GilesCommandExample()
   {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
      Point2d[] points = 
      { 
         new Point2d(0.0, -10.0), 
         new Point2d(10.0, 0.0), 
         new Point2d(0.0, 10.0), 
         new Point2d(-10.0, 0.0) 
      };
      object[] args = 
         new object[] {"._PLINE"}
            .Concat(points.Cast<Object>())
            .Concat(new [] {"", "._ZOOM", "_Extents"})
            .ToArray();

      // For any type 'T', if a method takes a 'params T[] args', 
      // you can pass individual arguments of type T, or you can 
      // pass all arguments contained in a single array of T[]:

      ed.Command(args);
   }

 

 

 But we can make things a bit easier as well:

 

 

 

   public static class MyCommandHelpers
   {

      public static object[] BuildList(this Editor editor, params object[] args)
      {
         return BuildListWorker(args).ToArray();
      }

      static IEnumerable<object> BuildListWorker(IEnumerable args)
      {
         if(args != null)
         {
            foreach(object o in args)
            {
               if(o != null)
               {
                  IEnumerable items = o as IEnumerable;
                  if(items != null && !(items is string))
                  {
                     foreach(object item in BuildListWorker(items))
                     {
                        yield return item;
                     }
                  }
                  else
                     yield return o;
               }
            }
         }
      }
   }
   
   

   [CommandMethod("COMMANDARGS2")]
   public static void CommandExample2()
   {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
      Point2d[] points = 
      { 
         new Point2d(0.0, -11.0), 
         new Point2d(11.0, 0.0), 
         new Point2d(0.0, 11.0), 
         new Point2d(-11.0, 0.0) 
      };

      ed.Command(ed.BuildList("._PLINE", points, "", "._ZOOM", "_Extents"));
   }

 

BuildList() works with any type of IEnumerable, for example:

 

 

   
[CommandMethod("CHANGETORED")] public static void CommandArgs3() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; var psr = ed.GetSelection(); if(psr.Status == PromptStatus.OK) { ed.Command(ed.BuildList("._CHPROP", psr.Value.GetObjectIds(), "", "color", 1, "")); } }

 

 

 

Message 19 of 26
_gile
in reply to: ActivistInvestor

Hi, @ActivistInvestor

 

You're right about the possibility of building an array to pass a collection of points to Command(). My purpose was more to compare Command() vs CommandAsync() than to explain how the params keyword works.

That said, it seems to me you are not completely right. According to my tests, when you do:

ed.Command (ed.BuildList ("._ PLINE", points, "", "._ZOOM", "_Extents"));

The command stops after drawing the polyline and does not zoom.

 

This does work as expected:

await ed.CommandAsync("_.pline");
 foreach (var pt in points)
    await ed.CommandAsync(pt);
await ed.CommandAsync("", "_.zoom", "_extents");

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 20 of 26
ActivistInvestor
in reply to: _gile


@_gile wrote:

Hi, @ActivistInvestor

 

You're right about the possibility of building an array to pass a collection of points to Command(). My purpose was more to compare Command() vs CommandAsync() than to explain how the params keyword works.

That said, it seems to me you are not completely right. According to my tests, when you do:

ed.Command (ed.BuildList ("._ PLINE", points, "", "._ZOOM", "_Extents"));

The command stops after drawing the polyline and does not zoom.

 

This does work as expected:

await ed.CommandAsync("_.pline");
 foreach (var pt in points)
    await ed.CommandAsync(pt);
await ed.CommandAsync("", "_.zoom", "_extents");

 


Hi @_gile

 

I wrote that example without testing it, and yes the ZOOM requires a separate call to Command() that follows the one that starts and ends PLINE, but the use of additional commands after finishing PLINE wasn't really what this is about.

 

It is about being able to build an array containing a variable number of arguments and passing that array in a single call to Command() rather than having to express each argument literally, which doesn't require the use of CommandAsync() at all. 

 

So, a more-correct example would use a second call to Command() for running each subsequent command, still not requiring any use of CommandAsync().

 

After searching this discussion group, I see that many seem to be confused about this, and are using CommandAsync() in cases where it isn't really needed. The only case where one really needs to use CommandAsync() is one where there is a pause for user input (something I would never do), or a case where not all of the arguments are known at the point when the command starts. IOW, the need for CommandAsync() is actually quite rare. 

 

It's helpful to illustrate the differences between the two methods. Although I think it would be even more helpful to demonstrate the use of CommandAsync() in a case where it is actually necessary. And, because I don't ever pause for user input in the middle of a command, I'm at a loss to come up with any other use case where it would be needed.

 

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost