Zoeken
Plugins tutorial 1: de basis
Deze tutorial omschrijft hoe voor de applicatie TLCGen een plugin kan worden opgebouwd. De tutorial verondersteld enige kennis van het werken met Visual Studio, en enige kennis van de programmeertaal C#. Voor het inhoudelijk opbouwen van de gebruiksinterface van de plugin is ook kennis van WPF en XAML nodig – dat valt buiten de scope van de tutorial.
Het complete Visual project met alle code uit deze tutorial kan hier worden gedownload. Merk op: de verwijzing naar TLCGen.Dependencies.dll (zie stap 1) zal moeten worden bijgewerkt voordat kan worden gecompileerd.
Basis opzet plugins in TLCGen
Een plugin wordt tijdens het starten van TLCGen door de applicatie uitgelezen en ingeladen. De plugin bestaat uit een dll (dynamic link library) met eventuele bijbehorende dll’s waarvan de plugin afhankelijk is (let op: deze moeten op een andere plek staan!).
Tijdens het starten van de applicatie, leest TLCGen de plugin dll’s uit, en zoekt in die libraries naar classes met het attribuut “[TLCGenPlugin]”. Wanneer een class dit attribuut heeft, maakt TLCGen een instance van de class aan, en gebruikt deze als plugin in de applicatie. Middels argumenten die worden opgegeven aan het attribuut, wordt aangegeven welke functionaliteiten de betreffende plugin heeft. Middels bitwise combineren kunnen hier meerdere waarden van de TLCGenPluginElems enumeration worden opgegeven.
In deze tutorial zullen we als voorbeeld starten met het pobouwen van een plugin die de groentijd van richtingen kan begrenzen op een instelbare waarde. In eerste instantie – in deze tutorial – zullen we middels de plugin enkel een tabblad met “Hallo wereld” aan de applicatie toevoegen. Vervolgens – in volende tutorials – bouwen we stap voor stap de verdere plugin op, zodat die kan reageren op berichten uit TLCGen, de bijbehorende data op kan laten slaan in de .tlc file, en deel kan nemen aan het genereren van CCOL code.
De basis: Hallo, TLCGen wereld!
Stap 1: de absolute basis
Start een nieuw project in Visual Studio 2017 (Let op! Gebruik geen eerdere versie van Visual!). Neem als type project “Class Library (.NET Framework”)” onder “Visual C#” > “Windows Desktop”:

