Aller au contenu

Messages recommandés

Posté(e)

Bonjour,

 

Dans ma solution C#, j'ai :

- un projet qui contient des fonctions génériques de manipulation des calques : Ajout d'un calque, Affectation d'une couleur à un calque ...

   public static void AddLayer(string sLayerName)
   {

     Document doc = Application.DocumentManager.MdiActiveDocument;
     Database db = doc.Database;

     // Vérifie que le nom du calque est correct
     if (string.IsNullOrEmpty(sLayerName)) return;

     using (Transaction tr = db.TransactionManager.StartTransaction())[/size]
     {
       LayerTable ltb = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
       try
       {
         //create a new layer.
         if (!ltb.Has(sLayerName))
         {
           ltb.UpgradeOpen();
           // Nouveau calque
           LayerTableRecord newLayer = new LayerTableRecord();
           // Nom du calque
           newLayer.Name = sLayerName;

           ltb.Add(newLayer);
           tr.AddNewlyCreatedDBObject(newLayer, true);
         }

         tr.Commit();
       }
       catch { tr.Abort(); }
     }
   }


   public static void SetColorLayer(string sLayerName, int iColorIndex)
   {
     Document acDoc = Application.DocumentManager.MdiActiveDocument;
     Database acCurDB = acDoc.Database;

     // Vérifie que le nom du calque est correct
     if (string.IsNullOrEmpty(sLayerName)) return;
     // Vérifie que la couleur est [1,255]
     if (iColorIndex <= 0 || iColorIndex >= 256) return;

	// Vérifie que le calque existe[/size]
     using (Transaction tr = acCurDB.TransactionManager.StartTransaction())
     {
       try
       {
         LayerTable acLayTbl = (LayerTable)tr.GetObject(acCurDB.LayerTableId, OpenMode.ForRead);
         //Vérifie si le calque existe
         if (acLayTbl.Has(sLayerName))
         {
           LayerTableRecord acLayTblRec = (LayerTableRecord)tr.GetObject(acLayTbl[sLayerName], OpenMode.ForWrite);
           acLayTblRec.Color = Color.FromColorIndex(ColorMethod.ByAci, (short)iColorIndex);
         }
         tr.Commit();
       }
       catch { tr.Abort(); }
     }
   }

 

 

- un projet avec un dialogue Modeless qui appelle ces fonctions sur un clic de bouton

using (DocumentLock lk = _doc.LockDocument())
{
 AddLayer("TOTO");
 SetColorLayer("TOTO", 3);
}

 

Le problème, c'est que le AddLayer se passe bien (a priori), mais que dans le SetColorLayer, je passe bien dans le test (acLayTbl.Has(sLayerName)) car l'entrée existe bien, mais lorsque j'essaie d'ouvrir en mode ForWrite mon LayerTableRecord je passe dans le Catch avec le message eWasErased.

 

Si mon dialogue est Modal ou si je rajoute dans mes fonctions de gestion de calque un verrouillage de mon Document, ça fonctionne.

 

Ce que je ne comprends pas c'est pourquoi avec mon document verrouillé avant l'appel de la fonction, il n'est plus verrouillé à l'intérieur.

 

Merci

 

Olivier

Posté(e)

Bon, ça n'a rien avoir avec le verrouillage du document.

En fait avant de lancer ma fonction, je faisais une Purge de mes calques et dans ce cas, au niveau de la DB, le calque existe mais il est marqué Erased, donc l'affectation d'une couleur à un calque qui existe mais a été supprimé génère l'erreur.

 

Olivier

Posté(e)

Le catch { tr.Abort(); } ne sert à rien puisque si une exception survient, ton code ne passe jamais sur la ligne tr.Commit et donc le tr.Abort est automatiquement appelé lorsqu'on sort du bloc using.

 

En plus faire un catch qui attrape toutes les exceptions, c'est une très mauvaise idée.

Maxence DELANNOY

Développement de compléments aux logiciels Autodesk : AutoCAD, Revit, Inventor, Vault, Navisworks... et autres logiciels de CAO

WIIP - http://wiip.fr

Posté(e)

