The last few posts have focused on the history of MDI in AutoCAD and how to store per-document data in ObjectARX applications. Now let’s take a look at what can be done for AutoCAD .NET applications...
There are two main approaches for storing per-document data in managed applications loaded into AutoCAD – I’ll take a look at the first in this entry and tackle the second technique next time.
Define commands as instance members of a class
In managed applications you can declare instance or static methods. Static methods are those specified as “static” in C# or “Shared” in VB.NET. Methods that are not shared/static are known as instance methods.
Static methods are “global” – they do not use data that is specific to an instance of the class they belong to. It’s common to call static methods directly from the class namespace (MyClass.myMethod()) rather than from specific instance of the class (myObject.myMethod()). To declare a method as static, you use the “static” keyword in C# and the “Shared” keyword in VB.NET.
Predictably enough, MSDN contains some good information on static classes and static class members.
Instance methods can be considered “local” in scope – they work on a specific instance of a class. A method not declared as static/Shared will be an instance method by default.
So what does this mean for us, as implementers of AutoCAD commands in .NET?
Here’s what the documentation says:
"For an instance command method, the method's enclosing type is instantiated separately for each open document. This means that each document gets a private copy of the command's instance data. Thus there is no danger of overwriting document-specific data when the user switches documents. If an instance method needs to share data globally, it can do so by declaring static or Shared member variables."
So to get the benefits of per-document data in a .NET application, you simply need to declare the relevant command(s) as instance (non-static). Here’s some sample C# code defining two separate commands: one is declared as static (accessing static data and even contained within a static class) while the other is an instance method:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
[assembly: CommandClass(typeof(CommandClasses.FirstClass))]
[assembly: CommandClass(typeof(CommandClasses.SecondClass))]
namespace CommandClasses
{
static public class FirstClass
{
private static int counter = 0;
[Autodesk.AutoCAD.Runtime.CommandMethod("glob")]
public static void global()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("\nCounter value is: " + counter++);
}
}
public class SecondClass
{
private int counter = 0;
[Autodesk.AutoCAD.Runtime.CommandMethod("loc")]
public void local()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("\nCounter value is: " + counter++);
}
}
}
Here’s what happens when you execute the two commands in two separate documents:
[From first drawing...]
Command: glob
Counter value is: 0
Command: glob
Counter value is: 1
Command: glob
Counter value is: 2
Command: loc
Counter value is: 0
Command: loc
Counter value is: 1
Command: loc
Counter value is: 2
Command: new
[From second drawing...]
Command: glob
Counter value is: 3
Command: glob
Counter value is: 4
Command: glob
Counter value is: 5
Command: loc
Counter value is: 0
Command: loc
Counter value is: 1
Command: loc
Counter value is: 2
So you can see that when you create and switch to a new document, the “glob” command (a static method) continues counting from where it left off. The “loc” command (an instance method) starts from zero, as a new instance of its command class has been created.
If you choose to mix static and instance methods & data in your class, then you will need to be a little careful about making sure the data gets initialized at the right time and place. In the above example I’ve kept things separate and have simply used variable initialization to specify the initial values for the two counters – you will probably want to define your own constructors (static or instance) if you have more complex scenarios to deal with.
In my next post I’ll take a look at the Document.UserData container, the alternative approach to managing per-document data in an AutoCAD .NET application.