Data on geometry.UserData disappears after undo?

I defined a UserData (Hole), this data is added to Brep, saved, copied, moved, undeleted, the data is normal, when I modify the Hole, I need to replace the Brep, after replacing the Brep, if I undo the replacement, Then my data will be lost, what is the reason?
UserData
Here is my code when I replace Brep:

        internal static void Hole_XY_RhinoUpdateHole(XY_Hole hole)
        {
            //When I undo, my data is lost

            RhinoApp.WriteLine("Replace Hole Brep!!!!!!!!!!! + BeginUndoRecord");
            var sn = RhinoDoc.ActiveDoc.BeginUndoRecord("ReplaceHole");
            RhinoObject rhinoObject = RhinoDoc.ActiveDoc.Objects.Find(hole.AttachGuid);
            if (rhinoObject != null && rhinoObject.Geometry.UserData.Find(typeof(XY_Hole)) is XY_Hole _Hole)
            {
                Brep brep = hole.CreateBrep();
                RhinoDoc.ActiveDoc.Objects.Replace(rhinoObject.Id, brep);  //Here hole.OnDuplicate is called four times?????
                bool commit = rhinoObject.CommitChanges();  //returns false forever???
                RhinoDoc.ActiveDoc.Views.Redraw();
            }
            if (sn > 0)
            {
                RhinoApp.WriteLine("Replace Hole Brep!!!!!!!!!!! + EndUndoRecord");
                RhinoDoc.ActiveDoc.EndUndoRecord(sn);
            }
        }
        private void RhinoDoc_AddRhinoObject(object sender, RhinoObjectEventArgs e)
        {
            if (e.TheObject.Geometry.UserData.Find(typeof(XY_Hole)) is XY_Hole hole) hole.AttachGuid = e.TheObject.Id;
        }

Puzzled -_-!!!

The reason why your UserData is lost when you undo the replacement of Brep is because the Undo mechanism in Rhino reverts the changes made to the geometry of the RhinoObject, but does not restore any attached UserData. When you replace the Brep, the RhinoObject gets a new geometry, and any previously attached UserData is lost.

:sweat_smile:Thank you for your answer, this is really a strange mechanism, is there any other solution?

You could make your own implementation of the UNDO command that stores userdata and adds it to the new geometry.

I wanted to regenerate a RhinoObject, but it seems to be the same result. The RhinoObject deleted by Object.Delete will still lose data after undoing the deletion, but the RhinoObject deleted manually by pressing del will not lose the data after undoing.

        internal static void Hole_XY_RhinoUpdateHole(XY_Hole hole)
        {
            //When I undo, my data is lost

            RhinoApp.WriteLine("Replace Hole Brep!!!!!!!!!!! + BeginUndoRecord");
            var sn = RhinoDoc.ActiveDoc.BeginUndoRecord("ReplaceHole");
            RhinoObject rhinoObject = RhinoDoc.ActiveDoc.Objects.Find(hole.AttachGuid);
            if (rhinoObject != null && rhinoObject.Geometry.UserData.Find(typeof(XY_Hole)) is XY_Hole _Hole)
            {
                Brep brep = hole.CreateBrep();

                //RhinoDoc.ActiveDoc.Objects.Replace(rhinoObject.Id, brep);  //Here hole.OnDuplicate is called four times?????
                //bool commit = rhinoObject.CommitChanges();  //returns false forever???

                RhinoDoc.ActiveDoc.Objects.AddBrep(brep, rhinoObject.Attributes.Duplicate());  //Here hole.OnDuplicate is called four times ??
                RhinoDoc.ActiveDoc.Objects.Delete(rhinoObject);    //When I undo, my data is still lost
                RhinoDoc.ActiveDoc.Views.Redraw();
            }
            if (sn > 0)
            {
                RhinoApp.WriteLine("Replace Hole Brep!!!!!!!!!!! + EndUndoRecord");
                RhinoDoc.ActiveDoc.EndUndoRecord(sn);
            }
        }

Is Geometry.UserData really so fragile?

  1. Store the object user data
  2. Remove the object
  3. Add the new object that fits your needs
  4. Assign the previously stored data to the new object
    It’s not fragile, this is how it works, userdata is object specific, therefore if you remove that specific object and a new one is created (UNDO) you lose all user data to that object, so you must implement an UNDO that stores the data and reassigns it. It’s not fragile, that’s how it works, and It’s actually pretty solid.

Hi @yi1357068078,

You might consider storing your user data on the object’s attributes, not it’s geometry.

– Dale

@farouk.serragedine
Thank you for your reply, I’m still a beginner, I can’t achieve this function, I think I have to find another way;

  1. When adding Brep in Rhino, AddRhinoObject will be triggered. At this time, move the data to Attributes for storage, and delete UserData on Brep;
  2. When running in Grasshopper, this data needs to be moved to Geometry;

@dale Hi Dale
This functionality almost always works in Grasshopper, so Geometry.UserData is preferred

@dale @farouk.serragedine
New problem occurs, data is not copied when copying properties;
My custom object inherits from Rhino.DocObjects.Custom.UserData; after the inherited object is added to Attributes.UserData, it cannot be copied and moved? This question was asked a long time ago

About UserData and it’s connection to RhinoObject