Dynamo 2.0 ist eine Hauptversion, und einige APIs wurden geändert oder entfernt. Eine der größten Änderungen, die sich auf Block- und Paket-Autoren auswirken wird, ist der Wechsel zum JSON-Dateiformat.
Generell werden Zero-Touch-Block-Autoren wenig bis gar keine Arbeit damit haben, ihre Pakete in der Version 2.0 zu verwenden.
Benutzeroberflächen-Blöcke und Blöcke, die direkt aus NodeModel abgeleitet werden, erfordern mehr Arbeit, damit sie in der Version 2.x ausgeführt werden können.
Erweiterungsautoren müssen möglicherweise auch einige Änderungen vornehmen, je nachdem, wie viele der Dynamo Core-APIs sie in ihren Erweiterungen verwenden.
Bündeln Sie Dynamo- oder Dynamo Revit-DLL-Dateien nicht zusammen mit Ihrem Paket. Diese DLL-Dateien sind bereits von Dynamo geladen worden. Wenn Sie eine andere Version bündeln, als der Benutzer geladen hat (d. h., Sie verteilen zum Beispiel Dynamo Core 1.3, der Benutzer führt Ihr Paket jedoch unter Dynamo 2.0 aus), treten mysteriöse Laufzeitfehler auf. Dazu gehören DLL-Dateien wie DynamoCore.dll
, DynamoServices.dll
, DSCodeNodes.dll
, ProtoGeometry.dll
.
Bündeln und verteilen Sie newtonsoft.json.net
nach Möglichkeit nicht zusammen mit Ihrem Paket. Diese DLL-Datei ist ebenfalls bereits von Dynamo 2.x geladen. Das gleiche Problem wie oben kann auftreten.
Bündeln und verteilen Sie CEFSharp
nach Möglichkeit nicht zusammen mit Ihrem Paket. Diese DLL-Datei ist ebenfalls bereits von Dynamo 2.x geladen. Das gleiche Problem wie oben kann auftreten.
Im Allgemeinen sollten Sie die Freigabe von Abhängigkeiten für Dynamo oder Revit vermeiden, wenn Sie die Version dieser Abhängigkeit steuern müssen.
1) Beim Öffnen eines Diagramms haben einige Blöcke mehrere Anschlüsse mit demselben Namen, das Diagramm sah beim Speichern jedoch einwandfrei aus. Dieses Problem kann mehrere Ursachen haben.
Die häufigste Fehlerursache ist, dass der Block mit einem Konstruktor erstellt wurde, der die Anschlüsse neu erstellt hat. Stattdessen hätte ein Konstruktor verwendet werden müssen, der die Anschlüsse geladen hat. Diese Konstruktoren sind gewöhnlich mit [JsonConstructor]
gekennzeichnet. Beispiele finden Sie unten.
Dies kann folgende Ursachen haben:
Es gab einfach keinen passenden [JsonConstructor]
, oder der Datei wurden Inports
und Outports
aus der JSON-DYN-Datei nicht übergeben.
Es wurden zwei Versionen von JSON.net gleichzeitig in denselben Prozess geladen, was einen .NET-Laufzeitfehler verursachte, sodass das Attribut [JsonConstructor]
nicht ordnungsgemäß verwendet werden konnte, um den Konstruktor zu markieren.
Die Datei DynamoServices.dll mit einer anderen Version als die aktuelle Dynamo-Version wurde mit dem Paket gebündelt. Dadurch kann ein .NET-Laufzeitfehler beim Ermitteln des Attributs [MultiReturn]
auftreten, sodass die mit verschiedenen Attributen markierten Zero-Touch-Blöcke diese nicht anwenden können. Sie werden möglicherweise feststellen, dass ein Block eine einzelne Wörterbuchausgabe anstelle mehrerer Anschlüsse zurückgibt.
2) Beim Laden des Diagramms fehlen Blöcke vollständig, und es treten Fehler in der Konsole auf.
Dies kann auftreten, wenn die Deserialisierung aus irgendeinem Grund fehlgeschlagen ist. Es empfiehlt sich, nur die benötigten Eigenschaften zu serialisieren. Wir können [JsonIgnore]
für komplexe Eigenschaften verwenden, die Sie nicht laden oder speichern müssen, um sie zu ignorieren. Eigenschaften wie function pointer, delegate, action,
oder event
usw. Diese sollten nicht serialisiert werden, da sie in der Regel nicht deserialisiert werden können und einen Laufzeitfehler verursachen.
Organisieren von benutzerdefinierten Blöcken in library.js
Bekannte Probleme:
Ein gleicher benutzerdefinierter Blockname und Kategoriename auf derselben Ebene in library.js führt zu unerwartetem Verhalten. QNTM-3653: Vermeiden Sie die Verwendung derselben Namen für Kategorie und Blöcke.
Kommentare werden in Blockkommentare anstatt in Zeilenkommentare umgewandelt.
Kurze Typnamen werden durch vollständige Namen ersetzt. Wenn Sie beispielsweise beim erneuten Laden des benutzerdefinierten Blocks keinen Typ angegeben haben, wird var[]..[]
angezeigt, da dies der Vorgabetyp ist.
In Dynamo 2.0 wurden Listen- und Wörterbuchtypen getrennt, und die Syntax zum Erstellen von Listen und Wörterbüchern wurde geändert. Listen werden mit []
initialisiert, während Wörterbücher {}
verwenden.
Wenn Sie zuvor das Attribut DefaultArgument
verwendet haben, um Parameter auf den Zero-Touch-Blöcken zu markieren, und die Listensyntax verwendet haben, um eine bestimmte Liste wie someFunc([DefaultArgument("{0,1,2}")])
als Vorgabe zu verwenden, ist dies nicht mehr gültig. Sie müssen dann das DesignScript-Snippet ändern, um die neue Initialisierungssyntax für Listen zu verwenden.
Wie oben erwähnt, sollten Sie Dynamo-DLL-Dateien nicht mit Ihren Paketen verteilen (DynamoCore
, DynamoServices
usw.).
NodeModel-Blöcke erfordern die meiste Arbeit bei der Aktualisierung auf Dynamo 2.x. Auf höherer Ebene müssen Sie Konstruktoren implementieren, die nur zum Laden der Blöcke aus JSON verwendet werden, zusätzlich zu den regulären NodeModel-Konstruktoren, die zum Instanziieren neuer Instanzen der Blocktypen verwendet werden. Um zwischen diesen zu unterscheiden, markieren Sie die Konstruktoren für die Ladezeit mit [JsonConstructor]
, einem Attribut von newtonsoft.Json.net.
Die Namen der Parameter im Konstruktor sollten im Allgemeinen mit den Namen der JSON-Eigenschaften übereinstimmen. Diese Zuordnung wird jedoch komplizierter, wenn Sie die Namen überschreiben, die mithilfe von [JsonProperty]-Attributen serialisiert werden. Weitere Informationen finden Sie in der Dokumentation zu Json.net.
Die häufigste Änderung, die beim Aktualisieren von Blöcken erforderlich ist, die von der NodeModel
-Basisklasse (oder anderen Dynamo Core-Basisklassen, z. B. DSDropDownBase
) abgeleitet wurden, ist die Notwendigkeit, Ihrer Klasse einen JSON-Konstruktor hinzuzufügen.
Die Initialisierung eines neuen Blocks, der in Dynamo erstellt wurde (z. B. über die Bibliothek), ist weiterhin durch den ursprünglichen parameterlosen Konstruktor möglich. Der JSON-Konstruktor ist erforderlich, um einen Block zu initialisieren, der aus einer gespeicherten DYN- oder DYF-Datei deserialisiert (geladen) wird.
Der JSON-Konstruktor unterscheidet sich vom Basiskonstruktor dadurch, dass er über PortModel
-Parameter für inPorts
und outPorts
verfügt, die von der JSON-Ladelogik bereitgestellt werden. Der Aufruf zum Registrieren der Anschlüsse für den Block ist hier nicht erforderlich, da die Daten in der DYN-Datei vorhanden sind. Ein JSON-Konstruktor sieht beispielsweise wie folgt aus:
using Newtonsoft.Json; //New dependency for Json
………
[JsonConstructor] //Attribute required to identity the Json constructor
//Minimum constructor implementation. Note that the base method invocation must also be present.
FooNode(IEnumerable<PortModel> inPorts, IEnumerable<PortModel> outPorts) : base(inPorts, outPorts) { }
Diese Syntax :base(Inports,outPorts){}
ruft den nodeModel
-Basiskonstruktor auf und übergibt die deserialisierten Anschlüsse an diesen.
Spezielle Logik im Klassenkonstruktor, die die Initialisierung bestimmter Daten umfasst, die in die DYN-Datei serialisiert werden (z. B. Festlegen der Anschlussregistrierung, Vergitterungsstrategie usw.), muss in diesem Konstruktor nicht wiederholt werden, da diese Werte aus dem JSON-Konstruktor gelesen werden können.
Dies ist der Hauptunterschied zwischen dem JSON-Konstruktor und Nicht-JSON-Konstruktoren für Ihre NodeModels. JSON-Konstruktoren werden beim Laden aus einer Datei aufgerufen und erhalten geladene Daten. Andere Benutzerlogik muss jedoch im JSON-Konstruktor dupliziert werden (z. B. Initialisieren von Ereignis-Steuerprogrammen für den Block oder Anhängen).
Beispiele finden Sie hier im DynamoSamples-Repository -> ButtonCustomNodeModel, DropDown oder SliderCustomNodeModel.
Bisher konnte ein Entwickler bestimmte Modelldaten über die SerializeCore
- und DeserializeCore
-Methode in das XML-Dokument serialisieren und deserialisieren. Diese Methoden sind weiterhin in der API vorhanden, werden jedoch in einer zukünftigen Version von Dynamo nicht mehr unterstützt (ein Beispiel finden Sie hier). Mit der JSON.NET-Implementierung können jetzt public
-Eigenschaften in der von NodeModel abgeleiteten Klasse direkt in die DYN-Datei serialisiert werden. JSON.Net stellt mehrere Attribute bereit, mit denen die Serialisierung der Eigenschaft gesteuert wird.
Dieses Beispiel mit der Angabe eines PropertyName
finden Sie hier im Dynamo-Repository.
[JsonProperty(PropertyName = "InputValue")]
public DSColor DsColor {...
Anmerkung
Wenn Sie eine eigene JSON.net-Konverterklasse erstellen, verfügt Dynamo derzeit über keinen Mechanismus, mit dem Sie diese in die Lade- und Speichermethoden einlesen können. Daher kann die Klasse auch dann nicht verwendet werden, wenn Sie sie mit dem [JsonConverter]
-Attribut markieren. Sie können den Konverter stattdessen direkt in Ihrem Setter oder Getter aufrufen. //ZU ERLEDIGEN: Bestätigung dieser Einschränkung erforderlich. Alle Nachweise sind willkommen.
Ein Beispiel, in dem eine Serialisierungsmethode zum Konvertieren der Eigenschaft in eine Zeichenfolge angegeben ist, finden Sie hier im Dynamo-Repository.
[JsonProperty("MeasurementType"), JsonConverter(typeof(StringEnumConverter))]
public ConversionMetricUnit SelectedMetricConversion{...
Für public
-Eigenschaften, die nicht für die Serialisierung vorgesehen sind, muss das Attribut [JsonIgnore]
hinzugefügt werden. Wenn die Blöcke in der DYN-Datei gespeichert werden, wird dadurch sichergestellt, dass diese Daten vom Serialisierungsmechanismus ignoriert werden. Beim erneuten Öffnen des Diagramms treten dann keine unerwarteten Auswirkungen auf. Ein Beispiel dafür finden Sie hier im Dynamo-Repository.
Wie bereits erwähnt, wurden in der Vergangenheit die Methoden SerializeCore
und DeserializeCore
verwendet, um Blöcke zu speichern und in die XML-DYN-Datei zu laden. Außerdem wurden sie und werden weiterhin auch zum Speichern und Laden des Blockstatus zum Rückgängigmachen und Wiederherstellen verwendet. Wenn Sie komplexe Funktionen zum Rückgängigmachen und Wiederherstellen für den NodeModel-Benutzeroberflächen-Block implementieren möchten, müssen Sie diese Methoden implementieren und in das XML-Dokumentobjekt serialisieren, das als Parameter für diese Methoden bereitgestellt wird. Dies sollte ein selten auftretender Anwendungsfall sein, mit Ausnahme von komplexen Benutzeroberflächen-Blöcken.
Ein häufiges Vorkommen in NodeModel-Blöcken, die von 2.0-API-Änderungen betroffen sind, ist die Anschlussregistrierung im Blockkonstruktor. Wenn Sie sich die Beispiele im Dynamo- oder DynamoSamples-Repository ansehen, werden Sie bisher die Verwendung der Methode InPortData.Add()
oder OutPortData.Add()
gefunden haben. In der Dynamo-API wurden die öffentlichen InPortData
- und OutPortData
-Eigenschaften bisher als veraltet markiert. In Version 2.0 wurden diese Eigenschaften entfernt. Entwickler sollten jetzt die Methoden InPorts.Add()
und OutPorts.Add()
verwenden. Darüber hinaus haben diese beiden Add()
-Methoden leicht unterschiedliche Signaturen:
InPortData.Add(new PortData("Port Name", "Port Description")); //Old version valid in 1.3 but now deprecated
im Vergleich zu
InPorts.Add(new PortModel(PortType.Input, this, new PortData("Port Name", "Port Description"))); //Recommended 2.0
Beispiele für konvertierten Code finden Sie hier im Dynamo-Repository -> DynamoConvert.cs oder FileSystem.cs.
Der andere häufige Anwendungsfall, der von den 2.0-API-Änderungen betroffen ist, bezieht sich auf die Methoden, die häufig in der Methode BuildAst()
verwendet werden, um das Blockverhalten basierend auf dem Vorhandensein oder Fehlen von Anschlussverbindungen zu bestimmen. Zuvor wurde HasConnectedInput(index)
verwendet, um einen verbundenen Anschlussstatus zu validieren. Entwickler sollten nun die Eigenschaft InPorts[0].IsConnected
verwenden, um den Anschlussverbindungsstatus zu überprüfen. Ein Beispiel hierfür finden Sie in ColorRange.cs im Dynamo-Repository.
Gehen wir nun die Schritte für die Aktualisierung eines 1.3-Benutzeroberflächen-Blocks auf Dynamo 2.x durch.
Damit die nodeModel
-Klasse in der Version 2.0 ordnungsgemäß geladen und gespeichert wird, müssen wir einfach nur einen jsonConstructor hinzufügen, der das Laden der Anschlüsse handhabt. Wir übergeben die Anschlüsse einfach an den Basiskonstruktor, und diese Implementierung ist leer.
Anmerkung: Rufen Sie RegisterPorts()
oder eine Variante davon nicht in Ihrem JsonConstructor auf. Dadurch werden die Eingabe- und Ausgabeparameterattribute in Ihrer Blockklasse zum Erstellen neuer Anschlüsse verwendet. Dies ist nicht erwünscht, da die geladenen Anschlüsse verwendet werden sollen, die an den Konstruktor übergeben werden.
In diesem Beispiel wird der JSON-Konstruktor mit dem minimalsten Ladeaufwand hinzugefügt. Was passiert aber, wenn wir komplexere Konstruktionslogik ausführen müssen, wie z. B. die Einrichtung einiger Listener für die Ereignisbehandlung im Konstruktor? Das nächste aus dem
DynamoSamples-Repository entnommene Beispiel ist oben im JsonConstructors Section
dieses Dokuments verknüpft.
Im Folgenden wird ein komplexerer Konstruktor für einen Benutzeroberflächen-Block dargestellt:
Wenn wir einen JSON-Konstruktor hinzufügen, um diesen Block aus einer Datei zu laden, müssen wir einen Teil dieser Logik neu erstellen. Beachten Sie jedoch, dass wir den Code, mit dem Anschlüsse erstellt, Vergitterungen festgelegt oder die Vorgabewerte für Eigenschaften angegeben werden, die aus der Datei geladen werden können, nicht berücksichtigen.
Beachten Sie, dass andere öffentliche Eigenschaften, die in JSON serialisiert wurden, wie ButtonText
und WindowText
, nicht als explizite Parameter zum Konstruktor hinzugefügt werden müssen. Sie werden automatisch von JSON.net mit den Settern für diese Eigenschaften festgelegt.