Author Topic: redo/undo, undofiler .net  (Read 3901 times)

0 Members and 1 Guest are viewing this topic.

nekitip

  • Guest
redo/undo, undofiler .net
« on: July 29, 2012, 01:43:22 AM »
Hello all. This is my first post, and I'm surprised i haven't seen this forum before!
I've been playing with vb.net for autocad for a while, so I don't have the right to say I'm absolute beginner, but... I'm not getting very far from that. :)

I have a question about undo.
I'm writing data in Xrecord and (maybe I'm doing it wrong), i cant get old values after undo, only xrecord removal. I believe undo doesn't work that way?
Here is my question:
In autocad, there is "UNDOFILER" in every object. What does that do? Can i populate it with my binary data? There is some info in ObjectArx, but i don't understand that at all, and there is nothing google can find for .net.

Alternative is, i think, to create some undo mechanism for that data (the one i write to xrecord), to work in separate .net class, using Stack, pop/push when "ismodified" is triggered or similar.
Is this concept right way to go? How do you do it?

Thank you!

TheMaster

  • Guest
Re: redo/undo, undofiler .net
« Reply #1 on: July 29, 2012, 06:18:33 PM »
Hello all. This is my first post, and I'm surprised i haven't seen this forum before!
I've been playing with vb.net for autocad for a while, so I don't have the right to say I'm absolute beginner, but... I'm not getting very far from that. :)

I have a question about undo.
I'm writing data in Xrecord and (maybe I'm doing it wrong), i cant get old values after undo, only xrecord removal. I believe undo doesn't work that way?
Here is my question:
In autocad, there is "UNDOFILER" in every object. What does that do? Can i populate it with my binary data? There is some info in ObjectArx, but i don't understand that at all, and there is nothing google can find for .net.

Alternative is, i think, to create some undo mechanism for that data (the one i write to xrecord), to work in separate .net class, using Stack, pop/push when "ismodified" is triggered or similar.
Is this concept right way to go? How do you do it?

Thank you!

UndoFiler is how object state is rolled back, and works the same as when an object is initially loaded from storage, and is of little use to you in solving your problem.

The data stored in an XRecord is immutable, and modifying XRecord data requires all the data to be replaced with data in another ResultBuffer.

My guess is that your problem has to do with undo/transaction boundaries. If you add a new XRecord entry to a Dictionary and then set its data within a single logical transaction (which are monolithic for the purposes of UNDO), undoing the operation will result in removal of the XRecord. If you add an XRecord to a dictionary and set its data, then in a subsequent transaction you modify that XRecord's data, undoing the latter should leave the XRecord in the state it was in when the original transaction in which it was added and assigned data was committed.

Unfortunately, vague descriptions of problems like this aren't enough to help others diagnose or solve your issue.

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: redo/undo, undofiler .net
« Reply #2 on: July 30, 2012, 07:40:59 AM »
Bill Adkison gave a great class on this last year at AU 2011. http://au.autodesk.com/?nd=class&session_id=9201

I'd download the materials and that should give you an idea of how the undo/redo system works in AutoCAD.
Revit 2019, AMEP 2019 64bit Win 10

nekitip

  • Guest
Re: redo/undo, undofiler .net
« Reply #3 on: July 30, 2012, 09:05:49 AM »
Thank you for answering.
MexicanCustard, thank you! I tried to go there, but it seems that i cannot read article if I'm not member of autodesk university.

TonyT, thank you.
 
Unfortunately, vague descriptions of problems like this aren't enough to help others diagnose or solve your issue.

but it seems to me that you have "solve my issue" :)
so i had the problem i didn't know i have - i was going in a soooo wrong way! i don't need undofiler...
luckily, tony has given me a clue.
so, to make Xrecord to work under "UNDO" conditions, you must write new Xrecord at one point, and then only write/change its ResoultBuffer!
i haven't tested it all. here is then how it is could be done.

-you must have transaction and Entity before this!
Code - vb.net: [Select]
  1. #Region "XrecDATA"
  2.     Protected Sub createXrec(ByVal name As String, ByVal ent As Entity, ByRef trans As Transaction)
  3.         If ent.ExtensionDictionary.IsNull Then
  4.             ent.CreateExtensionDictionary()
  5.         End If
  6.         Dim extensionDict As DBDictionary = trans.GetObject(ent.ExtensionDictionary(), OpenMode.ForWrite)
  7.         Dim newxrec As New Xrecord
  8.         extensionDict.SetAt(name, newxrec)
  9.         trans.AddNewlyCreatedDBObject(newxrec, True)
  10.     End Sub
  11.  
  12.     Protected Sub writeToXrec(ByVal name As String, ByVal data As ResultBuffer, ByVal ent As Entity, ByRef trans As Transaction)
  13.         'no dictionary at all
  14.         If ent.ExtensionDictionary.IsNull Then createXrec(name, ent, trans)
  15.         Dim extensionDict As DBDictionary = trans.GetObject(ent.ExtensionDictionary(), OpenMode.ForRead)
  16.         'no xrec with our name
  17.         If Not extensionDict.Contains(name) Then createXrec(name, ent, trans)
  18.         Dim xRec As Xrecord = trans.GetObject(extensionDict.GetAt(name), OpenMode.ForWrite)
  19.         xRec.Data = data
  20.     End Sub
  21.  
  22.     Protected Function readFromXrec(ByVal name As String, ByVal ent As Entity, ByRef trans As Transaction) As ResultBuffer
  23.         Dim ret_val As New ResultBuffer
  24.  
  25.         If ent.ExtensionDictionary.IsValid Then
  26.             Dim extensionDict As DBDictionary = trans.GetObject(ent.ExtensionDictionary(), OpenMode.ForRead)
  27.             If extensionDict.Contains(name) Then
  28.                 Dim xRec As Xrecord = trans.GetObject(extensionDict.GetAt(name), OpenMode.ForRead)
  29.                 ret_val = xRec.Data
  30.             End If
  31.         End If
  32.         Return ret_val
  33.     End Function
  34. #End Region

