Custom Modules

A MachineApp is a customized user interface that you can use to operate a machine that is controlled by an Automation1 controller. Custom Modules for MachineApps is a feature that lets you develop new modules that can be integrated and deployed with standard modules in a MachineApp.

Custom Modules interact with the Automation1 controller and other parts of the MachineApps Application with providers. A provider gives your Custom Module access to an instance of the .NET Controller object, which represents the connected controller in MachineApps. This lets you use the full Automation1 .NET API in your Custom Module. Other providers expose more features that your module can access, such as showing dialogs or notifications.

Custom Modules can also contain other functionality. A Custom Module can access the local hardware and file system of the computer where the Automation1 MachineApps application is running. Your Custom Module can reference other .NET assemblies, native DLLs, or configuration files. You can manage these files and your compiled Custom Modules through the MachineApps workspace in Automation1 Studio. Custom Modules can also rely on drivers or other installed applications or components when these dependencies can be found and/or loaded dynamically by your code that is running under .NET.

Additional Technical Details

Custom Modules are written in C#, use Windows Presentation Foundation (WPF) UI technology, and target the .NET 8.0 Long Term Support (LTS) runtime. Custom Modules reference several types that are part of the Automation1 MDK and are compiled for use with a specific version of Automation1.

Custom Modules inherently support the Model-View-ViewModel (MVVM) design pattern, which lets you specify one type for your DataContext (typically your ViewModel) and a different type for your UserControl. But you also have the flexibility to define all of your logic in the code-behind of your UserControl.

Automation1 MachineApps uses Dependency Injection and Reflection to create instances of your Custom Module types at runtime and give your Custom Module types instances of the Providers that they require. It is not necessary for you to call the constructor on your Custom Module or find the Providers that you need. The MachineApps Application does this for you when your Custom Modules are loaded with the standard modules that you add to a MachineApp.

Get Started with the Example Project

The CustomModulesExample is a Visual Studio Solution that shows you how to create a custom module. This project has two modules in it that show an MVVM and a non-MVVM method for creating a custom module.

Project Location

You can find the custom modules example project in the installation directory of the Automation1 MDK. The path to the example is: …\Aerotech\Automation1-MDK\MachineApps\Examples\CustomModulesExample.

Project Structure

The CustomModulesExample solution has two folders. One folder is for the Analog Inputs Module and the other is for the Analog Outputs Module.

Analog Inputs Module

This custom module uses the MVVM pattern by registering a view (AnalogInputsView) and a view model (AnalogInputsViewModel). When an instance of the module is created, the AnalogInputsViewModel is created and set as the DataContext of the AnalogInputsView. The view model implements INotifyPropertyChanged to let data binding occur. The view model also takes an IControllerProvider and an INotificationProvider as dependencies that are injected by the application when the module is created.

Analog Outputs Module

This custom module does not use the MVVM pattern. It has an AnalogOutputsView that defines the user interface in the AnalogOutputsView.xaml and has additional logic in the code-behind (AnalogOutputsView.xaml.cs). The AnalogOutputsRegistration sets the DataContext property to null to indicate that there is no view model in this condition. The AnalogOutputsView constructor can take providers as arguments that are injected by the application when the module is created.

Project Output

When you build the example project in Visual Studio, this process makes a dynamic link library (DLL) with the name CustomModulesExample.dll. This file contains all the things that are necessary for you to use the example custom modules in a MachineApp. But before you do this, you must use Automation1 Studio to upload the file to a controller. For information about how to do this, see the To Upload Your Custom Modules Configuration section of the MachineApps Workspace page.

API Overview

When you create a custom module, there are two specific types you will need. They are CustomModuleRegistration and CustomModuleMetadata. The CustomModuleRegistration type is abstract. It will be inherited from in order to register your module. It is not necessary for you to create an instance of this type. Studio and MachineApps will create instances through reflection when necessary.

CustomModuleRegistration

