Before proceeding, be sure to review Interface Asset general concepts and our introduction to creating your own interface asset. Treat these articles as prerequisites to the content below.
Introduction
Intuiface Interface Assets support .NET libraries written in C# or VB and rely upon reflection to generate instances, read or write properties and call methods of available objects/classes.
The following coding requirements are implied:
- Classes that will be manipulated by Intuiface Composer/Player must be public and provide a public argument-less constructor,
- These manipulated classes cannot be static class or static instances (singletons). However, you can use static objects within these classes for objects that don't have to be visible within Intuiface. This is particularly useful when you need a single object (e.g. an object opening a network port) in both Composer's Edit Mode and Play Mode.
To see an example up close, take a look at the following C# source code for the a custom interface asset located here.
Process
Create the Interface Asset and add it to Composer
- Create your Dynamic Link Library (DLL) using .NET Framework 4 in a tool like Visual Studio
- Use a public class as en entry point (see Facade design pattern below)
- All of its public properties, methods and events are going to be exposed within Intuiface Composer as Properties, Actions and Triggers
- Run the GenerateDescriptor tool (see next section for details) on your library then update the generated .ifd file in order to
- Add titles & descriptions to your properties (the title will be visible in Composer)
- Add default values (e.g. API key)
- Add a folder containing your .ifd & .dll(s) into
C:\Users\{UserName}\Documents\Intuiface\Interface Assets
Update your Interface Asset
Once an Interface Asset has been added to your experience, there are two ways to update it:
- Copy the new files directly into the project folder:
{ProjectFolder}\Files\InterfaceAsset\{YourInterfaceAssetFolder}
OR - Copy the new files into Composer's Interface Assets folder
C:\Users\{UserName}\Documents\Intuiface\Interface Assets
AND increment the version number found in the descriptor file. When opening your experience, the files in the project folder will be updated.
In both cases, to unload the previous dll version, you must close Composer before copying the updated files.
Debug your Interface Asset
Once you have built your solution in Visual Studio and created your experience to test it, you can attached Visual Studio debugger to the Composer process running this experience. To do so
- In Visual Studio, make sure you have built your IA in Debug mode.
- In Composer, open the experience containing your Interface Asset, and go in Play mode.
- In Visual Studio,
- click on the Debug menu, then on Attach to Process
- Select IntuifaceComposer.exe in the process list and click on Attach.
- When adding a breakpoint in your code, you should see a filled red dot on the left of the line number. If you see a white dot circled with red, it means your IA runs a different version of the current source code
Assisted Generation of the Intuiface Descriptor File (.ifd)
A small command-line tool, named GenerateDescriptor, can be used to generate a complete Intuiface Descriptor file for a .NET DLL.
Since it relies upon reflection to identify the properties, events and methods of the descriptor file, the output .ifd will probably contain more than what you want to expose in Intuiface Composer. (It only checks visibility to determine if a property, event or method will be described in the .ifd.) As a result, you will have to manually delete undesired parts of the .ifd to make it easier to understand and use in Composer.
Click here to download the GenerateDescriptor executable.
The command line syntax is the following: GenerateDescriptor.exe (DLL Name). You can also drag-and-drop your .dll onto GenerateDescriptor in Windows Explorer (see image below). Either way, the .ifd file is saved in the same folder as the dll, using the same base name as the dll.
Side note considering the usage of third party libraries in C++
If your C#/VB code wrapping third party C++ libraries, you might get errors when trying to automatically generate the descriptor file (.ifd).
Process:
- remove the C++ libraries from your build folder
- follow the process described above to generate the .ifd
- put the C++ libraries back in the build folder
The C++ libraries won't be loaded by Intuiface Player / Composer since they aren't referenced anymore in ths .ifd, but will be loaded by your C#/VB code when using the DLLImport methods.
Structure of the .ifd Descriptor File
As mentioned here, a descriptor file (.ifd) is required in order to add an Interface Asset inside an Intuiface project.
NOTE: Never edit your .ifd files while Composer is running. If you wish to make changes to a .ifd file, exit out of Composer first.
A .ifd file for a .NET DLL must obey the following rules :
• All required DLLs must be listed in the "dependencies" property • The main DLL must be listed first in the "dependencies" property • The "basePath" property denotes the default namespace of the DLL
Here is an example of an ifd file's global fields as created through use of the GenerateDescriptor tool:
"id": "EndlessAisle-Selection",
"name": "EndlessAisle-Selection",
"version": "1.0",
"protocol": "dll",
"baseUrl": null,
"basePath": "EndlessAisle_Selection",
"auth": {},
"dependencies": [
"EndlessAisle-Selection.dll",
"PDFNet.dll"
],
The description of a C#/VB class must be completed as follows:
• Properties are defined in the "schemas" section of the descriptor • Methods and events are defined in the "resources" section of the descriptor • Both schema and resource must share the same "id"
Remaining part of the example below:
"schemas": {
"CartItem": {
"id": "CartItem",
"type": "object",
"properties": {
"ProductRef": {
"$ref": "Product"
},
"Quantity": {
"type": "integer"
},
"TotalPrice": {
"type": "number",
"format":"double"
}
}
}
},
"resources": {
"CartItem": {
"isExternalAsset":"true",
"methods": {
"IncrementQuantity": {
"response": {
"type": "none"
}
},
"DecrementQuantity": {
"response": {
"type": "none"
}
}
}
}
}
You can download the full .ifd file referenced above here: EndlessAisle-Selection.ifd
How to reference DLL dependencies
If your .Net DLL has some dependencies on other DLLs, you have to list all required DLLs in the "dependencies" property.
In our example, the main DLL EndlessAisle-Selection.dll
requires PDFNet.dll
"id": "EndlessAisle-Selection",
"name": "EndlessAisle-Selection",
"version": "1.0",
"protocol": "dll",
"baseUrl": null,
"basePath": "EndlessAisle_Selection",
"auth": {},
"dependencies": [
"EndlessAisle-Selection.dll",
"PDFNet.dll"
],
Best Practices
Our experience has taught us to respect some important practices when working with .NET DLL Interface Assets.
Facade Design Pattern
Your DLL may incorporate a lot of logic, with a mandatory initialization phase, complex object parameters and interactions between many involved classes. Our recommendation is to hide this complex logic behind a Facade, using the dedicated Facade design pattern. Furthermore, this pattern can be used to decompose the underlying complexity (such as Kinect Gesture recognition) to smaller and simpler parts.
INotifyPropertyChanged Interface implementation
Each time a method is called on an Interface Asset instance, every property of this instance is reevaluated and visual representations are updated in the Intuiface experience. This behavior implies significant side effects :
- If a method modifies the property value of another class instance, this change will not be caught by the associated Interface Asset.
- If your instance has many properties, a massive refresh can lead to performance issues.
To solve such potential issues, your class can implement the .NET INotifyPropertyChanged interface. In this case, you will have to implement code to notify the Interface Asset that a property has changed as the properties would no longer be checked by Intuiface after a method call.
In the property setter, make sure you call the NotifyPropertyChanged action passing the name of the property as the "info" argument. Ex below is: NotifyPropertyChanged("Quantity");
for a property named Quantity
Sample C# source code:
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private int m_iQuantity= 0;
public int Quantity
{
get { return m_iQuantity; }
set
{
if (m_iQuantity!= value)
{
m_iQuantity= value;
NotifyPropertyChanged("Quantity");
}
}
}
Display a list of items in an Collection
To feed a Collection like an Asset Grid, Asset Flow, ... with dynamic data, the best and easiest solution is the following:
- Use an ObservableCollection property in your .NET class to store your dynamic data
- When you import your .NET Interface Asset in Composer and drag and drop your IA in a scene, an Asset Grid will be automatically created, with its data feed bound to your ObservableCollection
- Create methods in your .NET IA to add / remove items in your ObservableCollection property. Thanks to the generated binding, your Intuiface Collection (Asset Grid, Flow, ...) will automatically be updated.
You can download the source code here. The Endless Sample has been removed from the Marketplace, please contact us if you want to access to the archived version.
If not done already, you should also check this article to see how to visually represent your dynamic data using a Data Template
Make your actions asynchronous
In Player for Windows, actions are called on the graphics thread and thus can block your UI if that action runs a resource-intensive algorithm.
There are lots of different ways to create an asynchronous method in .NET and it is up to the developer to make a choice. You can find an article about this topic in the Microsoft MSDN documentation.
Limitations
- A .Net Interface Asset with a cyclic reference of an object in multiple classes will cause StackOverflowException.
Comments
0 comments
Article is closed for comments.