Olivier Eckmann Posté(e) le 18 décembre 2013 Posté(e) le 18 décembre 2013 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
Olivier Eckmann Posté(e) le 18 décembre 2013 Auteur Posté(e) le 18 décembre 2013 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
Maxence DELANNOY Posté(e) le 18 décembre 2013 Posté(e) le 18 décembre 2013 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 DELANNOYDéveloppement de compléments aux logiciels Autodesk : AutoCAD, Revit, Inventor, Vault, Navisworks... et autres logiciels de CAOWIIP - http://wiip.fr
Olivier Eckmann Posté(e) le 18 décembre 2013 Auteur Posté(e) le 18 décembre 2013 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 programmela création du calque se fait avec la couleur 7et ç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
Olivier Eckmann Posté(e) le 18 décembre 2013 Auteur Posté(e) le 18 décembre 2013 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 ROUGELa 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 fonctionsSetLayerColorpuisSetLayerLinetype=> OK ça crée un calque CENTER couleur ROUGE et type de ligne CACHEJe lance la commande PURGER et je purge le calque CENTERJe relance les fonctions SetLayerColor =>OKpuisSetLayerLinetype => Erreur eWasErase Ça me rassure, je ne suis pas complètement fou, mais ça ne fait pas avancer le schmilblic! Olivier
Olivier Eckmann Posté(e) le 18 décembre 2013 Auteur Posté(e) le 18 décembre 2013 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
(gile) Posté(e) le 19 décembre 2013 Posté(e) le 19 décembre 2013 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
Olivier Eckmann Posté(e) le 19 décembre 2013 Auteur Posté(e) le 19 décembre 2013 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
Messages recommandés
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 compteSe connecter
Vous avez déjà un compte ? Connectez-vous ici.
Connectez-vous maintenant