The CustomModuleRegistration type is an abstract class that is necessary to register a custom module with Studio so you can use it in MachineApps. When you use the Manage Custom Modules dialog in the MachineApps workspace to edit the custom modules configuration, Studio uses reflection to identify classes that inherit from CustomModuleRegistration and read the Metadata property for that module. This metadata is used by the MachineApp builder when it designs a MachineApp and provides information about the module name, type, and how you can use it.

The CustomModuleRegistration has two other properties. They are the UserControlType and the DataContextType. These properties are not instances of the module user control or data context. But these properties are their Type. When it is necessary to use an instance of a custom module in a MachineApp, the application creates an instance of the applicable type.

Tip: If you know a lot about the MVVM pattern, you can define the UserControlType and the DataContextType properties.

When the module is created, an instance of the view and the view model are also created. The view model is set as the DataContext for the view. If you do not use the MVVM pattern, then it is only necessary to define a UserControlType for your module. Refer to the example that follows.

Copy
public class MyModuleRegistration : CustomModuleRegistration
{
    public override CustomModuleMetadata Metadata => new CustomModuleMetadata("My Custom Module");

    public override Type UserControlType => typeof(MyView);

    public override Type DataContextType => typeof(MyViewModel);
}

CustomModuleMetadata

The CustomModuleMetadata type specifies information about your custom module.

The Name property specifies the unique name that will identify your module. The application shows it while you are designing a MachineApp.

The MachineAppModuleType property lets you put the module into Primary or Secondary regions when you design a MachineApp. The default value is MachineAppModuleType.Primary.

The ModuleOrientation property lets you limit secondary modules to specific regions. This property applies only if the MachineAppModuleType is MachineAppModuleType.Secondary. The default value is ModuleOrientation.Any.

The AllowMultipleInstances property lets you specify whether or not multiple instances of your custom module can exist in the same MachineApp. The default value is false.

The HasModuleToolbar property lets you specify if a module toolbar is added to your module. The default value is false.

To set more property values on the CustomModuleMetadata type, you must use the object initializers syntax when you construct the object. Refer to the example that follows.

Copy
public override CustomModuleMetadata Metadata => new CustomModuleMetadata("My Custom Module")
{
    MachineAppModuleType = MachineAppModuleType.Primary,
    AllowMultipleInstances = true,
    HasModuleToolbar = true,
};

Providers

Providers are types that are available for you to use in your custom modules. They can help you interact with the controller or the application. They also provide more features that your module can access. To use a provider, you must request it through dependency injection. To do this, include an argument with the type of the desired provided in your custom module user control or data context constructor. Make sure the type is one that is registered by the CustomModuleRegistration. When an instances of the module is created, MachineApps will provide an instance of the provider to the constructor. Refer to the example that follows.

Copy
// A Custom Module view model that takes a controller provider.
// Do not call this constructor. It will be called by
// MachineApps when your module is created.
public MyViewModel(IControllerProvider controllerProvider)
{
    this.controllerProvider = controllerProvider;
}

For more examples, see the CustomModulesExample project. Refer to the Get Started with the Example Project section of this page for more information.

The providers that follow are available:

Module Toolbar

The module toolbar shows the name of the module and lets you expand and collapse the module within the MachineApps application window. The CustomModuleMetadata class contains the HasModuleToolbar property that controls if the module toolbar is added to your module. The default value of this property is false. To add a module toolbar to your custom module, set the HasModuleToolbar property to true. You can only add the module toolbar to a primary module. The code example that follows shows how to add a module toolbar.

Copy
public class ExampleModuleRegistration : CustomModuleRegistration
{
    public override CustomModuleMetadata Metadata => new("ExampleModule") { HasModuleToolbar = true };
    ...
}

Add Controls to the Module Toolbar

