Hello everybody !
My first post here ;)
Many thanks to everybody reading it ;)
Context :
- AutoCAD Map 2013
- Visual Studio 2010
- .NET, C#, WPF
- FDO
- Oracle DataStore
Business Requirement :
The application manages some objects (features), containing business attributes and a geometry attribute (in an FDO meaning).
One of these business attributes should contain the length of the item drawn under AutoCAD Map.
If a user wants to modify the geometry of one of these items (by moving vertices for example), he must check out the feature of its choice (a polyline, or a point).
Then he can update the geometry of the feature, and finally, he has to check in the feature to store it permanently.
When checking-in the feature, I need to get the new length of the polyline (or new coordinates of a point for example), and I need to update the appropriate business attribute of the relevant object with the new length.
My technical implementation, not working :
I've handled the CommandEventHandler "CommandEnded" of the Document Object (Autodesk.AutoCAD.ApplicationServices.Document). This event is raised when an AutoCAD Map Command has ended. In this handler, I test the GlobalCommandName of the Event Argument. I test "MAPCANCELCHECKOUT", "MAPCHECKOUT" and "MAPCHECKINALL".
- When MAPCHECKOUT has finished : I need to retrieve all of the objects that have been selected. I put each of them in a Dictionary, where the Key is the ObjectId (Autodesk.AutoCAD.DatabaseServices.ObjectId) and the Value is the relevant Business Object (in my own Application).
- When MAPCHECKINALL has finished : I need to browse all Checked-Out entries of my Dictionary. Using the ObjectId (the Key), I try to get the new Length of the Polyline (or Coordinates for a Point). and I need to get this value and update the relevant Business Object (the Value). But when I call transaction.GetObject(key, OpenMode.ForRead, true), it always throws an Exception of type "ePermanentlyErased". So, in other words, I'm unable to get the new Length of any checked-out Polyline (Object, Entity, Curve, etc...).
void doc_CommandEnded(object sender, CommandEventArgs e)
{
Document doc = (Document)sender;
Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
switch (e.GlobalCommandName)
{
case "MAPCANCELCHECKOUT":
CancelCheckOut();
break;
case "MAPCHECKOUT":
DoCheckOut();
break;
case "MAPCHECKINALL":
DoCheckIn();
break;
default:
break;
}
ed.WriteMessage("\nCommand ended : [" + e.GlobalCommandName + "]");
}
Dictionary<ObjectId, TakmGenericObject> __objectsIdToTakmGenericObjectsCheckedOut = new Dictionary<ObjectId, TakmGenericObject>();
public void DoCheckOut()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
PromptSelectionResult result = ed.GetSelection();
SelectionSet selSet = result.Value;
AcMapMap currentMap = AcMapMap.GetCurrentMap();
MgLayerCollection layers = currentMap.GetLayers();
Database db = doc.Database;
using (Transaction acTrans = db.TransactionManager.StartTransaction())
{
foreach (SelectedObject selObj in selSet)
{
// Check to make sure a valid SelectedObject object was returned
if (selObj != null)
{
// Open the selected object for write
SelectionSet selSet2 = SelectionSet.FromObjectIds(new ObjectId[1] { selObj.ObjectId });
AcMapSelection sel = (AcMapSelection)AcMapFeatureEntityService.GetSelection(selSet2);
foreach (MgLayerBase layer in layers)
{
Int32 iCount = sel.GetSelectedFeaturesCount(layer, layer.FeatureClassName);
if (iCount>0)
{
// Getting Relevant Business Object
MgFeatureReader reader = sel.GetSelectedFeatures(layer, layer.FeatureClassName, false);
Collection<Object> ids = new Collection<Object>();
while (reader.ReadNext())
{
Int64 id = reader.GetInt64("ID");
ids.Add(id);
ed.WriteMessage("\nID: " + id);
}
String shortName = (layer.FeatureClassName.Contains(':') ? layer.FeatureClassName.Substring(layer.FeatureClassName.IndexOf(':') + 1) : layer.Name);
TakmGenericObjectCollection<TakmGenericObject> goCollection = new TakmGenericObjectCollection<TakmGenericObject>();
goCollection.Descriptor = TakmGenericObjectDescriptorDictionary.Instance.GetFirstGenericObjectDescriptorByTableName(shortName);
if (goCollection.Descriptor != null)
{
goCollection.SelectWherein("ID", ids);
foreach (TakmGenericObject genericObject in goCollection)
{
// Putting Key-Value into Dictionary
__objectsIdToTakmGenericObjectsCheckedOut.Add(selObj.ObjectId, genericObject);
}
}
}
}
}
}
}
}
public void DoCheckIn()
{
Collection<ObjectId> unlocked = new Collection<ObjectId>();
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
using (Transaction acTrans = db.TransactionManager.StartTransaction())
{
foreach (KeyValuePair<ObjectId, TakmGenericObject> kvp in __objectsIdToTakmGenericObjectsCheckedOut)
{
FeatureToDraw feature = new FeatureToDraw();
try
{
//
//
//
DBObject dbObj = acTrans.GetObject(kvp.Key, OpenMode.ForRead, true);
// ---> this line always generate exception!
//
//
Polyline pl = dbObj as Polyline;
if (pl != null)
{
feature.Length = pl.Length;
}
Curve crv = dbObj as Curve;
if (crv != null)
{
feature.Length = crv.GetDistanceAtParameter(crv.EndParam) - crv.GetDistanceAtParameter(crv.StartParam);
}
TakmGenericObject genericObject = kvp.Value;
if (genericObject.Descriptor != null)
{
// Updating Business attributes of Business Objects
// new length, new coordinates
// blablabla...
}
}
catch (System.Exception ex)
{
TakmLogger.Instance.LogError(__classFullName + "DoCheckIn", ex.Message);
if (ex.InnerException != null)
{
TakmLogger.Instance.LogError(__classFullName + "DoCheckIn", ex.InnerException.Message);
}
}
}
}
foreach (ObjectId objId in unlocked)
{
__objectsIdToTakmGenericObjectsCheckedOut.Remove(objId);
}
}
Can someone help me please ?
Do I had made the good choice ?
Is there any best practice regarding my needs ?
Thank you very much.
tom.