Merci pour le retour, je m'étais inspiré de certains morceaux de code du blog de Kean Walmsley qui utilisait cette syntaxe

       // Now let's create the leader itself
     Transaction tr = db.TransactionManager.StartTransaction();
     using (tr)
     {
       try
       {
         BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
         BlockTableRecord btr =
           (BlockTableRecord)tr.GetObject(bt[blockTableRecord.ModelSpace], OpenMode.ForWrite);

         // Add the MText
         MText mt = new MText();
         mt.Contents = "Leader with the \"" + arrowName +  "\" arrow head";
         mt.Location = endPt;
         ObjectId mtId = btr.AppendEntity(mt);
         tr.AddNewlyCreatedDBObject(mt, true);

         // Add the Leader
         Leader ld = new Leader();
         ld.AppendVertex(startPt);
         ld.AppendVertex(endPt);
         btr.AppendEntity(ld);
         tr.AddNewlyCreatedDBObject(ld, true);
         ld.Annotation = mtId;
         ld.Dimldrblk = arrId;

         tr.Commit();
       }
       catch
       {
         tr.Abort();
       }
     }

 

 

Ceci dit j'ai toujours mon problème de manipulation des calques après la commande PURGER.

- je démarre un dessin vierge:

- je lance mon programme (il ne fait que créer un calque et lui affecter la couleur 2)

     AddLayer("toto");
	SetColorLayer("toto", 2);

 

ça fonctionne.

 

- je purge le calque que je viens de créer (commande purger d'AutoCAD)

- je relance le programme

la création du calque se fait avec la couleur 7

et ça échoue à l'affectation de la couleur.

J'ai toujours eWasErased comme Autodesk.AutoCAD.Runtime.Exception

   public static void SetColorLayer(string sLayerName, int iColorIndex)
   {
     Document acDoc = Application.DocumentManager.MdiActiveDocument;
     Database acCurDB = acDoc.Database;
     Editor acEd = acDoc.Editor;

     // Vérifie que le nom du calque est correct
     if (string.IsNullOrEmpty(sLayerName)) return;
     // Vérifie que la couleur est [1,255]
     if (iColorIndex <= 0 || iColorIndex >= 256) return;

     // Vérifie que le calque existe
     using (Transaction tr = acCurDB.TransactionManager.StartTransaction())
     {
       try
       {
         LayerTable acLayTbl = (LayerTable)tr.GetObject(acCurDB.LayerTableId, OpenMode.ForRead);
         //Vérifie si le calque existe
         if (acLayTbl.Has(sLayerName))
         {
           LayerTableRecord acLayTblRec = (LayerTableRecord)tr.GetObject(acLayTbl[sLayerName], OpenMode.ForWrite);
           acLayTblRec.Color = Color.FromColorIndex(ColorMethod.ByAci, (short)iColorIndex);
         }
         tr.Commit();
       }
       catch (Autodesk.AutoCAD.Runtime.Exception err) { acEd.WriteMessage("\n" + err.Message); } //
     }
   }

 

 

Je n'y comprends plus rien.

 

Merci

 

Olivier

Posté(e)

J'avance doucement, mais ça m'inquiète un peu. Je suis reparti des exemples fournies dans l'aide AutoCAD .Net et j'ai le même plantage avec l'exemple fourni:

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Colors;

   [CommandMethod("SetLayerColor")]
   public static void SetLayerColor()
   {
     // Get the current document and database
     Document acDoc = Application.DocumentManager.MdiActiveDocument;
     Database acCurDb = acDoc.Database;

     // Start a transaction
     using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
     {
       // Open the Layer table for read
       LayerTable acLyrTbl;
       acLyrTbl = acTrans.GetObject(acCurDb.LayerTableId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead) as LayerTable;

       // Define an array of layer names
       string sLayerName = "CENTER";

       // Add or change each layer in the drawing
       LayerTableRecord acLyrTblRec;

       if (acLyrTbl.Has(sLayerName) == false)
       {
         acLyrTblRec = new LayerTableRecord();

         // Assign the layer a name
         acLyrTblRec.Name = sLayerName;

         // Upgrade the Layer table for write
         if (acLyrTbl.IsWriteEnabled == false) acLyrTbl.UpgradeOpen();

         // Append the new layer to the Layer table and the transaction
         acLyrTbl.Add(acLyrTblRec);
         acTrans.AddNewlyCreatedDBObject(acLyrTblRec, true);
       }
       else
       {
         // Open the layer if it already exists for write
         acLyrTblRec = acTrans.GetObject(acLyrTbl[sLayerName], Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite) as LayerTableRecord;
       }

       // Set the color of the layer
       acLyrTblRec.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 1);


       // Save the changes and dispose of the transaction
       acTrans.Commit();
     }
   }


   [CommandMethod("SetLayerLinetype")]
   public static void SetLayerLinetype()
   {
     // Get the current document and database
     Document acDoc = Application.DocumentManager.MdiActiveDocument;
     Database acCurDb = acDoc.Database;

     // Start a transaction
     using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
     {
       // Open the Layer table for read
       LayerTable acLyrTbl;
       acLyrTbl = acTrans.GetObject(acCurDb.LayerTableId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead) as LayerTable;

       string sLayerName = "CENTER";
       LayerTableRecord acLyrTblRec;

       if (acLyrTbl.Has(sLayerName) == false)
       {
         acLyrTblRec = new LayerTableRecord();

         // Assign the layer a name
         acLyrTblRec.Name = sLayerName;

         // Upgrade the Layer table for write
         acLyrTbl.UpgradeOpen();

         // Append the new layer to the Layer table and the transaction
         acLyrTbl.Add(acLyrTblRec);
         acTrans.AddNewlyCreatedDBObject(acLyrTblRec, true);
       }
       else
       {
         acLyrTblRec = acTrans.GetObject(acLyrTbl[sLayerName], Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead) as LayerTableRecord;
       }

       // Open the Layer table for read
       LinetypeTable acLinTbl;
       acLinTbl = acTrans.GetObject(acCurDb.LinetypeTableId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead) as LinetypeTable;

       if (acLinTbl.Has("CACHE") == true)
       {
         // Upgrade the Layer Table Record for write
         acLyrTblRec.UpgradeOpen();

         // Set the linetype for the layer
         acLyrTblRec.LinetypeObjectId = acLinTbl["CACHE"];
       }

       // Save the changes and dispose of the transaction
       acTrans.Commit();
     }
   }

 

