In this article you will see how you can work with objects when developing your articy:draft X plugins using the MDK.
All project objects are wrapped in an a type called ObjectProxy. This type provides a common interface to maniplate arbitrary project objects.
Because we are dealing with different object types via the ObjectProxy, we can't access the properties directly. Hence, to access a property, you need to use the indexer on an ObjectProxy object:
ObjectProxy prj = Session.GetProjectRoot();
string projectDisplayName = (string)prj["DisplayName"];The MDK provides a static helper object called ObjectPropertyNames to make accessing properties via the indexer less error-prone compared to working with string literals:
string projectDisplayName = (string)prj[ObjectPropertyNames.DisplayName];Setting properties works the same way using the indexer.
myObject[ObjectPropertyNames.Text] = "Some Text";For convenience, we also provide several getter and setter methods for important properties, like DisplayName and TechnicalName. Use these to avoid the need to cast the property values.
string displayName = myObject.GetDisplayName();
myObject.SetTechnicalName(displayName);In order to get the underlying oject type, use the member ObjectType
if(myObject.ObjectType == ObjectType.DialogueFragment)
{
}Most properties have a primitive type, but some can reference other project objects. Notable examples are the Parent and Speaker properties. In those cases, the indexer will return another ObjectProxy
ObjectProxy speaker = myObject[ObjectPropertyNames.Speaker] as ObjectProxy;
ObjectProxy parent = myObject.GetParent();
if(speaker != null && parent == parentCandidate)
{
string qualifiedSpeakerName = parent.GetDisplayName() + "." + speaker.GetDisplayName();
// ...
}When you have a query to find a specific type, it is possible that you get more objects than intended. For example, if you make a query over the whole project looking for DialogueFragments you will get Fragments found in the Flow and in any Documents. If that is not desired, you need to adjust your query or you need to check the objects' context.
if(myObject.IsInContext(ObjectContext.Flow))
{
}While Assets are also project objects, they have some unique characteristics it is worth knowing about.
Assets in articy:draft X are imported from a source and included as copies as part of your project. To import assets programmatically utilize the ApiSession object, which you can access as a member in your Plugin class (which is derived from MacroPlugin).
Importing a new asset is done via ImportAsset
ObjectProxy targetFolder = Session.GetSystemFolder(SystemFolderNames.Assets);
string newAssetName = "MyFlowAsset";
string filePath = @"C:\Flower.png";
var obj = Session.ImportAsset(targetFolder, newAssetName, filePath);Modifying an existing asset with a new source works in a similar way. For example, overwriting an image on your file system using a asset object works like this:
ObjectProxy targetAsset = ...
string filePath = @"C:\Flower.png";
Session.ChangeAsset(targetAsset, filePath);Important
When you are dealing with importing or changing assets, the Asset system of articy:draft X will import/modify this content asynchronously. This can be a potential pitfall if you want to work with the new asset content directly. To make sure that your asset operation is fully finished and the underlying content is available to work with, you need to call the following method:
Session.WaitForAssetProcessing(new WaitForAssetProcessingArgs());To re-iterate: this is only necessary when you need to work with the external asset file of an articy asset. If you want to work with the in-memory articy object, you can do that directly after the import operation.
Accessing the underlying asset file can be done like this:
var assetPath = myAsset[ObjectPropertyNames.AbsoluteFilePath] as string;
if (!string.IsNullOrEmpty(assetPath))
{
byte[] fileBytes = File.ReadAllBytes(assetPath);
...
}When you are writing a plugin that should work with multiuser, partitions and claiming, you need to make some additional checks before trying to create or modify objects.
The most important check is to see if an object is currently available for modification. To do that, check if an object is read only:
ObjectProxy obj = ...
if(obj.IsReadOnly)
{
// not mine, need to claim it before modifying
}When you want to claim an object, you need to claim its partition. To do that, you find the necessary methods on the ApiSession object:
ObjectProxy obj = ...
if (obj.IsReadOnly)
{
Session.ClaimPartition(obj.GetPartitionId());
}This only works if the partition was not claimed by somebody else. After a claim, you can check if it was successful by either checking IsReadOnly again or by using GetPartitionInfo(Guid):
ObjectProxy obj = ...
PartitionInfo partInfo = Session.GetPartitionInfo(obj.GetPartitionId());
if (!partInfo.IsClaimedByMe)
{
// not my partition
}If you are done with a partition, you might need to publish the changes, so other users in the project can get them.
Session.PublishProjectPartitions(false); // publish and unclaim