Dit artikel is een vervolg op de sessie die ik op de afgelopen Cttm gegeven heb waarbij in gegaan is op het ontwikkelen van een (draadloze) toepassing op een Pocket PC. In deel 1 wordt nog eens een korte samenvatting gegeven van de applicatie ontwikkeling op basis van Visual FoxPro en een .Net webservice. In het volgende magazine zal deel 2 verschijnen waarin te lezen hoe een oplossing gevonden is om volledig vanuit Visual FoxPro de Pocket PC te kunnen communiceren. Er wordt dan geen gebruik gemaakt van .Net webservices.
Visual Studio.Net 2003 Final Beta
In vorige versie van Visual Studio.Net moest de software om te kunnen ontwikkelen voor handheld devices nog apart geïnstalleerd worden. Hiervoor bestond de ‘Smart Device Extension’ software pack. Na de installatie van dit onderdeel ontstond een extra keuze ‘Smart Device Application’ in het project type venster. Vanaf VS 2003 is dit geïntegreerd en derhalve direct beschikbaar. De functionaliteit is niet heel erg veranderd, alleen de support voor bepaalde type processors in nieuwere Pocket PC’s (waaronder de veel verkochte Compaq IPAQ’s en andere merken devices) is uitgebreid. Vooral de nieuwere type handhelds gaven met VS 2000 applicaties veel problemen.
Smart Device Applications
Applicaties voor handhelds kunnen onder VS 2003 ontwikkeld worden in verschillende talen, namelijk VB.Net, C#.Net en C++. Het hangt maar net van de voorkeur van de software ontwikkelaar (of klant) af welke taal gekozen gaat worden. De definitieve platform keuze, Pocket PC (2002) of Windows CE moet echter vooraf gemaakt te worden.
In de particuliere markt, waarin de de Compaq IPAQ veel gebruikt wordt, tref je vaak Windows Pocket PC aan, eventueel Windows Pocket PC 2002. De industriele handhelds daarentegen zijn vaak uitgerust met Windows CE of Windows CE.Net. Deze laatste is op dit moment nog slecht verkrijgbaar, omdat VS.Net voor CE.Net nog maar net uit het Beta-test stadium is en fabrikanten derhalve tot voor kort niet toegestaan werd door Microsoft om op basis van Beta versies apparatuur en firmware te ontwikkelen.
Verder moet er een structurele keuze gemaakt worden of er een traditionele Windows applicatie ontwikkeld wordt, of dat er de voorkeur aan gegeven wordt om een Internet Explorer gebaseerde toepassing te schrijven. Deze laatste heeft in principe mijn voorkeur. De reden hiervoor is dat de meeste IPAQ gebaseerde systemen een tijdelijk geheugen hebben die erg makkelijk verloren gaat wanneer de batterij volledig leeg raakt. Het geheugen is van het type DRAM wat constant spanning nodig heeft om gegevens vast te houden. Waarschijnlijk is er niet gekozen voor een niet vluchtig geheugen zoals bijvoorbeeld EPROMS omdat de toegangssnelheid hiervan te laag is en een EPROM bovendien na een paar duizend keer defect zal raken.
Het gevolg van deze ‘tekortkoming’ is dat de Pocket PC al zijn instellingen en software kwijt zal raken wanneer de batterijspanning niet langer toereikend is. Nadat het apparaat opnieuw opgeladen is en herstart wordt zal alleen het operating system nog aanwezig zijn. Daarin zit wel Internet Explorer zodat web gebaseerde applicaties het nog steeds zullen doen. (De source bevindt zich dan immers niet op de webserver).
Omdat ik in dit artikel echter niet in wil gaan op de webserver aspecten met mobile devices wordt er dit keer een applicatie ontwikkeld die op de Pocket PC geïnstalleerd moet worden.
Het samenstellen van een Smart Device Applicatie lijkt erg veel op het aanmaken van een normale Visual Studio.Net applicatie. Er zijn echter een paar hele grote verschillen. Een probleem bij het ontwikkelen van applicaties voor Pocket PC’s is de omvang van een applicatie die zeer beperkt moet blijven omdat een Pocket PC weinig geheugenruimte (circa 32 tot 128 Mb) en al helemaal geen schijfruimte beschikbaar heeft. Microsoft heeft hierop ingespeeld door het grote .Net Framework te verkleinen in een speciale ‘Compact’ uitvoering. Het gevolg hiervan is dat de omvang zwaar gereduceerd is (tot ongeveer 5%) maar dat een hoeveelheid functionaliteit ook niet beschikbaar is in het Compact Framework. Wat me zo in ieder geval te binnen schiet is het ontbrekende van de XML Xpath parser zodat het daarbij behorende SelectSingleNode() commando niet mogelijk is.
Ook ligt er een grote uitdaging om met de zeer beperkte schermafmeting van 320*240 pixels en afwezigheid van een handzaam toetsenbord een applicatie te ontwikkelen die gebruik maakt van de touchscreen mogelijkheden en de programmeerbare toetsen. Er is wel een toetsenbord beschikbaar maar dan in de vorm van een on-screen toetsenbord die bovendien de helft van je applicatie scherm wegsnoept. Niet echt handig dus…
StockDemo applicatie
Als voorbeeld in dit artikel wordt een applicatie ontwikkeld die via een webservice de voorraad opvraagt van een artikel waarbij de mogelijkheid wordt gegeven om de voorraad real-time aan te passen en terug te sturen naar de webservice.
Waarom webservices?
De eerste voorwaarde om met een Pocket PC te kunnen communiceren met een netwerk waarop een backoffice applicatie beschikbaar is die voorraad standen registreert is natuurlijk dat er een netwerkkaart in de Pocket PC beschikbaar is. Dit zal uiteraard een draadloze netwerk kaart zijn, die het IEE802.11Q protocol zal moeten ondersteunen. Dit is een algemene standaard om te communiceren binnen draadloze netwerken.
Symbol heeft voor de Compaq IPAQ een SPS300 unit ontworpen waar behalve een netwerk kaart ook een extra accu geplaatst is, samen met een barcode scanner. Op het moment van schrijven van dit artikel waren er echter nog geen .NET drivers beschikbaar voor deze unit, zodat nog niet het meest optimale gebruik van de barcode scan-unit mogelijk is. Verder wordt de unit volledig ondersteund vanuit .Net.
Er kan nu een verbinding gelegd worden met het netwerk waarbij via bijvoorbeeld ADO met recordsets gegevens uitgewisseld kunnen worden. De rekencapaciteit, geheugen en netwerk bandbreedte van een Pocket PC is echter beperkt zodat het beter zou zijn om het rekenwerk op een andere PC (lees: server) uit te laten voeren en alleen het resultaat terug te laten sturen. Dit concept bestaat natuurlijk al geruime tijd en heet ‘Webservices’.
Met het verschijnen van Visual FoxPro 8 zou het mogelijk geweest moeten zijn om een webservice te bouwen die een .NET compatibel dataset retourneert als object type via een XML Adapter. De XML adapter component werkt wel goed, maar het retourneren daarvan als object gaf in de beta versie van Fox 8 al problemen en het lijkt er op dat deze niet zijn opgelost in de RTM versie. Om die reden heb ik er voor moeten kiezen om een webservice in VB.Net te bouwen (wat zondermeer al verschillende voordelen heeft) en vanuit VB.Net VFP gegevens aan te gaan roepen. Zoals eerder beschreven zal in deel 2 van dit artikel aandacht worden gegeven aan een oplossing waarbij toch uitsluitend van Visual FoxPro gebruik gemaakt wordt voor de communicatie met de Pocket PC.
Visual FoxPro COM component
Een redelijk eenvoudige manier om vanuit een VB.NET webservice te communiceren met VFP is via Com. Onderstaande code beschrijft de COM component die is aangemaakt in VFP.
* main.prg
DEFINE CLASS application as Custom olepublic
cInfo='' && Property for info when function failed
FUNCTION init
SET EXCLUSIVE OFF
SET TALK OFF
SET ECHO OFF
SET ESCAPE OFF
SET CENTURY on
SET DATE DMY
SET MULTILOCKS ON
SET DELETED ON
SET HOURS TO 24
SET POINT TO "."
SET DECIMALS TO 2
lcDllPath=ADDBS(JUSTPATH(application.ServerName))
lcDbc=lcDllPath+'cttmstock.dbc'
* Open DBC
OPEN DATABASE (lcDbc)
* Open tables
USE products IN 0 AGAIN ORDER tag id
=CURSORSETPROP('buffering',3, 'products')
ENDFUNC
FUNCTION GetProduct(tnBarcode as Integer) as String
* Get product information
LOCAL lcXml
this.OnStartFunc()
* Find product
IF SEEK(tnBarcode, 'products', 'barcode') OR;
SEEK(tnBarcode, 'products', 'code')
lcXml=''+ALLTRIM(STR(products.id))+''+;
IIF(products.cancelled,'Y','N')+''+;
''+products.description+''+;
ALLTRIM(STR(products.price*100,12,0))+''+;
''+ALLTRIM(STR(products.stock))+''
RETURN lcXml
ENDIF
RETURN ''
ENDFUNC
FUNCTION GetStock(tnIdProduct as Integer) as Number
* Return stock amount of tnIdProduct
IF SEEK(tnIdProduct, 'stock', 'id_product')
RETURN stock.current_stock
ENDIF
RETURN 0
ENDFUNC
FUNCTION OnStartFunc
* Reset error info property
this.cInfo=''
ENDFUNC
FUNCTION destroy
CLOSE DATABASES all
* Garbage collection
SYS(1104)
ENDFUNC
ENDDEFINE
In deze code bestaat een functie GetStock() die als parameter de primary key van een produkt ontvangt waarvan de voorraad informatie gewenst is. De functie retourneert een integer met het aantal op voorraad van het aangegeven produkt.
Ook is te zien dat er een functie GetProduct() bestaat die als parameter een barcode ontvangt van het produkt waarvoor de informatie gewenst is. De functie codeert vervolgens een XML string met daarin alle relevante informatie over het gevonden produkt. Deze string zal straks door de VB.NET webservice ontrafeld worden en omgezet worden naar een dataset voor het Compact Framework.
Let verder eens op het gebruik van de Application.ServerName functie in de Init method. Deze functie retourneert het volledige pad naar een COM server, in dit geval StockIoMgr.dll. Je kan dit gebruiken om het pad te bepalen van de database die bij dit project hoort. In dit geval is er voor gekozen om de data in dezelfde map te plaatsen als de COM component zelf. In de Destroy method wordt een SYS(1104) gegeven. Deze SYS() functie is nieuw in VFP 7 en schoont het geheugen op. Mochten er bepaalde componenten zijn blijven hangen, als gevolg van bugs in Windows of VFP dan loop je niet het risico dat het geheugen van de server als gevolg hiervan uiteindelijk geheel volloopt met een systeemcrash of zeer beroerde performance als uiteindelijk resultaat.
Compileer deze PRG als multi-threaded DLL zodat de COM component later aangeroepen kan worden vanuit Visual Studio.
VB.NET webservice
In de voorbeeldcode is een webservice CttmStockDemoWebservice beschikbaar. In het webservice project is een reference gelegd naar de StockIoMgr.Application component die zojuist in VFP is aangemaakt.
Zoals al eerder even aangehaald heeft het aanmaken van webservices vanuit .Net veel voordelen. Een daarvan is dat het testen ervan veel simpeler en gebruikersvriendelijker is dan vanuit VFP zelf. Bij het compileren van de webservice verschijnt een HTML pagina waarop alle functies binnen de webservice getest kunnen worden.
Enkele andere voordelen van het ontwikkelen van webservices vanuit .Net:
1. Installeren van een nieuwe webservice (DLL en eventueel ASMX file) kan plaatsvinden terwijl er gebruik gemaakt wordt van de webservice. Probeer dat maar eens met een op COM gebaseerde VFP webservice!
2. Een .Net webservice hoeft niet geregistreerd te worden via REGSVR32
3. De definitieve URL van de webservice hoeft niet ingesteld te worden zoals wel het geval is wanneer gebruik gemaakt wordt van de WSDLGen in de Soap toolkit
En niet te vergeten: .NET webservices zijn ook te gebruiken vanuit VFP!
Tip: Het installeren van een nieuwe VB.Net webservice kan plaatsvinden terwijl er gebruik gemaakt wordt van de webservice. Wanneer er echter gebruik gemaakt wordt door de webservice van een VFP Com component (zoals in dit voorbeeld) en die Com component moet ook vernieuwd worden dan ontstaat het oude ‘Com probleem’ dat DLL’s alleen maar vervangen kunnen worden wanneer er door niemand gebruik van gemaakt wordt. Bovendien moet een nieuwe DLL beslist opnieuw geregistreerd worden via REGSVR32.EXE. De VFP DLL in dit voorbeeld wordt een bepaalde tijd door de VB.NET webservice vastgehouden die op zijn beurt uitgevoerd wordt door Internet Information Server (IIS). Door IIS te herstarten is de VFP DLL weer vrij om te updaten met een nieuwere versie. Het herstarten van IIS gaat het snelst vanuit een Dos prompt met het commando IISRESET.
Smart Device applicatie
Nu de webservice gereed is kan deze ook vanuit het Compact Framework gebruikt worden. Maak een nieuwe SDE applicatie aan in VS met de naam CttmStockDemoTest en geef daarna een rechter-muis klik op ‘References’. Kies nu voor het toevoegen van een web-reference. Je gaat nu een referentie vanuit het project maken naar een service op het web, een webservice. Geef als URL
en na even zoeken zal VS aangeven dat de webservice StockIoMgr beschikbaar is op dit Internet adres. Klik op ‘Add reference’, hierna zal de webservice te zien zijn in het Solutions venster onder ‘Web references’. Klik vervolgens op de webservice en hernoem deze naar StockIoMgr.
Let op: Localhost adres
Programmeurs die vaker met IP adressen te maken hebben gehad weten misschien dat het adres
het lokale IP adres voorstelt. De gedachte om
te gebruiken bij het aanmaken van een reference naar een ASMX webservice is op zich een juiste. Vanuit VFP of vanuit een VB.NET applicatie die op de webserver zelf wordt uitgevoerd werkt dit ook correct. Zodra je echter de software verplaatst naar bijvoorbeeld een Pocket PC (of emulator) zal localhost op dat moment gaan naar het IP adres van de Pocket PC zelf. Dat dat zal leiden tot een foutmelding omdat op de Pocket PC geen webserver draait behoeft eigenlijk niet eens vermeld te worden…Trap dus niet in deze valkuil, die mij zelfs weer overkwam toen ik nog wat aanpassingen maakte voor de Cttm sessie!
Performance
De aanroep van de webservice zal in de praktijk even tijd in beslag nemen. De tijd die nodig is wordt gebruikt om een verbinding op te bouwen met een webserver, de gegevens te serialiseren naar een XML stream, door te sturen naar de webserver, te wachten op antwoord, de antwoord stream te de-serialiseren en het resultaat vervolgens te tonen. In totaal kosten deze handelingen niet bijzonder veel tijd, maar wanneer er meerdere gegevens nodig zijn (zoals bijvoorbeeld de voorraad, de prijs en produkt omschrijving) kan het uitvoeren van meerdere webservice aanroepen maar beter voorkomen worden.
Zou het Compact Framework XML volledig ondersteund hebben, dan zou het mogelijk zijn geweest om een XML string te sturen in een webservice aanroep met daarin alle gewenste informatie.
1004.95Test produkt 1000
Helaas is de XML support behoorlijk afgekloven zodat een SelectSingleNode om bovenstaande XML string uit elkaar te peuteren niet mogelijk is. Via allerlei truuks kom je uiteindelijk wel op het gewenste resultaat maar het viel mij op dat de berekeningen die daarvoor nodig zijn te veel performance gaan kosten. Een VB.Net webservice is echter wel voorzien van de XPath navigator zodat een XML string vanuit VFP door een webservice wel behandeld kan worden.
In het Compact Framework worden datasets wel goed ondersteund. Een dataset is te vergelijken met de database container van VFP waarin zich meerdere tabellen bevinden. Bovendien kan een tabel in een dataset eventueel on-the-fly samengesteld worden. Een dataset kan via een webservice gepasseerd worden wat natuurlijk een groot voordeel is omdat nu via een tabel constructie met een enkele aanroep alle benodigde gegevens kunnen worden uitgewisseld.
De eerder beschreven stockiomgr.prg is al voorzien van een GetProduct functie waarbij behalve de voorraad ook alle andere relevante gegevens van een produkt worden geretourneerd. De webservice leest deze XML string en converteert die naar een dataset en stuurt die door naar de Smart Device Application.
Private Function MakeTable( ByVal nBarcode As Integer ) As DataTable
Dim myTable As New DataTable("Info")
Dim myColumn As DataColumn
Dim myRow As DataRow
myColumn =
New DataColumn("IdItem", GetType ( Integer ))
myTable.Columns.Add(myColumn)
myColumn =
New DataColumn("Cancelled", GetType ( Boolean ))
myTable.Columns.Add(myColumn)
myColumn =
New DataColumn("Description", GetType ( String ))
myTable.Columns.Add(myColumn)
myColumn =
New DataColumn("CurrentPrice", GetType ( Integer ))
myTable.Columns.Add(myColumn)
myColumn =
New DataColumn("CurrentStock", GetType ( Integer ))
myTable.Columns.Add(myColumn)
Dim oVfpStock As New stockiomgr.application
Dim cXml As String = oVfpStock.GetProduct(nBarcode)
Dim oXml As New System.Xml.XmlDataDocument
oXml.LoadXml(cXml)
myRow = myTable.NewRow()
myRow(0) = oXml.SelectSingleNode("product/id").InnerText
If oXml.SelectSingleNode("product/cancelled").InnerText = "Y" Then
myRow(1) =
True
Else
myRow(1) =
False
End If
myRow(2) = oXml.SelectSingleNode("product/description").InnerText
myRow(3) = oXml.SelectSingleNode("product/price").InnerText
myRow(4) = oXml.SelectSingleNode("product/stock").InnerText
myTable.Rows.Add(myRow)
Return myTable
End Function
Hier is te zien hoe de GetProduct functie uit de VFP Com component worden aangeroepen en hoe deze vervolgens met behulp van SelectSingleNode() commando’s wordt omgezet naar een dataset. De webservice method GetProductInfo kan eventueel getest worden in Internet Explorer zoals eerder beschreven.
StockDemo Smart Device Application
Nu de webservice een behoorlijke hoeveelheid informatie oplevert wordt het ook tijd om functionele Smart Device applicatie te gaan demonstreren. In de meegeleverde bestanden bevindt zich een project CttmStockDemo, een applicatie voor een Pocket PC die gegevens opvraagt over een produkt en vervolgens de mogelijkheid biedt om de prijs en voorraad te wijzigen.
In de solution explorer is te zien dat er een tweetal forms bestaan, frmMain en frmConfig. frmMain is uiteraard het hoofdscherm, zoals te zien in bovenstaande afbeelding. Het document frmConfig is het configuratie scherm wat op te roepen is via de menubalk links onderin het scherm.
Public
Class frmMain
Inherits System.Windows.Forms.Form
Friend WithEvents MainMenu1 As System.Windows.Forms.MainMenu
Dim nId As Integer = 0
Dim nStock As Integer = 0
Dim nPrice As Integer = 0
Dim StockIoMgr As New StockIoMgr.IoMgr
Private Sub ResetFields( ByVal lResetBarcode As Boolean )
If lResetBarcode Then
txtBarcode.Text = ""
txtBarcode.Focus()
End If
txtProductInfo.Text = ""
spnStock.Text = ""
txtPrice.Text = ""
chkDiscontinued.Checked =
False
btnSave.Enabled =
False
spnStock.Enabled =
False
txtPrice.Enabled =
False
nId = 0
nStock = 0
nPrice = 0
End Sub
Private Sub GetProductInfo()
'Reset previous data
ResetFields(
False )
Dim dsStockInfo As New DataSet
Try
dsStockInfo = StockIoMgr.GetProductInfo(txtBarcode.Text)
Catch ex As Exception
MsgBox(ex.Message & ex.GetType.ToString)
Exit Sub
End Try
txtProductInfo.Text = dsStockInfo.Tables("info").Rows(0).Item("Description")
spnStock.Text = dsStockInfo.Tables("info").Rows(0).Item("CurrentStock")
txtPrice.Text = dsStockInfo.Tables("info").Rows(0).Item("CurrentPrice")
chkDiscontinued.Checked = dsStockInfo.Tables("info").Rows(0).Item("Cancelled")
nId = dsStockInfo.Tables("info").Rows(0).Item("IdItem")
nStock = dsStockInfo.Tables("info").Rows(0).Item("CurrentStock")
nPrice = dsStockInfo.Tables("info").Rows(0).Item("CurrentPrice")
spnStock.Enabled =
True
txtPrice.Enabled =
True
btnSave.Enabled =
True
End Sub
Private Sub bntZoek_Click( ByVal sender As System.Object, ByVal e As System.EventArgs)_
Handles
bntZoek.Click
GetProductInfo()
End Sub
Private Sub MenuSelect( ByVal sender As System.Object, ByVal e As System.EventArgs)_
Handles
MenuItem1.Click
Dim frm As New frmConfig
frm.Show()
End Sub
Private Sub frmMain_Load( ByVal sender As System.Object, ByVal e As System.EventArgs)_
Handles
MyBase .Load
StockIoMgr.Url = Global.Settings.GetString(SettingKeys.URL)
StockIoMgr.Timeout = Global.Settings.GetInt(SettingKeys.Timeout) * 1000
txtBarcode.Focus()
End Sub
Private Sub frmMain_Quit( ByVal sender As System.Object, ByVal e As System.EventArgs)_
Handles
MyBase .Deactivate
ResetFields(
True )
End Sub
End
Class
Bij het starten van de applicatie wordt frmMain_load uitgevoerd die uit het configuratiebestand de URL haalt van de webservice en de timeout instelling van de webservice client. De cursor wordt vervolgens in het barcode veld geplaatst zodat de barcode gescand of ingevoerd kan worden. Nadat een barcode ingevoerd is en op ‘zoeken’ wordt geklikt wordt de functie GetProductInfo() uitgevoerd die via de webservice StockIoMgr een dataset ontvangt. De verschillende gegevens uit de dataset worden vervolgens overgenomen in de objecten op het scherm en er worden een tweetal variabelen nStock en nPrice voorzien van de actuele voorraad en prijs. De reden hiervoor wordt straks toegelicht.
Muteren van gegevens
Nadat de gegevens getoond worden kunnen ze worden gemuteerd en moet het resultaat opnieuw worden opgeslagen in de VFP tabellen. Door een tweetal functies UpdateStock en UpdatePrice met als parameters de produkt primary key kan de prijs en voorraad worden gewijzigd.
FUNCTION UpdatePrice(tnIdProduct as Integer, tnPrice as Integer) as Logical
* Update price of tnIdProduct
this.OnStartFunc()
* Find product
IF SEEK(tnIdProduct, 'products', 'id')
REPLACE products.price WITH tnPrice/100 IN products
IF !TABLEUPDATE(0, .f., 'products')
=AERROR(laDummy)
this.cInfo=laDummy[1,2]
=TABLEREVERT(.f. ,'products')
RETURN .F.
ENDIF
RETURN .T.
ENDIF
RETURN .F.
ENDFUNC
FUNCTION UpdateStock(tnIdProduct as Integer, tnStock as Integer) as Logical
* Update stock of tnIdProduct
this.OnStartFunc()
* Find product
IF SEEK(tnIdProduct, 'products', 'id')
REPLACE products.stock WITH tnStock IN products
IF !TABLEUPDATE(0, .f., 'products')
=AERROR(laDummy)
this.cInfo=laDummy[1,2]
=TABLEREVERT(.f. ,'products')
RETURN .F.
ENDIF
RETURN .T.
ENDIF
RETURN .F.
ENDFUNC
Hercompileer het VFP project opnieuw als multithreaded DLL. Wanneer het compileren niet lukt vanwege een ‘File Access Denied’ dan wordt de DLL nog gebruikt door de VB.Net webservice. Een manier om het gebruik op te heffen is door middel van het herstarten van Internet Information Server. Dit kan vanuit een Dos command prompt met het commando ‘IISRESET’.
Voeg daarna onderstaande code toe aan IoMgr.asmx in de VB.Net CttmStockDemoWebservice:
_
Public Function UpdateStock( ByVal nId As Integer , ByVal nStock As Integer ) As Boolean
Dim oVfpStock As New stockiomgr.application
Dim cXml As String = oVfpStock.UpdateStock(nId, nStock)
Return True
End Function
_
Public Function UpdatePrice( ByVal nId As Integer , ByVal nPrice As Integer ) As Boolean
Dim oVfpStock As New stockiomgr.application
Dim cXml As String = oVfpStock.UpdatePrice(nId, nPrice)
Return True
End Function
Compileer ook dit project opnieuw met F5 en test eventueel via de interactieve user interface of beide functies goed werken.
Door daarna de Smart Device applicatie CttmStockDemo uit te breiden met een Save button met onderstaande code kunnen mutaties worden opgeslagen in de VFP products tabel.
Private Sub btnSave_Click( ByVal sender As System.Object, ByVal e As System.EventArgs)_
Handles
btnSave.Click
If nStock <> spnStock.Value And Not StockIoMgr.UpdateStock(nId, spnStock.Value) Then
MsgBox("Bewaren nieuwe voorraad niet geslaagd!")
End If
If nPrice <> txtPrice.Text And Not StockIoMgr.UpdatePrice(nId, txtPrice.Text) Then
MsgBox("Bewaren nieuwe prijs niet geslaagd!")
End If
ResetFields(
True )
End Sub
Hier wordt dan ook het nut duidelijk van de twee variabelen nPrice en nStock die aangemaakt zijn: wanneer een prijs of voorraadstand niet gewijzigd is en de gebruik kiest voor opslaan zal deze mutatie niet worden uitgevoerd zodat de applicatie direct weer beschikbaar is voor scannen. Het zou immers jammer zijn van de kostbare tijd om een tweetal wijzigingen weg te schrijven terwijl er niets gewijzigd hoeft te worden. Ook ontstaat hierdoor de mogelijkheid om bijvoorbeeld wel de prijs te wijzigen maar niet het voorraad aantal zodat ook in dat geval er maar een trip over het netwerk zal plaatsvinden in plaats van twee.
Ten slotte
De laatste versie van de source code in Vb.Net en VFP bij dit artikel is te downloaden als WirelessIpaqDevelopment.zip van de SDGN website en bij
.
Biografie
Mark Vroom is software analist bij NedFox B.V. en momenteel bezig met de tweede fase van de uitrol van POS4All, de Point-Of-Sale applicatie van NedFox. Deze applicatie is ontwikkeld in Visual FoxPro en maakt gebruik van een scala aan moderne technieken zoals LiveUpdate, Messaging, Mobile Computing, VB.Net Web interface en XML in- en exports voor zowel produktiegegevens als systeemparameters. Daarnaast is hij op free-lance basis beschikbaar voor ondersteuning op gebied van applicatie analyse, development en implementatie in VFP, VB.NET en SQL.
Mark I. Vroom
Software analist NedFox B.V.
mark@nedfox.nl
http://www.nedfox.nl