Hernoem “Class1.cs” naar bijvoorbeeld “GroenBegrenzerPlugin.cs”. Visual Studio vraagt nu of de class in het bestand ook hernoemd moet worden: dat is handig, of moet anders daarna.
Voor het opbouwen van een TLCGen plugin moet het project een referentie hebben naar de TLCGen.Dependencies library. Deze wordt meegeleverd met TLCGen, of kan zelf gebouwd worden met de broncode van TLCGen (zie “zelf compileren TLCGen”). Voor het toevoegen van de referentie: rechtermuitklik op “References” in de Solution Explorer, vervolgens “Add reference”, en dan via “Browse” het bestand TLCGen.Dependencies.dll zoeken en toevoegen. Zie ook onder “Stap 3”.
Open nu het GroenBegrenzerPlugin.cs bestand en decoreer de class met het TLCGenPlugin attribuut.
Voor de AFM plugin ziet de basis class met het benodigde attribuut er zo uit:
[TLCGenPlugin(TLCGenPluginElems.TabControl)] public class GroenBegrenzerPlugin { }
Hiermee wordt aangegeven dat de AFMPlugin class een plugin is voor TLCGen, en wordt als functionaliteit van de plugin opgegeven dat die een tabblad heeft: het argument dat aan het TLCGenPlugin attribuut is opgegeven geeft aan dat de plugin een tabblad ter beschikking stelt, dat TLCGen op moet halen om weer te geven in de GUI voor de gebruiker. Doordat we werken in een namespace die ondergeschikt is aan TLCGen.Plugins, hoeven we nu geen using statement toe te voegen.
De plugin kan nu echter nog niets, en zal bij inladen door TLCGen een foutmelding opleveren, omdat de aangegeven functionaliteit (een tabblad) nog niet is geïmplementeerd.
Stap 2: implementatie van plugin functionaliteit
Voor elke vlag die wordt opgegeven bij het TLCGenPluginElems attribuut moet de class het bijbehorende functionaliteit implementeren. Dit verloopt via implementatie van een interface. Dit stelt TLCGen in staat de betreffende functionaliteit uit de plugin te gebruiken. De interfaces hebben enige overlap, want een plugin moet sowieso zijn naam ontsluiten, en een variabele hebben waarin een verwijzing naar de actuele regeling opgeslagen kan worden.
Het beschikbaar stellen van een tabblad verloopt via de interface “ITLCGenTabItem”. Via deze interface ontsluit de plugin het tabblad (als DataTemplate). Het interface biedt de mogelijkheid aan te geven dat het tabblad een icoontje heeft, en heeft een aantal methoden om bij selectie en deselectie van het tabblad actie te ondernemen.
De AFM plugin class ziet er na implementatie van het ITLCGenTabItem interface bijvoorbeeld zo uit:
[TLCGenPlugin(TLCGenPluginElems.TabControl)] public class GroenBegrenzerPlugin : ITLCGenTabItem { #region Fields private bool _isEnabled; private ControllerModel _controller; private const string _myName = "Groen begrenzer"; #endregion // Fields #region ITLCGen shared items public ControllerModel Controller { get => _controller; set => _controller = value; } public string GetPluginName() { return _myName; } #endregion // ITLCGen shared items #region ITLCGenTabItem public string DisplayName => _myName; public System.Windows.Media.ImageSource Icon => null; public System.Windows.DataTemplate ContentDataTemplate => null; public bool IsEnabled { get => _isEnabled; set => _isEnabled = value; } public bool CanBeEnabled() { return true; } public void LoadTabs() { } public void OnDeselected() { } public bool OnDeselectedPreview() { return true; } public void OnSelected() { } public bool OnSelectedPreview() { return true; } #endregion ITLCGenTabItem #region Constructor public GroenBegrenzerPlugin() { } #endregion // Constructor }
De code zal enige foutmeldingen geven. We moeten sowieso boven aan de file toevoegen: using TLCGen.Models;. Dit kan ook door op een rood gearceerd stuk code Ctrl+. te toetsen, en de juiste actie uit de lijst die verschijnt te kiezen. Pas na het volgen van stap 3 zal de code echter compileren, wegens het momenteel ontbreken van de juiste referenties voor gebruik van de namespaces System.Windows.Media en System.Windows.
De infrastructuur voor het opbouwen van de tabblad functionaliteit is nu aanwezig, echter zal de plugin nog steeds niet functioneren, omdat de eigenlijke functionaliteit nog afwezig is.
Stap 3: implementatie tabblad
We zijn nu echter klaar voor de eigenlijk implementatie van het tabblad! Als eerste moeten we de juiste referenties instellen voor het project in Visual. Omdat we zullen werken met WPF moeten worden toegevoegd:
PresentationCore
PresentationFramework
System.Xaml
WindowsBase
Dit gaat via een rechtermuisklik op “References” bij het project in de Solution Explorer:

De betreffende references zitten dan onder “Assemblies” > “Framework”.
Stap 3a: Toevoegen UserControl
Het project is nu geschikt om te werken met WPF. Als eerste voegen we de GUI toe voor het tabblad, in de vorm van een WPF UserControl. We zullen dit later als DataTemplate ontsluiten richting TLCGen.
Voeg een nieuwe WPF UserControl toe via rechtermuisklik op het project > “Add” > “New item”. Selecteer onder “Visual C# Items” het item “WPF”, en selecteer dan “User Control (WPF)” in de lijst. Geeft het een handige naam, bijvoorbeeld “GroenBegrenzerTabView.xaml”. Let op, dat geen Windows Forms user control wordt toegevoegd, maar een WPF user control!
Een leeg tabblad is ook maar zo leeg, dus in de traditie van programmeer tutorials zullen we een “Hallo, TLCGen wereld!” bericht toevoegen. Open hiertoe het GroenBegrenzerTabView.xaml bestand, en voeg het volgende toe tussen <Grid>
en </Grid>
:
<TextBlock Text="Hallo, TLCGen wereld!" FontSize="22" FontWeight="Bold" Foreground="DeepPink" Background="Gold" Margin="5" />
In Visual Studio zal het resultaat direct worden weergegeven.
Stap 3b: Ontsluiten tabblad via ITLCGenTabItem interface
TLCGen moet de UserControl die we net hebben aangemaakt kunnen vinden, om deze te gebruiken als tabblad voor weergave in de GUI. Hiertoe moeten we de ContentDataTemplate property van de plugin class aanpassen. Momenteel staat daar deze code:
public System.Windows.DataTemplate ContentDataTemplate => null;
Dit moeten we veranderen, zodat ons UserControl geladen kan worden. Dit kan bijvoorbeeld als volgt:
DataTemplate _ContentDataTemplate; public DataTemplate ContentDataTemplate { get { if (_ContentDataTemplate == null) { _ContentDataTemplate = new DataTemplate(); var tab = new FrameworkElementFactory(typeof(GroenBegrenzerTabView)); _ContentDataTemplate.VisualTree = tab; } return _ContentDataTemplate; } }
Bovenaan moet hiertoe “using System.Windows” worden toegevoegd. Deze code zorgt ervoor dat het tabblad wordt aangemaakt en op verzoek aan TLCGen wordt ontsloten. Voor de interne werking van deze code: zoek via een zoekmachine naar de documentatie van bijvoorbeeld de FrameworkElementFactory class.
Stap 4: aangeven plaatsing tabblad in TLCGen
TLCGen moet weten waar het tabblad geplaatst moet worden: als hoofdtabblad, of als subtabblad van een ander tabblad. Dit verloopt via een extra attribuut op de AFMPlugin class:
[TLCGenTabItem(-1, TabItemTypeEnum.MainWindow)] [TLCGenPlugin(TLCGenPluginElems.TabControl)] public class AFMPLugin : ITLCGenPlugMessaging, ITLCGenTabItem { ...
De -1 geeft hier de volgorde aan, waarbij -1 betekent: TLCGen bepaald zelf de volgorde, en zal het tabblad plaatsen ná de ingebouwde tabbladen.
TabItemTypeEnum.MainWindow geeft aan dat het tabblad direct in het hoofdvenster terecht zal komen. Een andere opties is het tabblad elders onder te brengen, bijvoorbeeld in het tabblad “Specials”: TabItemTypeEnum.SpecialsTab.
Stap 5: toevoegen van de plugin aan TLCGen
Om de plugin te gebruiken in TLCGen zijn er 2 mogelijkheden:
Kopiëren van de resulterende dll naar de Plugins map van TLCGen
De dll elders plaatsen (in een eigen map zonder andere dlls!) en via het register aangeven waar TLCGen moet zoeken
Voor nu maken we gebruik van de eerste mogelijkheid. Bouw eerst het project in Visual. Zoek de resulterende dll op in de projectmap, in de submap /bin/Debug (of Release).
Start nu TLCGen, en maak een nieuwe regeling aan of open een bestaande. Ons nieuwe tabblad zal nu in de GUI verschijnen (de tab heet in dit plaatje “AFM”, als overblijfsel uit een eerdere versie van de tutorial):

Gefeliciteerd! We hebben nu een volledig functionele plugin, en kunnen met de inhoudelijke werking van de GUI, de opslag van data en het genereren van code aan de slag!