Hi.
I have added 2 event handlers in the main class of my app:
class Start_app : Autodesk.AutoCAD.Runtime.IExtensionApplication { #region IExtensionApplication Members public void Initialize() //hace de constructor sobre la clase. { Document acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; acDoc.Database.ObjectModified += MainForm.callback_ObjectModified; acDoc.Editor.EnteringQuiescentState += new EventHandler(MainForm.Editor_EnteringQuiescentState); }
Then I have a command in my app to show a modal form (ShowDialog ( ) ) which has a button called [ADD].
If I press this button, the program modifies 2 points (pass through points) of a fixed line of an alignment.
At the end of the event of pressing this button, I have a bool global variable called "Modified_byProgramation" which is in TRUE;
Once is fired the last line command: form.ShowDialog(), the ObjectModified event is fired.
public static void callback_ObjectModified(object sender, ObjectEventArgs e) { if (variables_globales.Alin_Modified_byProgrammation ==false) { //do............ }
I don´t know to do anything inside the callback_objectModified method when I modify the object by programmation, but, how I put again the variable
variables.gloables.Alin_Modified_byProgrammation= true?
I have noticed that Civil 3D fires 3 times the callback_objectModified after I modify an alignment by programmation but I don´t know if it will be more times in another time.
I would like to put the variable in true but I don´t know where I could put it.
Thanks.
Solved! Go to Solution.
Solved by joantopo. Go to Solution.
Note that I have tried this:
Within the load_form, I have removed the event handlers:
acDoc.Database.ObjectModified -= MainForm.callback_ObjectModified; acDoc.Editor.EnteringQuiescentState -= new EventHandler(MainForm.Editor_EnteringQuiescentState);
And at the end of the "command_method", (after the "formulario.ShowDialog( ) ), I add again the event handlers:
Anchored_Align.MainForm formulario = new Anchored_Align.MainForm(); formulario.ShowDialog(); acDoc.Database.ObjectModified += MainForm.callback_ObjectModified; acDoc.Editor.EnteringQuiescentState += new EventHandler(MainForm.Editor_EnteringQuiescentState); }
But this doesn´t work because after that code snippet it is fired the ObjectModified method again at the same time.
It is not a good practice to tie AutoCAD process too tight with UI, especially with AutoCAD's event handling.
It looks like, you want to know which entity (in your case, Alignment) or entities, being modified (and then do something afterwards). Using Database.ObjectModified would in general give you chance to keep track of entities being modified.
In most cases, one would "sandwich" Database.ObjectModified event handler between Document.CommandWillStart (start counting by hooking up ObjectModified event handler) and DocumentCommandEnded.(end counting and remove ObjectModified event handler). After the command ends, if there is target entities changed, do something as needed.
If you want to do give user an UI (modal form), the process could be even easier and all the work can be separated from UI and the UI is only for getting user interaction (button clicking).
Say, you can have a class like this to do all the work (pseudo code):
public class MyClass
{
private List<ObjectId> _modifiedEnt=new List<ObjectId>();
public void ModifySomeEntities()
{
var db =....MdiDocument.Database;
db.ObjectModified+=DB_ObjectModified;
_modifiedEnts.Clear();
//Do whatever you need to do with the MdiDocument/database
try
{
.....
}
finally
{
db.ObjectModified-=DB_ObjectModified;
}
}
private void DB_ObjectModified(object sender, ObjectModifiedEventArgs e)
{
//Test if the modified entity is the target entity, for example:
if (e.DBObject is xxxxxx)
{
if (!_modifiedEnts.Contains(e.DBObject.ObjectId) _modifiedEnts.Add(e.DBObject.ObjectId)
}
}
public int ModifiedEntityCount
{
get { return _modifiedEnts.Count; }
}
public void DoExtraWork()
{
if (_modifiedEnts.Count==0) return;
//Do something with changed entities
foreach (var id in _modifiedEnts)
{
.....
}
}
}
Then in the modal form, assume there is a button "Do Work":
private btnDoWork_Click(...)
{
var work=new MyClass();
work.ModifySomeEntities();
if (work.ModifiedEntityCount>0)
{
//Prompt user, if necessary
....
//Do extra work
work.DoExtraWork();
}
}
Note, when something is modified in drawing, Database.ObjectModified could fire multiple times, depending on what type of entity being modified, especially when the entity is a complicated one, such as Civil3D entity Alignment, because its change could results in other related object change, which is not exposed to outside. That is why we need some code in the Object|Modified event handler to properly filter out the entity in interest.
Norman Yuan
Great !
Right now works perfect with this code:
--->In the class "Start_app" I add again the event handlers for ObjectModified and EnteringQuiescentState
--->When I open the form with ShowDialog(), in the form load event, I remove these event handlers.
-->The last lines in the command_method will be:
Anchored_Align.MainForm formulario = new Anchored_Align.MainForm(); formulario.ShowDialog(); variables_globales.Alin_Modified_InDrawing = false; Document acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; acDoc.Database.ObjectModified += MainForm.callback_ObjectModified; acDoc.Editor.EnteringQuiescentState += new EventHandler(MainForm.Editor_EnteringQuiescentState); }
Look at the global variable : variables_globales.Alin_Modified_InDrawing, must be False and must be located before adding again the event handlers.
So, the method for the ObjectModified event will be:
public static void callback_ObjectModified(object sender, ObjectEventArgs e) { if (variables_globales.Alin_Modified_InDrawing == true) //quiere decir que se ha modificado desde el dibujo. { if (e.DBObject.GetType() == typeof(Autodesk.Civil.DatabaseServices.Alignment)) { //obtenemos el handle de la entidad que se ha modificado al dibujo. ObjectId Id_align_mod = e.DBObject.Id; int pos1 = variables_globales.listaGeneral.FindIndex(x => x.AL1_id == Id_align_mod); int pos2 = variables_globales.listaGeneral.FindIndex(x => x.AL2_id == Id_align_mod); if (pos1 >= 0 || pos2 >= 0) { variables_globales.Coll_IdAlins.Add(e.DBObject.Id); //pasamos el Id del eje a la lista. } } } }
This method only will work if the global variable is true
variables_globales.Alin_Modified_InDrawing == true
And it means that we are modifing an Alignment object in the drawing, not from my form.
In the "callback_ObjectModified" method, I check if the modified alignment in the drawing is included in my List (the registers that I add in my form) and if it is true, then I add its ObjectId to the ObjectIdCollection= variables_globales.Coll_IdAlins.Add.
After a ObjectModified event is always fired the EnteringQuiescentState event , so the method for the EnteringQuiescentState event is this:
public static void Editor_EnteringQuiescentState(object sender, EventArgs e) //estado inactivo { variables_globales.Alin_Modified_InDrawing = true; if (variables_globales.Coll_IdAlins != null && variables_globales.Coll_IdAlins.Count > 0) { //le quitamos el event handler de objeto modificado para que no salte el evento. Document acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; acDoc.Database.ObjectModified -= MainForm.callback_ObjectModified; for (int i = 0; i <= variables_globales.Coll_IdAlins.Count - 1; i++) { for (int k = 0; k <= variables_globales.listaGeneral.Count - 1; k++) //we check every register in the listaGeneral List { if (variables_globales.listaGeneral[k].AL1_id == variables_globales.Coll_IdAlins[i] || variables_globales.listaGeneral[k].AL2_id == variables_globales.Coll_IdAlins[i]) { Proces(k, false); } } } variables_globales.Coll_IdAlins.Clear(); acDoc.Database.ObjectModified += MainForm.callback_ObjectModified; } }
Look at the "Proces(k,false)" is modifying the alignment by programmation" so I have to remove the event handlers before and I have to add them after.
If the ObjectIdCollection has at least 1 item, then it do the "Proces(,)" method for each item.
Due to I can have the same alignment in my List in each Register (row), we can repeat this operation for each register.
It is very important this line, to celar the ObjectIdCollection at the end:
variables_globales.Coll_IdAlins.Clear();