is this ok?
i hope i don't have some disposing to do also somewhere...

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: redo/undo, undofiler .net
« Reply #4 on: July 30, 2012, 11:12:49 AM »
BTW, joining AU is free.
Revit 2019, AMEP 2019 64bit Win 10

TheMaster

  • Guest
Re: redo/undo, undofiler .net
« Reply #5 on: July 30, 2012, 06:26:24 PM »
Thank you for answering.
MexicanCustard, thank you! I tried to go there, but it seems that i cannot read article if I'm not member of autodesk university.

TonyT, thank you.
 
Unfortunately, vague descriptions of problems like this aren't enough to help others diagnose or solve your issue.

but it seems to me that you have "solve my issue" :)
so i had the problem i didn't know i have - i was going in a soooo wrong way! i don't need undofiler...
luckily, tony has given me a clue.
so, to make Xrecord to work under "UNDO" conditions, you must write new Xrecord at one point, and then only write/change its ResoultBuffer!
i haven't tested it all. here is then how it is could be done.

-you must have transaction and Entity before this!
Code - vb.net: [Select]
  1. #Region "XrecDATA"
  2.     Protected Sub createXrec(ByVal name As String, ByVal ent As Entity, ByRef trans As Transaction)
  3.         If ent.ExtensionDictionary.IsNull Then
  4.             ent.CreateExtensionDictionary()
  5.         End If
  6.         Dim extensionDict As DBDictionary = trans.GetObject(ent.ExtensionDictionary(), OpenMode.ForWrite)
  7.         Dim newxrec As New Xrecord
  8.         extensionDict.SetAt(name, newxrec)
  9.         trans.AddNewlyCreatedDBObject(newxrec, True)
  10.     End Sub
  11.  
  12.     Protected Sub writeToXrec(ByVal name As String, ByVal data As ResultBuffer, ByVal ent As Entity, ByRef trans As Transaction)
  13.         'no dictionary at all
  14.         If ent.ExtensionDictionary.IsNull Then createXrec(name, ent, trans)
  15.         Dim extensionDict As DBDictionary = trans.GetObject(ent.ExtensionDictionary(), OpenMode.ForRead)
  16.         'no xrec with our name
  17.         If Not extensionDict.Contains(name) Then createXrec(name, ent, trans)
  18.         Dim xRec As Xrecord = trans.GetObject(extensionDict.GetAt(name), OpenMode.ForWrite)
  19.         xRec.Data = data
  20.     End Sub
  21.  
  22.     Protected Function readFromXrec(ByVal name As String, ByVal ent As Entity, ByRef trans As Transaction) As ResultBuffer
  23.         Dim ret_val As New ResultBuffer
  24.  
  25.         If ent.ExtensionDictionary.IsValid Then
  26.             Dim extensionDict As DBDictionary = trans.GetObject(ent.ExtensionDictionary(), OpenMode.ForRead)
  27.             If extensionDict.Contains(name) Then
  28.                 Dim xRec As Xrecord = trans.GetObject(extensionDict.GetAt(name), OpenMode.ForRead)
  29.                 ret_val = xRec.Data
  30.             End If
  31.         End If
  32.         Return ret_val
  33.     End Function
  34. #End Region

is this ok?
i hope i don't have some disposing to do also somewhere...

It looks like you're actually confusing one problem with another one.

The actual problem is that your code doesn't check for the XRecord's existence before attempting to modify its data. You should always design code that stores data in an XRecord so that it first checks for the XRecord's existence, and if it does not exist, creates it, and then writes the data. If the XRecord already exists, then the code just skips the creation process and modifies the existing XRecord's data.

If you do it that way, you wouldn't have to worry about undo, and what you percieve to be the problem, is not a problem at all.  If you search for sample code that works with XRecords you will find that most of it follows the basic pattern I mention above.
« Last Edit: July 30, 2012, 06:30:39 PM by TonyT »

BlackBox

  • King Gator
  • Posts: 3770
Re: redo/undo, undofiler .net
« Reply #6 on: July 30, 2012, 06:51:05 PM »
Bill Adkison gave a great class on this last year at AU 2011. http://au.autodesk.com/?nd=class&session_id=9201

I'd download the materials and that should give you an idea of how the undo/redo system works in AutoCAD.

Just wanted to say thanks for posting this AU course... Downloaded it earlier today, and had no idea (still being new to .NET) just how much Undo/U & Redo/MRedo logic was 'taken care of' for us when using Commands, and even LISP.

Much of it (the course) is still above my head, but both interesting, and informative.

Cheers, MexicanCustard! :beer:
"How we think determines what we do, and what we do determines what we get."

nekitip

  • Guest
Re: redo/undo, undofiler .net
« Reply #7 on: July 31, 2012, 04:25:37 PM »
"UNDO removes updated dictionary entry"
http://adndevblog.typepad.com/autocad/2012/07/undo-removes-updated-dictionary-entry.html
...
it looks like the developers need to write about this also. and on the same day! :)