Hi, I got this error when add UserData to the attributes of the object.
System.NullReferenceException: Object reference not set to an instance of an object.
at Rhino.DocObjects.Custom.UserData.NonConstPointer(Boolean createIfMissing)
at Rhino.DocObjects.Custom.UserDataList.Add(UserData userdata)
I am following this sample
MyUserData class is inherited from DocObjects.Custom.UserData
I am adding user data directly to the attributes of RhinoObject: robj.Attributes.UserData.Add(MyUserData)
Where can be the problem?
I see it leads to UserData.NonConstPointer but no idea what is wrong there.
This won’t be implemented any time soon. It will take quite a bit of core changes to allow for custom UserData to be defined by something other than a plug-in. I would recommend using the UserDictionary if at all possible.
This won’t be implemented any time soon. It will take quite a bit of core changes to allow for custom UserData to be defined by something other than a plug-in
Hi @stevebaer do you have any updates/plans about addressing this issue?
I just found out MyUserData: Rhino.DocObjects.Custom.UserDictionary works within a separated dll library other than rhino plugin.
This surprises me because: Rhino.DocObjects.Custom.UserDictionaryinherits from Rhino.DocObjects.Custom.UserData, but MyUserData2: Rhino.DocObjects.Custom.UserData doesn’t work in a separated dll library (null reference exception when adding it to a geometry).
What’s main difference that makes this Rhino.DocObjects.Custom.UserDictionary useable, while Rhino.DocObjects.Custom.UserData doesn’t?
Is it safe to say: I can move from geometry.UserDictionary back to this custom MyUserData: Rhino.DocObjects.Custom.UserDictionary?
RhinoCommon has the full definition of what a UserDictionary is and knows how to perform all of the serialization of this data into an out of a 3dm file. This is not the case for your own custom userdata derived class. Custom user data has a Guid associated with it written in the 3dm file that tells it what plug-in defines that custom user data class, but for the actual serialization it is up to the plug-in to perform this task. We don’t have this concept in place for non-plugin support library DLLs
I did a little bit more tests today. Yes, there is no issue with adding MyUserData: Custom.UserDictionary to geometry, even this MyUserData is in non-plugin dll.
But as you said, it has issues that saving to 3dm file. The override Write of MyUserData: Custom.UserDictionary is called, I assume the data is saved to 3dm. But Read is never called, and cannot find any data anymore after reopen the file.
Thanks for your confirmation.
I guess I eventually have to give up on Custom.UseData.
Sorry for reviving this thread, but I wanted to let those interested know that there is a work around to this: define an Interface.
Define the interface in your common library, and implement it in your plugin. You then can iterate through the UserDataList on an object looking for UserData that implements your interface.
@stevebaer or @dale do you see any pitfalls with using this approach?
Thanks
For Example:
In Common Library
public interface ICustomUserData
{
public string Notes {get; set;}
public string Description {get;}
}
In Rhino Plugin
//This GUID is empty, use your own!
[Guid("00000000-0000-0000-0000-000000000000")]
public class CustomUserDataImpl : UserData, ICustomUserData
{
/// Standard Implementation from SampleCSUserData Project ///
}
In Grasshopper Plugin
protected override void SolveInstance(IGH_DataAccess DA)
{
var objGuid = Guid.Empty;
if (!DA.GetData(0, ref objGuid)) return;
var ro = RhinoDoc.ActiveDoc.Objects.Find(objGuid);
if (ro == null)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "The Id is not for a Rhino Object");
return;
}
foreach (var ud in ro.Attributes.UserData)
{
if (ud is ICustomUserData csd)
{
DA.SetData(0, csd.Notes);
return;
}
}
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "The Object Did not contain Custom User Data");
return;
}