“Hey, that’s a great looking application! Where did you find those controls?”
Invariably, in the Microsoft .NET community, the answer is found on www.nuget.org.
Since the NuGet package management system gained popularity, software developers can browse through an amazing library of tools and add-ons, many of which are permissible to use and distribute under the the MIT license. I’ll be highlighting some of my favorites that have proven invaluable in the development of control software for precision mechatronic projects.
Mechatronics Specific Needs
At Simplexity Product Development, we work on a diverse repertoire of projects that require PC control of complex devices. These include sample preparation units, thermocyclers, QC (Quality Control) stations for consumable manufacture, and proof-of-concept testbeds used for process development. They often require multiple device connections over different protocols, extensive configurations, and precision integrated control of a machine.
Common to all of these is the large number of configuration parameters for setting device operation variables such as motor currents and voltage thresholds, as well as operation defining values for the specific device purposes. Reagent dispense volumes, number of temperature cycles, or pass/fail limits are a few examples.
These parameters must be made available to administrators and operators for editing, which means we need a control and value binding for each parameter. That’s a lot of UI items to manage for often a hundred or more pieces of data! Furthermore, requirements may dictate that some parameters are presented as a list of more complex types, such as a sequence of thermocycler time and temperature points, or a group of parameter inputs for a test process.
It’s common to need state machines to define and guide device operation. Typically, the state machines are quite complex, as they must conduct critical operations and handle error events flawlessly. Initial code infrastructure for state machines can be time-consuming to develop.
Read on as I highlight some of my favorite tools for setting up a new control application in record time!
Open Source and Free License Code Packages
Open source and free license libraries have been around for a long time, and whether you are a Linux aficionado or Python is your thing, you have been surely capitalizing on the plethora of time-saving package installations. And for free!
The .NET platform has been relatively slower to adopt this paradigm, as the development environment itself comes at considerable cost.
Third party .NET libraries historically cost quite a bit as well. Witness Crystal Reports- a stalwart yet expensive reporting package utilized heavily in all fields of commerce. Advanced graphing products are also popular and expensive. C# had been developed as a language for business, and the platform itself generates profitable tools.
But the development community is rather roguish by nature and will not tolerate stiff licensing fees. Microsoft eventually issued their Community edition (with licensing restrictions for educational and non-profit use only), and the NuGet package manager was incorporated into their IDE.
Admittedly, as a longtime .NET developer in the corporate realm, I avoided costs by relying on code re-use, internally developed libraries, and streamlining design before considering a third-party package.
Of course, I’ve always used the obvious NuGet packages like NLog or Newtonsoft JSON, but for my first state machine implementation years ago, I ported a C++ example we had developed internally rather than searching for 3rd party options. However, when a co-worker implemented a state machine solution based off a NuGet download, one that was ingeniously simple to implement, I realized every design decision I make should first consider the question: what NuGet packages are available?
If you are developing control applications for hardware systems, here are a few NuGet packages that will surely make your life easier.
Stateless
I’ll begin with the Stateless library because it is so incredibly easy to use. Stateless (an ironic name for a state machine infrastructure) is a wonderful library for setting up your device workflow. To define a state machine, you create event and state enumerations, associate each state with a function, and define allowable transitions and triggers (events). That’s it!
Let’s look at a simple example. Say we have a fluid dispensing station where we operate a series of pumps. We must load parameters based on scanned barcodes, prime and calibrate the pumps, and launch the dispense operation. We might define a set of states like DispenseState, as shown below.
Then we define the events, which are called “Triggers” in Stateless vernacular.
Next are the state initializations, which allow you to assign function calls to the state entry events, and define allowable transitions from each state:
State transitions are achieved by raising an event through a simple call:
One consideration in adopting the Stateless package is that it is not internally threadsafe, so multithreading details are left for the consumer to address.
This example is very high-level and omits the operational specifics, but have you seen a simpler state machine implementation? I think not!
Some additional useful features are:
• Asynchronous state entry calls
• Parameterized triggers
• Event subscription for monitoring state transitions
Stylet
The ViewModel first approach to development in the MVVM pattern has quite a few advantages, most notably a greater decoupling of the View from the ViewModel, allowing for:
• Dependency Injection
• View management for multiple devices
• View development requiring little or no code-behind
• Reduced need or likelihood of Dispatcher calls in the ViewModel
• Enhanced automated testing
All of these are fantastic pluses!
Let’s dig into Stylet, a svelte solution that makes your application code the ultimate in MVVM design. Stylet implements under the WPF framework an initial “Shell” View and ViewModel. It provides an Inversion of Control (IoC) container, where additional ViewModels and data objects are stored. We will suppose that we have an application with a Tab Control, and two Tab Pages.
Here is the initial structure of my new WPF solution as we begin. The Stylet package has been installed in a packages.config:
Stylet implements the following design patterns:
- Dependency Injection
- Inversion of Control
Therefore, a “Bootstrapper” is required to instantiate the containers for our dependencies. Sounds like a lot of work, doesn’t it? Not to worry! Also install the following package:
You will find that the Bootstrapper is generated for you:
Notice also that a “Pages” folder with the initial “Shell” View and ViewModel has been added. We are already on our way to MVVM design heaven! The App.xaml file has been updated with the Stylet “ApplicationLoader” resource, defining the Bootstrapper:
Next, add a tab control with a Stylet resource under the Pages folder:
I’ll also add a couple of Tab page controls and their ViewModels, which derive from the Stylet “Screen” class. In addition, we have a ViewModel for the Tab Control View. Naming convention is important here (View names end with “View”, ViewModel names end in “ViewModel”):
Now we tie it all together by adding the ViewModels to the IoC Container in the Bootstrapper. We do this in the “ConfigureIoC” method of the class that was generated for us:
We derive the TabViewModel from a Stylet Conductor, add a constructor with the Tab Page ViewModel input parameters, and add the pages to the Tab control:
And finally, we alter the ShellViewModel to set the active item to the TabView:
When we execute the project, we get a data-ready application shell that is easy to maintain, readily extensible, and appropriate to handle UI challenges of various device types:
I’ll continue with this example in the next section, where we will implement yet another design pattern that provides astounding ease in data development with a pleasing UI.
PropertyTools
I find it difficult to understand how Microsoft, a company that literally built itself on user experience, offers such uninspired UI controls in its frameworks. I suppose the reasoning lies in that the .NET development platform is so comprehensive, it is left as an exercise for the developer to create the desired enhancements. And thereby we seek NuGet packages such as PropertyTools and PropertyTools.wpf, a set of custom control packages that includes a specific component that is worthy of an MVP (most valuable player) award in mechatronics application development.
In the PropertyGrid control, a UI presentation is generated for display and editing of the public members of a given class. The PropertyTools NuGet packages supply this component in a manner that is far superior to the generic offering found in the .NET Winforms libraries (and which is outright omitted in WPF). It is polished enough to proudly include in your application, and even better, it allows for user data management at minimal cost in time.
Let’s look at the PropertyGrid in our sample application. We first install NuGet packages:
• PropertyTools
• PropertyTools.wpf
Next, we add a couple of classes:
• Data: class representing our mechatronic settings
• CustomControlFactory: factory class for building our edit controls
Our project now looks like this:
For the Data class, we’ll include a couple of members and implement the INotifyPropertyChanged interface below:
The control factory class derives from the PropertyTools factory object and implements the CreateControl method:
In the Bootstrapper class, we add initialization code to instantiate the Data class, and we add it to the IoC container. We also set Stylet’s default property change dispatcher in the Configuration method.
As we arrange the UI, we will organize the first tab page to contain the main application functionality, and the second will hold the application settings. They are named as such in the ViewModels. We include the Data class from the IOC container as an input parameter to the constructor of the second tab ViewModel, where we assign it to a class member, as you can see below.
Finally, in the view XAML for the second tab, we include the namespace for PropertyTools, add the PropertyGrid control, and assign data and factory types:
We now have an application framework that not only supports IoC and Dependency Injection, but also implements a factory to build the control structure for the data in the IoC container:
Note in the image above how PropertyTools presents the data in a readable fashion with spaces inserted into the parameter names and controls arranged in a general “miscellaneous” group box. We can customize these by adding some annotations:
The controls are fully bound to the data members, and you can simply add more data and generate the corresponding UI items.
Let’s finish up by presenting an example of a more complex data type, a list of data objects that may represent a set of process steps. We first create the class representing a single step, derived from INotifyPropertyChanged.
We add an ObservableCollection of the new type to the Data class:
Below is the result – a DataGrid in which you can add or delete complex data objects to your class collection:
Amazing! Once you add a data member, the editing control is generated for you. The tedious XAML editing and data binding steps for each piece of data including the complex data grid are no longer needed.
There are, of course, some limitations. Some examples are:
- Data grid column names are not changed with DisplayName annotations.
- Data binding triggers are obfuscated and occur on control loss of focus by default.
- The data grid does not produce scrollers, so column widths are sized to fit the control space. I’ve solved this by hosting the generated control in a ScrollViewer.
Thank a NuGet Publisher!
If you are a software developer responsible for controlling scientific or manufacturing devices, you have plenty of tasks on your plate beyond the routine concerns of input data management, workflow infrastructure, and extensibility. In fact, almost any coding challenge you face has assuredly been addressed in some part by those who generously publish their code as a NuGet package. We thank you all!