Fortfarande nöjd med den lösningen? Hur pass integrerad blir den med C#-kod, har inte provat använda C++/CLI ännu?
Lösningen blir GRYM!!! Jag har kört/jobbat på den någon vecka nu och den smäller inte en enda gång. Fördelen med C++/CLI är att jag kan prata unmanaged/native med telldus-API:t (direkt med libbet) precis som från vilket C++-program som helst, MEN jag exponerar också managed .NET-klasser mot .NET-världen. OCH jag kan göra detta utan unsafe, stökig interop, marshalling och liknande.
Av erfarenhet kan jag säga att ger man sig in i unsafe-marshalling-träsket så har man en lång och jobbig väg att vandra...
Hur som helst! Min lösning består av två lager...
Längst ned hittar du C++/CLI-lagret som nästan ett-till-ett översätter från Telldus-API till en .NET-klass. Samtidigt så introducerar jag enums för en del konstanter och ersätter de hemska callbacken med civiliserade .NET-events. Felkoder översätts också till exceptions. Det här lagret betraktar jag som färdigt för mina ändamål. Jag har då hoppat över funktionerna som hanterar olika tellstick-enheter, som till exempel tdConnectTellStickController(). Jag skulle kunna lägga till det innan jag delar med mig...
Över det lagret hittar du ett lager skrivet i C# som vidare översätter till en
objektorienterad modell som gör det ännu mer nice att använda. Anledningen att jag inte har gjort allt i C++/CLI är att det är rätt stökigt att använda. Man ska aldrig göra mer än nödvändigt i C++.
Det är det här lagret som din applikation är tänkt att använda. Till exempel:
1. Enheter wrappas i en klass som heter Device som har properties som Name, Protocol osv... och metoder som TurnOn, TurnOff osv... Samma sätt med sensorer som hamnar i en klass som heter Sensor och kommandon från fjärrkontroller och liknande hamnar i klassen Command. Ett objekt av typen Device eller Sensor blir dessutom automatiskt uppdaterade, till exempel om någon släcker lampan eller en ny temperaturavläsning sker.
2. Objekt av typen Device läggs i en ReadOnlyObservableCollection<Device> vilket gör att man kan databinda direkt till det från en WPF-applikation. ÄR INTE DET HÄFTIGT? Det samma gäller Sensorer. Så ett testprogram som visar enheter och sensorer kan man nästan helt skriva i XAML. Tas en enhet bort, från till exempel Telldus Center, så tas det automagiskt bort ur sin collection också.
3. Det här lagret introducerar också .NET-events som DeviceAdded, DeviceRemoved, SensorUpdated osv...'
4. Trådbytet görs också automatiskt så att event från Telldus kommer in på den tråd du använde för att skapa wrappern. Så gör du "Tellstick myStick = new Tellstick()" från GUI-tråden så blir det på GUI-tråden som alla events rasar in. Det är ju så man vill ha det, eller hur?
5. Dubletter på temperaturavläsningar och kommandon filtreras bort. Ofta skickar ju en termometer sitt värde flera gånger som en skur. Dessa filtreras bort. Annars skull det utlösa en kaskad av GUI-uppdateringar om man använder databindningar.
Det här lagret är inte färdigt. Bland annat skulle jag vilja stoppa in metoderna TurnOn, TurnOff, Dim, Execute osv... i properties så att det går att databinda mot dem från WPF. Det är lite sådant smått och gått som återstår.
Hur pass integrerad blir den med C#-kod
Svar: du får civiliserade .NET-klasser som ser ut och uppför sig som vilka .NET-klasser som helst. Du behöver inte anropa Init()/Close() eller tänka på någon typ av uppstädning. Dessutom är allt objektorienterat, till skillnad från Telldus .NEt-wrapper. Att använda den kändes som att programmera old fashioned ANSI-C fast i C#. Du har också .NET-event tillstället för callbacks. Exceptions istället för felkoder. Enums istället för konstanter.
Vill du dela med dig av den?
Absolut! Med ett par ögon till kanske jag kan få tipps på hur den kan bli ännu bättre. Jag vill bara se över namnsättningar, kommentarer och fila till det sista. Ge mig någon vecka så delar jag med mig av koden. Påminn mig om jag glömmer...
Ett kodexempel i C# hur man använder min wrapper (Jag har inte kompilerat, utan det är mer för att illustrera...)
Code: Select all
{
Tellstick myTellstick = new Tellstick();
//Print all devices
foreach(Device device in myTellstick.Devices)
{
Console.WriteLine("\nDevice name: " + device.Name);
}
//Rename device at index zero (assuming there is a device at index zero)
myTellstick.Devices[0].Name = "Foo";
//Turn on device (assuming there is a device at index zero)
if(myTellstick.Devices[0].SupportsTurnOn == true)
{
myTellstick.Devices[0].TurnOn();
}
//No need to clean up
}