MVC In LabVIEW – Making More Modular Applications Easier
If you are reading around the internet on blogs like this you are also probably searching for the Mecca of clean, readable, maintainable code which is quick and easy.
OK, we all know that doesn’t exist but I have been working on a new MVC library that has the potential to help.
Model View Controller or MVC architectures appear to be somewhat of a staple of modern software design. The idea is that you divide your software into the three parts that interaction:
This helps to make your system more modular and easier to change, for example you should be able to completely change the GUI (View) without touching anything functional. There is a fairly well defined method of implementing MVC in LabVIEW using queued message handlers and user events.
I have been starting to work with Angular.js, an MVC (well MVWhatever) framework for JavaScript. In this, the view is provided by HTML & CSS pages and controllers and models are written in Javascript. To bring it together you simply reference items in the view that exist in the scope and Angular.js does all of the binding to keep these in sync. I had to have something this simple to allow rapid and easy development of MVC applications in LabVIEW.
Luckily whilst having these thoughts, the CLD summit happened here in the UK so I proposed trying to work through this idea as part of a code challenge section of the day and managed to find a group of (hopefully) willing programmers to work through the idea with this.
The Model
So lets start with the model.
Javascript has the significant advantage of being a weakly typed language. To emulate this and to avoid the headache of having loads of VIs to manage different datatypes we defined a model which uses variants at the core to store the data.
This will have a performance impact but you can’t have it all! To make things more interesting as well I have often found it can be useful to refer into the model by name as well (this might be something we need later). Therefore these data points can get stored into a variant dictionary so that we can recall them by name.
Note I have also wrapped the data items and models in objects which are in turn DVRs. objects because thats how I like to organise my code and helps to give these items a unique look, DVRs because fundamentally the model and datapoints should be common, wherever you access them in the program.
Then to access items we can update the item in the dictionary. Because we are using DVRs we actually only have to read the DVR back out and then we can update through the data class (which exposes a data write through a property node).
So the model is not to difficult and to be fair there are several libraries and similar methods as essentially this is a variable engine (CVT library for example).
The View
The bit that was bugging me was the data binding. There are ways that it can be done but I really didnt want the developer to have to write any code for this, it should be as simple as naming controls in a given way without having to add another whole process to your code.
There are two basic approaches possible:
- Polling: Angular.js actually uses a polling mechanism checking for value changes, I have used a similar solution to bind shared variables with OPC UA tags. This involves spawning a separate process and the extra complexities with controlling this.
- Events: Events are highly efficient but again, we want to avoid dealing with a parallel processes. This is where event callbacks seemed to solve the problems.
Event callbacks allow you to register for an event but rather than using an event structure to define the code, we can just define a callback VI which is called every time an event fires. This happens in the background without needing a parallel process.
Despite what the help file says, these currently work without issue for front panel events as well as activeX or .net events.
This allows us to bind the data items to controls (by registering for the value change event) or bind to indicators (register for a user event which the data point fires every time it is updated).
The final step is to be able to bind to the front panel automatically, this is the simple bit. There is a VI that finds all of the labels that match a pattern {dataname} and automates the binding process.
Where can I get it?
I have packaged this code on bitbucket. Please download the VI package and give it a try.
What Next?
Firstly, let me know what you think, it makes it much more fruitful to know people are trying it and (hopefully) enjoying it.
I have a few ideas for improvements including:
- Working out a good error handling system on the callbacks.
- Allowing the callback VIs to be replaced with custom versions.
- Saving and loading the model to/from file.
You can see the plans, or add bugs or features to the issues section on bitbucket.
Fabiola
June 26, 2014James,
Love how elegant and simple this approach is. This is also a good opportunity to collaborate via Bitbucket. This is the first time I try to collaborate on a public project, I was going to do a small change just to make sure I knew how to do it, but I am getting an “Access Denied” message when I do the pull request.
Is there something special I need to do to be able to do a pull request?
Thanks,
Fab
Fabiola
June 26, 2014Nevermind, found it! I was cloning instead of forking.
Thanks,
Fab
Michael (VI Shots)
June 27, 2014I hate when that happens.
Norman Kirchner
June 27, 2014You’ve created a global repository of all information, buyer beware. Would you make an application with global variables all over the place?
I like the idea of finding a good solution for functionally containing different parts of an application, but I think this one will lead to more issues w/ race conditions and memory performance issues than might seem at first glance.
Then again perhaps I’m missing something, I’m curious as to your thoughts.
~,~
Andrea
November 14, 2014It actually seems that using variant attributes to implement the dictionary is not a performance problem at all, actually more the contrary
http://ekerry.wordpress.com/2012/09/04/using-variant-attributes-for-high-performance-lookup-tables-in-labview/
Yair
November 16, 2014Andrea, there are two variants here –
The one Eli was referring to is the container, which is only used because it has the attributes mechanism and doesn’t actually have a value, so there’s no effect on the performance there. Eli was saying the performance was good because of the algorithm used to store and retrieve the attributes and that’s probably also why it’s used here.
The one James was saying causes an issue is the one that is actually stored as an attribute – that’s the one that appears as the data in the datapoint and has to converted/copied as needed when it’s written or read.
Patricio
August 19, 2022The repo is not found 🙁
James McNally
October 3, 2022Sorry – It must have been lost when moving everything off bitbucket. I’ll have to track down if I have another copy backed up.
Pen_Name
March 6, 2023Did you ever find this code? I’d be interested to look at it.
James McNally
May 4, 2023No Sorry, I think it was on a service that I closed down.