DynamoDS / DynamoRevit

Dynamo Libraries for Revit
https://dynamobim.org
342 stars 188 forks source link

obtain node guid, other mechanism for checking where input is coming from #1565

Open ksobon opened 7 years ago

ksobon commented 7 years ago

This is my issue that came out when I was working on Filters for the view schedule. Since Schedule filters are not inherited from Element class they are not being assigned the Id nor UniqueId values. They also don't get tracked/bound the same way that other revit elements normally do. So, basically every time I make a change to one of the inputs on the node, it re-executes and creates a new instance of a filter. I then had to override the Equals property of that class to make sure that I am not adding the same filter twice. That doesn't exactly solve the issue here. This is more of a Dynamo issue. Every time I change an input to the node, it re-executes itself, and produces a new instance of the Filter class. So If I am changing my input for value from 1 to 2 then to 4 I end up adding three filters to schedule. That's not very good when you run in the automatic mode. Here's an example:

untitled

Is there a way to either get the input node GUID or some other mechanism of tracking what node produced a given input? I would then know that even though a new class came in, it came from the same node as before so it's an updated version of that filter rather than a new one. Shouldn't nodes not produce new instances of classes on input changes? Is there a way to control that? I am just trying to figure out a way to work in Automatic mode here, which as currently constructed doesn't work well for this particular functionality.

Ideas?

@ikeough @mjkkirschner

mjkkirschner commented 7 years ago

you are creating a wrapper around the filter so you can implement your own ID for it correct? You can store that in trace, and do the right thing based on if you find an ID or not.

Does that make sense? Perhaps you store the GUID and some properties about the filter together?

You don't need a GUID or revit unique ID to store things in trace, you can use set raw trace to put whatever you want in there as long as it's serializable. There is a max size in thread local storage so simple objects 😉 .

mjkkirschner commented 7 years ago

checkout the direct shape implementation for use of raw trace.

ksobon commented 7 years ago

Nice, that's exactly what I was looking for...i hope. Cheers!

ksobon commented 7 years ago

@mjkkirschner is Trace data stored permanently with the file when closed? I am seeing my guids get re-created again after I close/re-open my DYN file. I am using the SetRawDataForTrace and GetRawDataFromTrace methods.

ksobon commented 7 years ago

I don't see anything extra in the DYN file after I save the definition. Is there a way to serialize something beyond the current session? Thanks!

ksobon commented 7 years ago

@mjkkirschner any ideas on this? Was SetRawDataForTrace supposed to serialize data into the DYN file? Did I miss something? I know you can do that with the SerizlizeCore override in NodeModel but what about ZT?

mjkkirschner commented 7 years ago

I'll need to see your code - setRawTrace puts stuff into the .dyn file under something like SessionTraceData usually encoded as base64 strings. Have you put a serializable class into trace?

mjkkirschner commented 7 years ago

if you check out: https://github.com/DynamoDS/DynamoRevit/blob/Revit2017/src/Libraries/RevitNodes/Elements/DirectShape.cs#L22

it itself inherits from SerializedID which implements necessary methods for serializing using ISerializable attribute and interface.

https://github.com/DynamoDS/DynamoRevit/blob/7270187e8688fbd8ec538b4617810dccdb9a695f/src/Libraries/RevitServices/Persistence/ElementBinder.cs

ksobon commented 7 years ago

yes, so I jacked this from the DirectShape class:

    [SupressImportIntoVM]
    [Serializable]
    public class ScheduleSortGroupFieldState : SerializableId
    {
        public string syncId { get; set; }
        public ScheduleSortGroupField field { get; set; }

        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("syncId", syncId, typeof(string));
            info.AddValue("field", field, typeof(ScheduleSortGroupField));
        }

        public ScheduleSortGroupFieldState(ScheduleSortGroupField ssgf, string syncId) :
            base()
        {
            this.syncId = syncId;
            this.field = ssgf;
        }

        public ScheduleSortGroupFieldState(SerializationInfo info, StreamingContext context) :
            base(info, context)
        {
            syncId = (string)info.GetValue("syncId", typeof(string));
            field = (ScheduleSortGroupField)info.GetValue("field", typeof(ScheduleSortGroupField));
        }
    }

Then used the set and get like this:

 var oldField = ElementBinder.GetRawDataFromTrace();
            var so = (Autodesk.Revit.DB.ScheduleSortOrder)System.Enum.Parse(typeof(Autodesk.Revit.DB.ScheduleSortOrder), sortOrder);

            if (oldField != null)
            {
                var sortGroupField = oldField as ScheduleSortGroupFieldState;
                var serializedField = sortGroupField.field;
                this.GUID = serializedField.GUID;
                return;
            }
            this.GUID = Guid.NewGuid();

            var traceData = new ScheduleSortGroupFieldState(this, Guid.NewGuid().ToString());

            ElementBinder.SetRawDataForTrace(traceData);
        }

and it works in session, but wasn't serializing anything into the DYN file. I will have another look.

mjkkirschner commented 7 years ago

@ksobon It could also be a bug with SetRawDataForTrace, but I believe this works and serializes correctly for direct shape.