By default, the module toolbar shows the name of your module and a button to expand and collapse the module. To add more buttons or text to the module toolbar, use the Aerotech.Automation1.Applications.Core library that has a ModuleToolbarHelper.ToolbarContent attached property that you can set in the XAML code of your custom module view. The value of the property must be a single FrameworkElement object. To add more controls, use a Panel element such as a Grid or a StackPanel.

To use the ModuleToolbarHelper.ToolbarContent attached property, you must add a mapping to the Aerotech.Automation1.Applications.Core namespace in the XAML of your custom module view. Then, add a ModuleToolbarHelper.ToolbarContent node inside the top-level UserControl node. Refer to the example that follows to see how to add controls to the Module Toolbar.

Copy
<UserControl    x:Class="YourApplication.YourModuleView"
        ...
xmlns:core="clr-namespace:Aerotech.Automation1.Applications.Core;assembly=Aerotech.Automation1.Applications.Core">
    <core:ModuleToolbarHelper.ToolbarContent>
        <aero:AeroButton Content="Click Me!" HorizontalAlignment="Left"/>
    </core:ModuleToolbarHelper.ToolbarContent>
    ...
</UserControl>

The data context for the controls that you add to the module toolbar is the same data context as your custom module view. Thus, controls on the module toolbar can bind to properties in the data context of your custom module.

Controls Library

The Aerotech.Automation1.Applications.Controls library supplies a set of common WPF controls that are styled like the controls in Aerotech modules. You can build a custom module with the controls in this library to make your custom module look like Aerotech modules.

How to Use the Controls Library

To use the Controls library, you must add the Aerotech.Automation1.Applications.Controls.dll library as a reference in your Visual Studio solution. Then, in your custom module view XAML, you must add a mapping to the Aerotech.Automation1.Applications.Controls namespace. You can use the controls in this namespace to create your custom module view. Refer to the List of Controls section to see the controls that are available. See the example that follows that shows how to map the Controls library namespace.

Copy
<UserControl    x:Class="YourApplication.YourModuleView"
        ...
xmlns:aero="clr-namespace:Aerotech.Automation1.Applications.Controls;assembly=Aerotech.Automation1.Applications.Controls">
...
</UserControl>

Appearance Property of Controls

The Controls library sets the Style property for each control automatically, so it is not necessary to set the Style property of a control. Some controls have more than one style that you can change with the Appearance property on the XAML element of the control. To see which controls support the Appearance property and the list of Appearance values for each control, refer to the List of Controls section. See the example that follows that shows how to change the appearance of a control.

<aero:AeroButton Content="Hello, world!" Appearance="Secondary"/>

The size and color of the controls use the Primary Color, Primary Hover Color, and Use Touch Sizing options in your MachineApp settings.

List of Controls

This section lists the controls that the Controls library supplies to you. The Control Name column lists the names of the controls that are found in the Aerotech.Automation1.Applications.Controls namespace. The Type Reference column lists the type of the control and links to the API reference for that type. The Appearance column lists the different styles of each control. The Control Style column shows you what each control style looks like.

Figure: Controls in the Control Library

Control Name Type Reference Appearance Control Style
AeroButton Button Primary (default)

Secondary

Link

AeroCheckBox CheckBox  

AeroComboBox ComboBox  

AeroRadioButton RadioButton  

AeroTextBlock TextBlock Paragraph (default)

This is the default.

Subheading

Heading

Title

AeroTextBox TextBox  

AeroToggle CheckBox  

Debugging Custom Modules

You can use Visual Studio or other IDE applications with debugging capabilities to debug your custom module. To do this, refer to the steps that follow.

  1. Build your custom module project with the Debug configuration.

  2. Set your Debug configuration build output folder as your Custom Modules working directory.

  3. Upload your working directory to the controller.

  4. Add your custom module to a MachineApp.

  5. Launch Automation1 MachineApps.

  6. Connect to your controller.

  7. Launch the MachineApp that includes your custom module.

  8. Open your IDE and attach its debugger to the Automation1 MachineApps application process.

Frequently Asked Questions