La première commande crée un calque nommé CENTER et lui affecte la couleur ROUGE

La seconde commande affecte le type de ligne CACHE au calque CENTER

 

Je démarre un dessin vierge, je charge le type de ligne CACHE.

Je lance les fonctions

SetLayerColor

puis

SetLayerLinetype

=> OK ça crée un calque CENTER couleur ROUGE et type de ligne CACHE

Je lance la commande PURGER et je purge le calque CENTER

Je relance les fonctions

 

SetLayerColor =>OK

puis

SetLayerLinetype => Erreur eWasErase

 

Ça me rassure, je ne suis pas complètement fou, mais ça ne fait pas avancer le schmilblic!

 

Olivier

Posté(e)

J'ai la haine. Le problème se pose sous AutoCAD MAP 2007, MAP 2008 (peut-être MAP 2009) mais plus à partir de MAP 2010.

 

Si quelqu'un a une solution pour faire fonctionner ça sur une version d'AutoCAD 2008 (ou 2007), je suis preneur.

 

Merci

 

Olivier

Posté(e)

Salut Olivier,

 

J'ai testé avec VS2008 et AutoCAD 2007 et confirme ce bug (comment appeler ça autrement ?).

Quand on recrée le calque purgé, il semble valide : Objectid.IsErased est false, mais impossible le ré-ouvrir dans une autre transaction : ObjectId.IsErased est devenu true !

Je n'ai pas trouvé comment contourner ceci et il probable qu'Autodesk ne se penche pas sur une question qui concerne des versions dont il n'assurent plus le support...

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Merci Gilles d'avoir pris le temps de vérifier ce problème.

Comme on travaille sur des versions 2007 à 2012, je suis un peu obligé de prévoir les différents cas.

Je vais m'arranger autrement pour créer mes calques, et contrôler plus finement les erreurs sur mes transactions pour les calques.

 

Olivier

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité