I’ve always published content targeted to mid-level C# developers. However quite a chunk of emails that I receive are from people getting started with C#. Hopefully this article will be a path for these people, a guide on learning how to do an HMI step by step and get consistent progress. I’m also mentioning some advanced topic, so just scroll down if you are already familiar with C# and WPF.
I personally prefer videos instead of books for my learning, so here you’ll get more video resources.
My take on free online resources vs paid ones
I am a believer on free education resources. However I will also link paid resources in this article. While I’m not affiliated to the websites, I believe that time is an asset and you should choose carefully where you spend your time. If you are a student, then it’s fine if you spend tons of hours searching YouTube tutorials or blogs. If you need to get a project done on a certain deadline, it’s not a big deal to pay for answers.
The paid resource that I use the most is Pluralsight. It often offers discounts, 2 free weeks, free weekends, whatever. Is it mandatory ? No. Are you in a hurry ? Then yes. Is it worth the money ? Definitely yes.
I don’t know C#
To learn C#, Microsoft has a YouTube channel that has plenty of tutorials. In particular you can check playlists in the beginner series
C# 101 is for example a series of videos focused on learning the basics of C#.
If you are into books, I always liked Microsoft Visual C# Step by Step, but I believe there are tons of valid books out there, that’s what I read personally back then.
Getting the first window displayed
HMI are visual application, so once you know the basics C# and can run a console app, you need to display at least something to the screen. This means you have to learn the Windows SDK to develop Windows apps. There are tons of technologies available out there, what I’m referring here is WPF, or Windows Presentation Foundation.
Alternatives are Windows Forms (that also uses C#), Web Apps on Electron, Win32 apps, other proprietary frameworks like LabView etc.
I would discourage the use of UWP, because it’s sandboxed and has too many limitations. WPF has full access to the operative system and you want exactly that for an HMI.
To show your first window with WPF, you can refer to another Microsoft playlist: Desktop and .NET Core 101
Connecting a PLC to the app: driver selection
Once you can put labels and buttons on the window, you’ll probably want to connect a plc to the app. On this website I talk about some driver for the major brands, but market is always changing. So how do you search for a driver for your plc ? The answer is, you either pay for a commercial one, or you use an open source one and search on Github.
You can run a search, expand code, commits, filter for language, and you’ll get a list of repositories.
For example this is a how an advanced search looks like filtering for code and C#
It is important that you look for how active is the project, if there is a manual, how many issues are open and resolved, is anyone answering to the issues, etc.
My take on commercial drivers vs open source ones
Sometimes open source drivers have better quality than commercial ones. And often multiple people jumps on board and they improve the open source driver by submitting issues or patches. However with commercial drivers you get assistance and people dedicated to fix your problem. It’s up to you. I don’t have a specific recommendation here. But while on open source you can see the code and run away if it’s total garbage, without even the need to try it, on commercial drivers you can’t see the source code.
MVVM and frameworks to navigate between multiple windows
At this point you can show values from plc to the screen, and use buttons and textbox to change values. Now you probably want to create more pages and a navigation system so you can switch pages back and forth.
WPF navigation is based on swapping UserControls inside a Window. There are some examples of custom navigation on the website. You can roll your own, it’s completely fine.
I also suggest you learn about MVVM (Model-View-ViewModel), how DataBinding works, and start using INotifyPropertyChanged and ICommand on your app. Again tons of resources on YouTube.
Once you get to the point that you need a navigation stack, or you have quite a complicated navigation, my suggestion is that you use a framework to do that. What I usually use is PRISM. I don’t advocate it’s the best, but it works fine. To learn PRISM there are free videos on Brian Lagunas Youtube channel.
Paid resources you can find on Pluralsight, videos that I liked are the ones from Brian Lagunas. Be sure to sort for Recency when searching for tutorials on pluralsight.
Themes and UI personalization for WPF
Ok so the app is getting interesting but it’s ugly, so what about themes and stuff. First you have to learn about WPF controls.
Then regarding themes, you can find some on this website, but the two most used are
Pick what you like, go to the wiki, learn it and use it.
In an HMI you are probably going to need charts sooner or later.
A popular library is OxyPlot. There is extensive documentation and online resources on that. You have to be smart with points and performance, because it might get slow.
For other libraries, google is your friend. Charts are very popular components that can be find in either commercial or open source repositories.
App gets big, use git to keep track of changes and history
The times where developers were zipping the project, labeling with “proj_backup_20_1_23.zip”, and store it on a shared folder are ended. If you’re doing this, then you have to stop and learn git, because that’s how modern development is done.
There is a manual on this website, very simple, teaching the basics of git. That’s basically all you need.
Personally I use GitExtensions on Windows, I like it more than the standard git client and it makes my life easier.
I don’t use the git cli, unless I’m forced to. I prefer visual tools.
Alarms and events: use a SQLite database and store your alarms
Alarms and events are usually stored on database. The standard database for Windows Apps is SQLite. You can use whatever you like but that’s the industry standard.
To use SQLite you have to know the SQL language. You can use libraries that generates SQL queries and SQL commands (these libraries are called ORM, object-relational mapping). My advice is to use ORM, but you must know what’s going on under the hood, because if the generated queries are slow you must know how to fix them.
Again, for free education run a search on YouTube for SQLite C# tutorial
About ORM, some are simpler, some are more complicated and have more advanced features.
A simple to use library is SQLite.Net. If you never used a ORM before you might want to start with this one. It will get the job done for most apps.
To open SQLite files, I use SQlite Browser.
A special mention is needed for Akavache, that is a key-value store that uses SQLite. It isn’t fit to store data that are relational in nature, like alarms and events, but for other types of data, like recipes for example, it might be a good fit. I usually store json on akavache. You can check it out, it’s good if you need a key-value store.
Logging: Serilog and Appcenter
Logging is a critical part of the app. If you are not logging anything and the app crashes, you are blind and can only guess what’s happening.
In a WPF app you must at least log Unhandled Exceptions, and in particular:
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
DispatcherUnhandledException += (s, e) =>
e.Handled = true;
TaskScheduler.UnobservedTaskException += (s, e) =>
The library that I use for logging is Serilog. Again head to the wiki and see how to setup and search Youtube for tutorials.
What I personally do:
1- in development: log Debug or Verbose to a file and Output windows of Visual Studio
2- in production: log Error to a file and AppCenter
3- store the logger settings in the appsettings, so I can edit the appconfig file and switch to Debug at any time
When you are in production and you have no controls for the app, you can get the logs on AppCenter. Youtube again is your friend.
AppCenter is a free platform that let’s you track usage, crashes, errors, etc. So you can know about your crashes and fix them. This is how it looks like:
Installers: MSI packages, exe, etc.
Once you are ready to distribute your app, it’s better to create an installer package that contains all the dependencies.
My preference is to use WIX toolset. I did a video time ago showing how to produce an MSI package with WIX, it’s not up to date but concepts are still valid.
Other alternatives are Squirrel, or run a search on google for some paid ones, like InstallShield.
Visual Studio plugins to scaffold entire app infrastructure
There is a plugin that let’s you create a basic infrastructure of a WPF app from scratch: Windows Template Studio
It’s free and it’s common that I use it, not for the whole app architecture, but for some ideas. If you don’t know what’s going on, you can use it and learn what it’s generating and why.
Containers and Dependency Injection: do I need it ?
If you use frameworks like PRISM or MVVM Light, you probably get to use a Dependency Injection container.
Do you need it ? I would say yes. I would invest some time in learning it once you see the app grows to a certain size.
Basically all containers are the same, but you want to prefer containers that enforces the registration at startup and that are immutable.
Unfortunately Unity doesn’t enforce that and PRISM is very permissive.
My suggestion is, when using a DI Container, try to stick to constructor injection and registration of components at startup, even if your container let’s you do late registration or service location. To succeed with Dependency Injection, you need discipline in managing your dependencies.
Also I suggest to not use a Service Locator.
The bible of Dependency Injection is this book: Dependency Injection in .NET
Event driven apps: Reactive Extensions and ReactiveUI
This is kind of an advanced topic, I use Reactive Extension and ReactiveUI quite extensively in my projects because they fit nicely with the application architecture that I use.
Basically an HMI is an event based app, where events can come from the PLC (a value has changed, an alarm has been raised, …) or Human (button has been pressed, value has been changed on the screen, alarms has been resetted).
Sometimes it’s difficult to handle those events, especially when you have to combine, filter, throttle, etc.
On events you usually subscribe to them, run some logic in a callback and then unsubscribe. Merging these subscriptions can be quite difficult and lot of state changes and state tracking might be needed.
If you have those problems you should then check Reactive Extensions guide.
Reactive Extensions basically let’s you convert events on Observables, and offers you extensions to aggregate, filter, throttle, whatever operation you want to do with your events. All with very little code needed.
While you may never need it, you should at least be aware that they exists and some people (like me) likes to build whole apps on top of those concepts.
If you are interested in getting a deep understanding of ReactiveUI, there is the book You, I and ReactiveUI that goes very deep with all the features you need to know.
Domain Driven Design
Again this is another advanced topic, which you don’t need to know at the beginning but once your app grows big, you should be at least aware that this concept exists.
MVVM describes quite well how the architecture of the app should be, to decouple the View (xaml / code-behind) from the code that interacts with the view (viewmodel – model), to achieve a clear separation of concern.
The problem is that it’s not clear the difference between the ViewModel and the Model. You often hear:
The ViewModel is the one that has Binding and Commands, and the Model is everything else
But where to put the various components of the app like database queries, api calls, plc code, and other components you might need?
Domain Driven Design (DDD) puts some sort of order, telling that ok Model doesn’t exists, you have Domain Objects that are used through the app, they can be stored in the database as entities, mutated in viewmodels and displayed in the UI, etc.
It makes use of concept like App Services, DTO, Domain Objects and other components to define an architecture that is complementary to the MVVM one, to get a well structured and extensible app without dying in a spaghetti mess.
It’s quite an abstracted and difficult concept to master, and the best practical videos that really helped me in the day-to-day coding are on Pluralsight, in particular these courses:
- Refactoring from Anemic Domain Model Towards a Rich One
- Domain-Driven Design: Working with Legacy Projects
- Domain-Driven Design in Practice
The blog of the author is free, so you might want to check that here.
There is a fine line between concepts that helps you speed up your development and over-engineering over-architecting things. You have to find the balance that suits you.
CICD pipelines: Azure Devops
CICD stays for continous integration, continous delivering. These concepts are mandatory while working in a team, but they are helpful also if you are alone.
Let me explain you quickly how modern development works.
There is a project, the project is stored in a GIT repo, every developer can push to the git repo and clone the git repo and has access to the code.
This means that if you do some work, you create a new branch, code your feature, and when you finish it, you want to put your changes to the active codebase.
Now, in a team, there are all sort of problems that comes at this point, for example you might find that the code that you were working on has been changed by another developer and it’s causing a conflict, or that another developer changed the code and the app doesn’t build anymore, all sort of problems.
A CI pipeline is a tool that when you commit to a branch, it runs a build, runs the tests (if you coded some), verify that your app is fine and only then it let’s you merge your changes with the active branch.
Anyway the important take here is, run the build automatically at every commit, know exactly what commit break the build, revert that commit so a mistake from one developer doesn’t slow down the work of the entire team.
If you would like that at every commit someone builds the project for you, runs the tests, makes the installer as output and gives you a link to download the installer, then you might want to use a CI pipeline. It will also tell you when it fails, at what commit it fails, so a simple revert will save the day.
If you need this kind of tools, Azure Devops is free up to 5 developers, it has 1 free build agent and it just works.
Also GitHub offers these features, and others. I’m more familiar with Azure Devops.
A special mention is needed for Cake, that is a build automation system where you can define all the steps of your build. It runs on top of powershell and can be run as a script on Azure pipelines or whatever pipeline you use. Usually CI tools needs several steps to build your project, for example:
- run tests
- sign the assemblies
- package to an installer
If you use the CI tools to create those steps, it gets difficult to reproduce it offline. It’s better to write those steps with Cake and then run Cake either offline or as part of the CI pipeline with a simple powershell command.
Cake tutorials are available on YouTube.
Unit tests: do I need it ?
Last but not least, unit tests. This is another topic that you have to find the fine line where it doesn’t slow you, but instead it makes you faster.
If you don’t know, unit tests are code that runs your code and perform some checks. For example if you have a method like:
int Sum(int a, int b)
A Unit test would be something that calls that method with predefined values, like Sum(3,4), and verify the result, in that case you would write
var result = Sum(3,4);
Now things gets more complicated if you are performing an operation on a external dependency, like an http call to an external endpoint or a plc for example. Or test methods that aggregates multiple classes.
Anyway, before even considering unit tests you should be familiar with dependency injection and all sort of topics we discussed above, because unit tests works well with dependency injection and they should be run in a CI pipeline.
If you are developing an HMI and you are the only developer, then it might not be worth the time if the app stays small. It will pay back if there is quite a complicated business logic that is constantly being changed and extended.
So for example an app that it’s a 3 month work and then you forget it, might not be worth it. An app that you know you are going to keep extending and modify for the rest of your career in that company, then you have to consider adding unit tests.
In a team tests are mandatory, and especially if junior developers are on the team.
My general rule is to test the business logic and have high coverage for that, other areas it depends.
It’s a massive topic and if you want to know more, go on Youtube.
Ok we are at the end. There’s quite a lot, but it can be learned incrementally.
I wanted to write down most of what’s needed in a single post, without going too deep, and I encourage you to deepen your knowledge on those topics.
While it’s good to have a general overview of what’s out there, I suggest you to don’t get lost on problems that you don’t have. Keep things practical and get your project done. If you see you are slowing down with the development, especially if the app is reaching a certain size, you might find some suggestions on this article.
If you have questions, write on comments below.