dotNed

Welkom bij dotNed Inloggen | Aanmelden | Help
in Zoeken

Dennis' avonturen in .net

  • Terug naar de blogosphere.

    Ok. Ik weet het. We hebben het allemaal druk. Het is crisis/depressie/chaos of hoe je de markt ook wil noemen en dat betekent dat we allemaal een stapje harder moeten lopen. Is dat een reden om niet meer te bloggen? Nou uhm nee. Eigenlijk niet. Maar tel daar bij op dat ik de afgelopen maanden bezig geweest ben met het oprichten van een nieuw bedrijf, weken heb gemaakt van over de 130 uur (ik weet het, dat betekent meerdere nachten niet slapen maar werken) en je begrijpt dat mijn focus een tijdje ergens anders heeft gelegen.

    Maar die tijd is voorbij: ik ben weer druk bezig om orde in de chaos te scheppen en een van de gevolgen is dat ik weer veel meer tijd heb gekregen om zaken op te pakken die ik belangrijk vindt. Naast tijd voor mijn gezin houdt dat ook in dat ik meer tijd heb voor dotNed, de Surface user group en uiteraard het schrijven van artikelen, blogposts en het houden van lezingen. Goh, wat heb ik dat gemist.

    Dus.. ik ben weer terug en je hoort heel gauw nog veel meer van me!

  • CodeCamp 2009: Sessies en OpenSpace

    Als eerste: de sessies voor de CodeCamp 2009 zijn bekend en staan online op http://www.codecamp.nl We denken dat het een erg interessante mix van sessies is, met genoeg sessies voor iedereen om een aantal interessante onderwerpen voor iedereen. De agenda ziet er nu als volgt uit:

     

    Tijdslot Track A Track B Track C
    09:30 - 10:45 Around .net framework 4.0 in an hour (Ronald Guijt) ASP.Net - MVC 2.0 (Sander Gerz) Windows Mobile en het werken met data (Arjan van Huizen)
    11:00 - 12:15 ADO.NET EF 4.0 (Kurt Claeys) SharePoint Nightmares (Marianne van Wanrooij) iPhone development met jQTouch (Maurice de Beijer)
    13:15 - 14.30 VSTO 2010 met Office 2010 (Hassan Fadili) Modulaire Silverlight apps met Prism (Timmy Kokke) Microsoft Surface Development (Freena Eijffinger & Dennis Vroegop)
    14:45 - 16:00 VSTS 2010 (Pieter de Bruijn) Windows Identity Foundation (Michiel van Otegem) SQL Azure (Marcel Meijer)

    Naast deze sessies hebben we ook nog de OpenSpace sessies. Daar hebben we geen agenda voor maar dat ligt nu eenmaal in de aard van een OpenSpace gebeuren. In het kort komt het neer op het volgende: als je iets hebt waar je graag met een aantal mensen over wilt discussieren, schrijf je dat 's ochtends op een flip-over. Mochten mensen dat interessant vinden, dan kunnen ze een stem uitbrengen op dat onderwerp. In de lunchtijd (van 12:15 - 13:15) is dan de keuze aan de mensen waar ze heen gaan en aan welke discussie ze mee willen gaan doen. Heeft jouw sessie genoeg stemmen dan komen de mensen vanzelf wel naar je toe, zo niet: dan is je sessie blijkbaar niet interessant voor een grote groep. Het idee is dat we een aantal van deze sessies tegelijkertijd hebben zodat mensen kunnen kiezen wat ze doen. De inhoud van de lunch sessies laten we dus volledig aan de bezoekers over!

    Denk eens na over sessies of onderwerpen en discussieer mee met je mede-ontwikkelaars over jouw favoriete onderwerp!

    Ik kan haast niet wachten tot het 21 november is..

  • CodeCamp 2009: Call For Speakers

    Op 21 november 2009 organiseren de SDN, de dotNED User Group en VBcentral.nl samen de derde Nederlandse Code Camp. Een unieke dag, voortkomend uit een unieke samenwerking. Kenmerkend aan deze dag is, dat het een evenement is dóór ontwikkelaars en vóór ontwikkelaars!

    We zijn op zoek naar collega ontwikkelaars die het leuk vinden om ook een sessie voor hun rekening te nemen. Er is ruimte voor de meer traditionele sessies, maar bijvoorbeeld ook voor Chalk & Talk sessies. In principe is zijn de mogelijke onderwerpen zeer divers en worden door ons op voorhand niet beperkt. Ben jij geïnteresseerd om ook een sessie te doen? Laat het ons weten! Ook als je geen of nog niet zoveel sprekerservaring hebt ben je meer dan welkom. Indien je dat wilt willen we je hier best mee helpen.

    Het evenement vindt plaats in Rotterdam en meer informatie kun je vinden op de Code Camp website:www.codecamp.nl

    We zien graag jouw sessievoorstel tegemoet! Stuur deze zo snel mogelijk naar: andre@obelink.com.

    Een lijstje van onderwerpen waar deelnemers ondermeer om vragen:

    • Architectuur/Design patterns
    • Frameworks
    • Surface
    • .NET 4/3.5
    • Visual Studio 2010
    • VSTS
    • Open Source
    • SharePoint
    • ASP.NET/MVC/Web development/Silverlight
    • Windows 7
    • iPhone
    • DNN
    • VSTO
    • LINQ
    • SQL Server 2008
    • Geneva
    • BizTalk
    • Windows Presentation Foundation
    • Windows Communication Foundation
    • Windows Workflow Foundation
  • OpenCoffee was leuk!

    Op vrijdag 4 september hadden we bij dotNed de tweede OpenCoffee. Dit keer was de avond gesponsort door QDelft. De opkomst was beter dan verwacht: we hadden ongeveer twee keer zoveel mensen dan we eigenlijk verwacht hadden.

    Veel mensen die aanwezig waren kenden elkaar eigenlijk alleen via het online circuit, en dan met name via Twitter. Het was leuk om te zien hoe dat werkte: je zag mensen eerst voorzichtig aftasten ("hee, uhm, ben jij niet.") maar al snel werden de gespreken die eerst via Twitter verliepen doorgezet onder het genot van een biertje en een hapje. QDelft had de catering prima voor elkaar, er was genoeg te eten en te drinken voor iedereen, iets wat de sfeer enorm positief veranderde.

    De gesprekken gingen over allerlei verschillende onderwerpen. Uiteraard werd er veel over .net gesproken, maar ook andere onderwerpen passeerden de revue. Er zijn een hoop nieuwe contacten gelegd en oude contacten werden verstevigd. Het was dus een leuke manier om te netwerken.

    Wat mij betreft houden we binnenkort graag weer zo'n avond!

    Met dank aan Mendelt (met een passie voor Mono, dus mocht je een Mono expert nodig hebben moet je bij hem zijn :-) ) voor zijn inzet en uiteraard aan QDelft voor het hosten van deze avond!

  • OpenCoffee op 4 september

    Het is weer eens tijd voor een OpenCoffee / OpenBeer event bij dotNed. De meeste mensen zijn weer terug van vakantie, een mooie gelegenheid om bij elkaar te komen en te praten met je mede ontwikkelaars!

    Op een OpenCoffee zijn er geen presentaties, geen workshops en geen chalk 'n talks. Wel zijn er ontwikkelaars zoals jij, die graag over hun werk praten en ideeen willen uitwisselen!

    Deze OpenCoffee (uiteraard gratis, dit keer gesponsort door QDelft) vindt plaats op 4 september te Delft. Een routebeschrijving vind je hier. Aanmelden hoeft niet, maar we vinden het wel fijn als je even laat weten dat je langs komt. Dit in verband met de catering. Je bent van harte welkom vanaf 5 uur!

    Als je langs wilt komen stuur dan even een berichtje. Dat kan naar mij (dennis@dotned.nl of twitter @dvroegop) of naar de initiatiefnemer van deze OpenCoffee Mendelt Siebenga (twitter @mendelt)

    We zien je graag op de 4e!

  • Geslaagde launch van de Surface Gebruikers groep Nederland

    Logo_Sugar Donderdag 25 juni stond de dotNed meeting in het teken van Microsoft Surface. We hebben de avond benut om de nieuwe gebruikersgroep te lanceren, je vindt hier meer informatie over op http://surface.dotned.nl Sevensteps waren zo vriendelijk om een video impressie te maken, deze kan je hier bekijken.

    Wat mij betreft houden we gauw weer zo'n avond!

  • Surface, design challenges

    Surface is cool. Iedereen die er naar gekeken heeft is dat wel met me eens. Hoewel de hardware op het eerste gezicht niet echt indrukwekkend is (een tafel met een PC erin, dat is toch niets nieuws?) zijn er behoorlijk wat geavanceerde technieken toegepast. Niet voor niets heeft Microsoft meer dan 100 patenten aangevraagd op toegepaste ideeen in de tafel. De meeste daarvan hebben te maken met het projectie en vision gedeelte, ik neem aan dat er heel wat drempels overwonnen zijn om dit allemaal voor elkaar te krijgen.

    Het programmeren voor Surface is makkelijk. Nou ja, makkelijk voor mensen die ervaring hebben met WPF. Ook XNA kenners kunnen goed aan de slag met Surface maar ik denk dat 90% van de developers met de WPF versie aan de gang gaan.

    Als ik een demo geef aan mensen zegt iedereen dat het zo eenvoudig is om software te schrijven voor Surface. WPF, wat extra controls en meer heb je niet nodig. Iedereen kan het! We moeten echter niet vergeten dat 'die paar extra controls' heel wat manjaar werk in zich hebben: het is vaak zo dat hoe makkelijker iets in het gebruik is, hoe moeilijker het is geweest om het te bedenken en te bouwen.

    Maar goed,  hoewel de hardware dus best indrukwekkend is en de SDK goed in elkaar zit, is er eigenlijk niets dat ons tegenhoudt om hele mooie applicaties te schrijven voor Surface. Toch? Nou. er is nog een klein dingetje dat we moeten doen: het verzinnen van een goede applicatie voor Surface.

    En daar schuilt het grote probleem.

    Surface is een heel nieuw platform. Niet qua hardware en zeker niet qua software, maar wel voor wat betreft het gebruik.

    Surface is een platform voor de Natural User Interface (NUI). Dit is iets heel anders dan de Graphical User Interface (GUI) die we gewend zijn. Ik durf zelf te zeggen dat de overgang van GUI naar NUI net zo groot, dan niet groter is dan de overgang van Command Line Interface (CLI) naar GUI! En dat was al geen makkelijke stap!

    In een GUI maken we gebruik van metaforen. We maken afbeeldingen die iets voorstellen in de echte wereld. Denk aan een icoontje van een prullebak om aan te geven dat we iets weg willen gooien. Een tekening van een papiertje zal wel iets met afdrukken te maken hebben, en zo voorts. Ook het gebruik van de mousepointer, menus, windows en dergelijke zijn allemaal metaforen voor dingen uit het echte leven. De bedoeling is dat de gebruikers die zaken herkennen en snappen wat de bedoeling is. Dat dit niet altijd zo werkt wordt wel bewezen door de enorme hoeveelheid trainingen en documentatie die applicaties nodig hebben om duidelijke te maken wat de gebruiker met de software kan doen. Blijkbaar is voor veel gebruikers de mentale stap van abstract icoontje naar 'real-life' toch te groot! Voor de duidelijkheid: ik heb het niet over mensen zoals jij en ik: wij zijn dit gewend en we weten niet beter. Ik praat hier over de gemiddelde gebruiker die slechts af en toe achter een computer zit. Voor die mensen is het allemaal erg ingewikkeld!

    Een NUI gaat een stap verder. In plaats van een abstracte afbeelding maken we gebruik van echte, fysieke objecten. In plaats van gegevens op een formulier in te vullen met je naam en wachtwoord om in te loggen, leg je je visitekaartje neer op de tafel. De machine weet nu wie je bent, je hoeft verder geen actie te ondernemen. In plaats van iets te selecteren en dan op een knopje met een prullebak te drukken, sleep je een foto op het scherm naar een prullebak: zelfs mijn dochter van 6 snapt dat.

    De uitdagingen voor Surface zijn echter groter.

    In Surface kennen we in principe geen CurrentUser. Een applicatie kan gelijkertijd door meerder mensen bedient worden. Dat betekent dat als we een systeem schrijven we bijvoorbeeld geen acties kunenn maken die de state van de gehele applicatie veranderd. Een voorbeeld verduidelijkt dit:

    Stel, we maken een vingerverf applicatie. Op het scherm kunnen we een kaartje neerleggen met een kleur erop: op het moment dat bijvoorbeeld een groen kaartje neergelegd wordt worden alle vingerbewegingen op het scherm neergezet als groene strepen. Halen we het groene kaartje weg en vervangen we deze door een rode, kun je met rood verfen. Hartstikke leuk natuurlijk, maar wat als jij en ik nu samen aan onze versie van Mona Lisa bezig zijn? Ik wil het haar zwart maken, maar net op het moment dat ik met mijn vingers dat begin in te kleuren vervang jij het zwarte kaartje door eeen witte (want jij wilt de ogen inkleuren). Op datmoment kan ik niets meer doen: ik moet wachten tot jij klaar bent met wit.

    Daarnaast zijn wij, als traditionele programmeurs, gewend aan een aantal standaard metaforen. Zo zie je in veel applicaties een of andere vorm van een 'save' button om de huidige status op te slaan. Als je hier over nadenkt is dat best vreemd: in het echte leven doen we dat ook niet. Als ik iets op een papiertje schrijf hoef ik dat niet op te slaan. Dus in een NUI zou ik dat ook niet moeten doen!

    Nu is het niet zo moeilijk om software zo te schrijven dat de state altijd opgeslagen wordt. Maar wat als je nu de state voor meerdere cases wilt opslaan? In onze vingerverf applicatie wil ik een tekening kunnen maken, maar ik wil niet dat jouw tekening de mijne overschrijft (andersom vind ik persoonlijk niet zo erg :-) ) Hoe lossen we dat nou op? Dat kunnen we bijvoorbeeld doen door iedereen een object te geven (bijvoorbeeld een pasfoto). Op het moment dat die pasfoto op het systeem ligt weet Surface voor welke gebruiker deze tekening is. Als ik mijn foto weg haal en jij legt de jouwe neer, zal mijn kunstwerk opgeslagen worden en komt de jouwe tevoorschijn (indien het tekenen een groepsactiviteit is kunnen we een groepsfoto plaatsen.) Geen 'save' knop meer: altijd toegang tot mijn werk en ik heb geen toegang tot jouw werk. Precies zoals een normale gebruiker verwacht.

    Surface is een tafel. Het leuke van een tafel is dat mensen er om heen gaan staan. Het nadeel is dus wel dat je geen applicaties kunt maken die een duidelijke onder- en bovenkant hebben. Immers, als er tekst op het scherm staat is dat voor een persoon goed te lezen, maar de andere gebruikers kunnen daar niets mee (nou ja, ze kunnen het op z'n kop lezen maar handig is dat niet). Je moet dus rekening houden met dit aspect. Niet eenvoudig!

    Ik denk dat veel ontwikkelaars in het begin dit soort fouten gaan maken. Ook ik maak me daar nog steeds schuldig aan. Ik heb op zich een goede oplossing: mijn dochter van 6 is een geweldige beta tester. Hoewel ze niet begrijpt wat de systemen doen,  kan ze er wel mee overweg. De User Interface heeft geen geheimen voor haar. Als die geheimen er wel zijn, heb ik mijn werk niet goed gedaan.

    Ik hoef nu alleen nog maar even een killer applicatie voor Surface bedenken..

  • Introducing: Surface User Group Netherlands

    Logo Surface UG

    Met gepaste trots introduceren we een nieuw onderdeel van dotNed: de Surface User Group Nederland. We hebben een nieuwe Surface User Group Website (nog in ontwikkeling, maar de homepage staat er), een nieuw logo en veel nieuwe ideeen!

    We denken dat het introduceren van een nieuwe GG (gebruikersgroep, voor het geval je de afkorting niet kent) een aantal vragen opwerpt:

    • Waarom een nieuwe gebruikersgroep?
    • Waarom kan dit niet gewoon onder de vlag van dotNed?
    • Wat is uberhaupt Surface?

    In deze blogpost zullen we uitleggen wat het idee is en wat we van plan zijn met de nieuwe GG.

    Indien je niet weet wat Microsoft Surface is, raad ik je aan even naar de officiele Microsoft Surface Website te gaan. Daar kun je een voorproefje krijgen van wat het platform biedt.

    We denken dat Surface een concept is dat een revolutie in computer gebruik teweeg kan brengen. Het platform is dusdanig vernieuwend dat mensen niet goed weten wat het is en wat ze er mee kunnen. In tegenstelling tot het .net framework snappen veel mensen het concept van Surface niet helemaal.

    In de oprichtingsnotulen van dotNed staat dat het doel van dotNed is "het promoten van het .net framework en het verspreiden van kennis hierover". Nu is het promoten van het .net framework niet echt meer nodig: iedereen weet ondertussen wel wat het is en waarom het gebruik van .net een goed idee is. De laatste jaren houden we ons dus voornamelijk bezig met het verspreiden van de kennis over .net. Dat doen we door maandelijks een gratis bijeenkomst te organiseren, aanwezig te zijn op de diverse grote events en door middel van onze blogs.

    Voor Surface ligt dit anders. Ook hier geloof ik dat het belangrijk is om de uitgangspunten van dotNed uit te dragen, namelijk het promoten van het platform en het uitwisselen van kennis hiervan, maar het nut van Surface is nog niet bij iedereen duidelijk. We willen ons bij de Surface GG gaan richten op het beantwoorden van de onderstaande 3 vragen:

    WatWaaromHoe"Wat" gaat in op de vraag wat Surface nou precies is. Wat is het voor machine, wat is het concept erachter, hoe bestel ik er een, wat is de techniek erachter. "Waarom" is meer conceptueel: waarom zou ik als organisatie zo'n machine aanschaffen? Waarom is dat handig voor mij? Wat kan ik er allemaal mee dat mij een voorsprong op mijn concurrenten geeft? Met andere woorden: met het beantwoorden van de "waarom" vraag gaan we in het conceptuele niveau van Surface.

    "Hoe" is meer technisch: hoe maak ik nu applicaties op Surface? Hoe voldoe ik aan de guidelines van Microsoft? Hoe plaats ik een ElementMenu in mijn ScatterViewItem? (Mocht je niet weten wat een ElementMenu of een ScatterViewItem is, dan geven we daar natuurlijk eerst uitleg over :-) ) Naast de technische aspecten zullen we ook diep ingaan op vraagstukken op het gebied van User Experience. Het concept van Surface stelt hele andere eisen aan de user interface dan een Windows of Web applicatie.

    Je ziet dat we met deze 3 vragen verschillende doelgroepen bedienen. Met de "waarom" vraag helpen we de decisionmakers, met de "hoe" vraag helpen we de ontwikkelaars op dit platform. De "wat" vraag is uiteraard bedoelt voor iedereen die iets meer over Surface wil weten.

    Hoe bereiken we nu dat we de goede antwoorden geven? We hebben daarvoor een paar mogelijkheden:

    1. Blog posts. Dit is behoorlijk eenrichtingsverkeer, maar we kunnen daardoor wel veel informatie bij jullie kwijt
    2. Een forum. Dit zal de plek worden waar mensen vragen kunnen stellen en beantwoorden. Wij van dotNed zullen hier een actieve rol in spelen.
    3. Bijeenkomsten. We zullen regelmatig bijeenkomsten organiseren, bij voorkeur bij bedrijven die een Surface Unit hebben staan, om daar hands-on ideeen op te doen. Dit is uiteraard de beste manier om de Surface Unit van dicht bij te zien en er mee te werken.
    4. Lezingen geven. Om de wat/waarom vragen te beantwoorden zijn we altijd bereid om naar organisaties toe te gaan om ze daar uit te leggen wat Surface is en wat het voor kun kan doen (verzoeken even mailen naar dennis@dotned.nl ) Uiteraard geldt dit niet alleen voor commerciele organisaties maar ook op het gebied van onderwijs en non-profit organisaties
    5. Acte de presence geven op events van andere partijen. Denk aan een DevDays, SDN events en dergelijke.
    6. Delen van code libaries, met daarin 'best practices' voor het ontwikkelen op Surface.

    De mensen achter de Surface GG zijn allemaal early adopters van het platform. We hebben de trainingen gevolgd en hebben reeds een aantal applicaties opgeleverd op Surface bij onze klanten. We mogen dan ook wel stellen dat het kennis niveau behoorlijk hoog is, maar we willen altijd meer leren en weten wat er allemaal gebeurd op dit platform! De Surface GG wordt momenteel aangestuurd door drie personen:

    Mocht je dus bij een bedrijf werken die een Surface heeft, of worstelt met de vraag of ze er een (of meerderer!) aan moeten gaan schaffen, neem dan even contact op met ons zodat we kunnen kijken wat we voor elkaar kunnen betekenen!

    We zijn een community. Een community bestaat bij de gratie van de communityleden. Wij hebben veel ideeen, maar die kunnen pas tot leven komen als jullie mee denken en actief meedoen. Wat dat betreft is geen enkel verschil met dotNed, we zijn er voor en door jullie! We willen graag jullie ideeen horen. Dat kan op verschillende manieren:

    We hopen er met z'n allen iets moois van te maken!

  • Wildcard sessies op DevDays

    DevDays2009 De agenda voor de DevDays is helemaal gevuld. Een hele hoop sprekers komen op 28 en 29 mei naar Den Haag om zo'n 3000 ontwikkelaars in Nederland op de hoogte te brengen van wat er allemaal te doen is op het gebied van Visual Studio, Windows 7 en nog veel meer.

    Nou ja.. helemaal gevuld. Dat is niet helemaal waar. Er zijn twee slots opgehouden die door de community ingevuld mogen worden. Mensen kunnen een voorstel doen voor een sessie en de bezoekers aan de DevDays site mogen dan bepalen welke sessies gehouden mogen worden.

    Nu is het geval dat twee leden van de dotNed community, die de trouwe bezoekers aan onze meetings ongetwijfeld kennen, een sessie proposal ingediend hebben. Het zou leuk zijn als die twee sprekers hun kans krijgen om op DevDays te mogen spreken!

    Dus mijn verzoek is: kijk naar hun sessie voorstel en als je het een goede sessie lijkt, stem dan op ze!

    (Het feit dat de beide heren allebei Dennis heten heeft niets te maken met mijn verzoek om hun voorstellen te steunen :-) )

    De sessies zijn:

    Dennis Doomen: TDD and SOLID, two ingredients for high quality software

    "Many attempts have been made to improve the overal quality of our software development efforts, but if there's one I'd like to put some attention on, it's Test Driven Development. It's design-first, test-first approach has proved significant increases in overal quality. However, TDD is not easy and requires quite some understanding of proper object oriented design. S.O.L.I.D. is one of the better known acronyms referring to a set of very imporant design principles that both improve your ability to do TDD, but also make sure that your software is highly testable and maintainable."

    Stem voor deze sessie op deze pagina

    Dennis van der Stelt: If you build it, you'll ship it

    "Every developer is familiar with the phrase "It works on my machine". But what if you could claim your code can be deployed at any time of the day? Simply because the latest tested and verified version has been prepared for you on your build server. Not to mention with separate installation packages for both testing-, acceptance and production environment?"

    Stem voor deze sessie op deze pagina

  • OpenCoffee / OpenBeer event op 1 mei

    U vraagt, wij draaien.

    Al verschillende keren werd ons gevraagd om eens iets te organiseren waarbij de community bij elkaar kan komen om gewoon even over het vakgebied te praten, of zelfs over koetjes en kalfjes.

    Aangezien een community  bestaat bij de gratie van de inzet van de 'leden' willen we hier graag aan meewerken. Dus hebben we besloten de eerste dotNed OpenCoffee / OpenBeer middag te organiseren.

    Nu moet je je bij het woord organiseren niet teveel voorstellen: het enige wat we doen is een locatie beschikbaar stellen. Bij volgende bijeenkomsten kan dat ook in de kroeg bij jou om de hoek zijn!

    Op vrijdag middag 1 mei kun je bij Oosterkamp in Doorn (routebeschrijving) vanaf een uur of 5 langskomen om kennis te maken met de rest van de dotNed community. We hebben geen sprekers, geen agenda, maar wel een bar en een plek om als het regent te schuilen. Voor de rest is het aan jullie!

    Ik zou het wel waarderen als je even een mailtje stuurt naar dennis@dotned.nl of via Twitter (@dvroegop) als je langs wilt komen, kunnen we even in de gaten houden of dit levensvatbaar is.

    We danken Oosterkamp voor het beschikbaar stellen van de locatie!

    Wil je nou zelf een keer iets dergelijks organiseren, laat het me dan op bovenstaand email adres weten en we publiceren de gegevens op onze website en in onze nieuwsbrief.

    We hopen dat het een succes wordt!

  • WPF: Images laden in code

    Stom, stom, stom. Ik ben bezig met een stukje code waarin ik in WPF een image als brush wil gebruiken voor een 3D object. Normaal doe ik dat in de XAML code, maar aangezien het hier om de texture van een trackball gaat, wilde ik het in code zetten.

    Normaal doe ik het dus als volgt:

    <geo:DrawableGeometry3D GraphicType="Oiltank"                                       
                            Position="1 1 1"
                            Dimension="1.5 1.5 1.5" >
        <geo:DrawableGeometry3D.Material>
            <DiffuseMaterial>
                <DiffuseMaterial.Brush>
                    <ImageBrush ImageSource="pack://application:,,,/Images/CheckerBoard.png"/>
                </DiffuseMaterial.Brush>
            </DiffuseMaterial>
        </geo:DrawableGeometry3D.Material>
    </geo:DrawableGeometry3D>

    Met dit als resultaat:

    image

    In code lukte het me maar niet. Hoe kon ik nou de material aanmaken met een image? Het antwoord is natuurlijk: op dezelfde manier als in XAML, met een klein verschil. Dit is de code:

        1 DrawableGeometry3D sphere = new DrawableGeometry3D()
        2 {
        3     GraphicType = GraphType3D.Sphere,
        4     Position = new Point3D(0, 0, 0),
        5     Dimension = new Vector3D(2, 2, 2)
        6 };
        7 
        8 _ViewportTrackball.Children.Add(sphere);
        9 _CheckerBoardMaterial = new DiffuseMaterial();
       10 
       11 BitmapImage bmpImage = new BitmapImage();
       12 bmpImage.BeginInit();
       13 bmpImage.UriSource = new Uri("pack://application:,,,/Images/CheckerBoard.png");
       14 bmpImage.EndInit();
       15 
       16 _CheckerBoardMaterial.Brush = new ImageBrush(bmpImage);
       17 
       18 sphere.Material = _CheckerBoardMaterial;

    (Hier maak ik een bol, in de XAML code een afgeronde cylinder, maakt voor het verhaal niet uit). Het geheim zat hem in de regels 12 en 14. Je moet BeginInit() en EndInit() aanroepen, anders doet 'ie het niet.

    Waarom, vraag je je wellicht af, begin ik deze post nou met "stom, stom, stom"? Het antwoord is simpel.

    Ik had de BeginInit() en EndInit() niet staan. Dus ik kreeg exceptions. Dus ik ging debuggen. Dus ik ging zoeken. En niet vinden. Als ik echter 5 seconden de tijd had genomen om de Exception te bestuderen, dan had ik gezien dat er stond:

    {"BitmapImage has not been initialized.  Call the BeginInit method, set the appropriate properties, and then call the EndInit method."}

    Dat had me een hoop tijd gescheeld.. Zucht. Geleerde les? Lees de foutmelding! Er kan iets nuttigs in staan!

    PS Even ter mijn verdediging: bij de meeste fouten in mijn applicatie krijg ik alleen een algemene melding over de XAML die niet geladen kan worden, pas na 5 levels diep in de inner exception te graven kom ik bij de echte exception terecht. Dus ik lees ze amper meer. Niet slim, maar ja..

  • Named usercontrols en named children.

    Neem even de volgende code. Het is een standaard WPF Window met een Grid en een Button in de Grid.

    <Window x:Class="NameScopeTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid Name="myGrid" >
            <Button Name="myButton"/>
        </Grid>
    </Window>

    Niet echt spannend, zou ik denken. Nou heb ik echter in mijn code een eigen container nodig, om redenen die er even niet toe doen. Ik heb daarvoor een UserControl gemaakt en die ziet er als volgt uit

    XAML:

    <UserControl x:Class="NameScopeTest.MyContainer"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="300" Width="300">
        <Grid>
            <!-- This will hold the child controls -->
            <StackPanel Orientation="Horizontal" Name="myStackPanel"/>        
        </Grid>
    </UserControl>

    En de bijbehorende C# class:

    using System;
    using System.Windows.Controls;
     
    namespace NameScopeTest
    {
        /// <summary>
        /// Interaction logic for MyContainer.xaml
        /// </summary>
        public partial class MyContainer : UserControl
        {
     
            public UIElementCollection Children { get; set; }
            public MyContainer()
            {
                this.Children = new UIElementCollection(this, this);
                InitializeComponent();
            }
        }
     
    }

    In de Window1 XAML file krijg je dan het volgende:

    <Window x:Class="NameScopeTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:myStuff="clr-namespace:NameScopeTest"
        Title="Window1" Height="300" Width="300">
        <Grid Name="myGrid" >
            <myStuff:MyContainer>
                <Button />
            </myStuff:MyContainer>
        </Grid>
    </Window>

     

    Tot zover geen enkel probleem. Ik heb een namespace reference toegevoegd en vervolgens mijn MyContainer met daarin een Button in de Grid gezet. Het verschil met de eerste xaml file is dat ik in het eerste voorbeeld de elementen een naam gegeven hebt.

    Aangezien MyContainer afgeleid is van UserControl hebben we de Name property. Dus die kunnen we zetten, en ook op de button doen we dat gelijk maar even:

    <Window x:Class="NameScopeTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:myStuff="clr-namespace:NameScopeTest"
        Title="Window1" Height="300" Width="300">
        <Grid Name="myGrid" >
            <myStuff:MyContainer Name="myContainer" >
                <Button Name="myButton"/>
            </myStuff:MyContainer>
        </Grid>
    </Window>

     

    Compile, en. helaas. Dit gaat dus niet. Visual Studio geeft me een hele mooie foutmelding:

    Error    1    Because 'MyContainer' is implemented in the same assembly, you must set the x:Name attribute rather than the Name attribute. Line 7 Position 30.    C:\Users\Dennis\Documents\Visual Studio 2008\Projects\NameScopeTest\NameScopeTest\Window1.xaml    7    30    NameScopeTest

    We krijgen te horen dat we niet de Name property moeten gebruiken maar de x:Name. Deze twee zijn verschillend, maar functioneel doen ze min of meer hetzelfde (x:Name is de instance name van het object dat je maakt, net zoals je in de code behind je variabele een naam geeft. Name is echter een DependencyProperty. Nogmaals: functioneel zijn ze vrijwel gelijk).

    Ok, dan passen we de code aan en vervangen we <myStuff:MyContainer Name="myContainer"> door <myStuff:MyContainer x:Name="myContainer">

    Compile en. nee.  Nog steeds niet:

    Error    1    Cannot set Name attribute value 'myButton' on element 'Button'. 'Button' is under the scope of element 'MyContainer', which already had a name registered when it was defined in another scope. Line 8 Position 21.    C:\Users\Dennis\Documents\Visual Studio 2008\Projects\NameScopeTest\NameScopeTest\Window1.xaml    8    21    NameScopeTest

    WTF? Na lang zoeken blijkt dat dit standaard gedrag is. Een UserControl met een XAML erbij kan geen named-child elementen bevatten. Lastig, erg lastig. De oplossing? Geen UserControl als baseclass gebruiken maar Control. En dan de rendering zelf regelen.

    Dit werkt dan wel, maar het is wel veel lastiger (je moet nu alles wat je eerst in de XAML van je usercontrol deed zelf doen in de OnRender()). Ik snap niet goed wat de reden van deze beperking is, maar er zal wel over nagedacht zijn Weet iemand de reden voor dit alles?

    geplaatst Monday, March 23, 2009 10:33 AM door dvroegop | 1 Reacties
    Filed Under: ,
  • Open Space Code NL

    Geen dotNed event maar het lijkt er wel een beetje op gezien de aanmeldingen tot nu toe: de Dutch Open Space Code dag op 6 juni 2009. De locatie moet nog bevestigd worden, maar het lijkt me een dag die je niet kan missen. Een dag lang praten en coderen met andere ontwikkelaars, wat wil je nog meer? Voor meer informatie en inschrijven: http://openspacecode.nl/ 

    Ik ben er in ieder geval!

  • Maandag 9 maart: Code Contracts, Pex en CHESS

    PEXOp maandag 9 maart hebben we bij de Visual Studio Team System sectie van dotNed een bijzondere spreker. Jonathan "Peli" de Halleux, werkzaam bij Microsoft Research, komt naar Nederland om te spreken over Code Contracts, Pex and CHESS. Wellicht komen deze termen wat onbekend voor, maar dat is juist de reden om deze speciale meeting bij te wonen. Het thema van de avond is software reliability en testing.

    Naast zijn werk voor Microsoft Research is Jonathan ook bekend als auteur van MbUnit, diverse add-ins voor Reflector en projecten voor de fun. Ligt de kwaliteit van programmacode je aan het hart, dan is dit een unieke kans om niet te missen.

    De avond wordt gehost door de VX Company. Zoals altijd is de bijeenkomst gratis, inclusief een hapje en een drankje.

    Schrijf je hier wel eerst even in. 

    Let op: de inschrijving sluit eind dinsdag 3 maart dus wees er snel bij!

  • C#, C++, MessageLoops, P/Invoke en CLR Types: zucht.

    Bij Detrio maken we WPF software. Die software moet bediend kunnen worden vanaf een touchscreen. In Windows 7 en WPF 4.0 zit dat standaard ingebouwd; je hebt alleen de juiste hardware nodig. En die is gewoon te koop.

    Prima.

    Maar.... Windows 7 is nog in beta en WPF 4.0 is nog lang niet in zicht. En als dat al wel zo was dan duurt het nog een hele tijd voor het bedrijfsleven er aan wil. Helaas, maar het is niet anders. We moeten het dus doen met de spullen die nu op de markt zijn.

    Op kantoor heb ik de beschikking over HP hardware. Een daarvan is de TX2 laptop, met inderdaad een multi-touch scherm. In Vista is het gebruik ervan uitgeschakeld: Vista herkent maar een touch tegelijk. Ok, bij de HP zit software om foto's te bekijken en dat soort dingen die wel gebruik maken van multi-touch maar echt indrukwekkend is dat allemaal niet.

    Ik wil uiteraard mijn applicaties ook gebruik laten maken van de multi-touch mogelijkheden. Dus ik ben op een zoektocht gegaan naar hoe dat moet. Uiteindelijk kwam ik op de site van de leverancier van het scherm voor mijn TX2 terecht. Deze leverde een SDK waarmee ISV's (dat zijn wij dus, de independent software vendors) hun applicatie multi-touch enabled kunnen maken onder Vista.

    Helaas was alle code die er bij geleved werd in C++ en dat is toch niet echt meer mijn taaltje. Er zat ook een DLL bij en die kan ik vanuit C# prima gebruiken. Ik weet nog genoeg van C++ om de voorbeelden om te kunnen zetten in C# dus vol goede moed ging ik aan de gang.

    Stappen voor het verwerken van multi-touch events

    In eerste instantie zag het er allemaal heel eenvoudig uit. In principe moest ik het volgende doen:

    1. Importeer de methods uit de DLL
    2. Maak een connectie met de hardware (een methodcall)
    3. Registreer welke gestures je wilt ontvangen (zoom, rotate, scroll, etc)
    4. Registreer een Windows Message die verstuurd wordt als er een touch wordt waargenomen
    5. Vang die message in je MessageLoop af
    6. Vertaal de wParam en lParam in de juiste types (een enum en een struct)
    7. Doe iets met die info in je applicatie

    Er zijn 4 methods in de DLL die ik moet gebruiken. Deze zien er als volgt uit (in c++):

    void* NtrGesturesConnect();
    void NtrGesturesDisconnect(void* Handle);
    bool NtrGesturesRegister(void* Handle, TNtrGestures* data, HWND hWnd);
    void NtrGesturesUnRegister();

    De TNtrGestures is een struct met daarin alle gestures waarin je geinteresseerd bent. Die ziet er als volgt uit (weer c++):

    struct TNtrGestures
    {
        bool ReceiveZoom;
        bool UseUserZoomSettings;
        bool ReceiveScroll;
        bool UseUserScrollSettings;
        bool ReceiveFingersDoubleTab;
        bool UseUserFingersDoubleTabSettings;
        bool ReceiveRotate;
        bool UseUserRotateSettings;
    }

    Niet zo moeilijk, nietwaar? Je geeft aan welke gestures je wilt krijgen door de juiste velden op true te zetten (je kunt ook aangeven of je de raw data wilt of dat de data moet worden aangepast aan de voorkeuren van de gebruiker) en that's it.

    Importeren van de functies

    Dit moest even vertaald worden in C#. Geen probleem, doen we even!

    class Digitizer
    {
        [DllImport(@".\NtrigISV.dll")]
        public static extern IntPtr NtrGesturesConnect();
     
        [DllImport(@".\NtrigISV.dll")]
        public static extern void NtrGestureDisconnect(IntPtr handle);
     
        [DllImport(@".\NtrigISV.dll")]
        public static extern bool NtrGesturesRegister(IntPtr handle, TNtrGestures data, IntPtr hWnd);
     
        [DllImport(@".\NtrigISV.dll")]
        public static extern IntPtr NtrGesturesUnRegister();
     
        [DllImport(@"user32.dll")]
        public static extern uint RegisterWindowMessage(string lpString);
     
    }

    Een class gemaakt en daarin de methods gezet. Ok. Laten we eens gaan testen. Een WPF applicatie gemaakt en eerst een kijken of we kunnen connecten met de digitizer.

    Helaas. Dat gaat dus niet. De eerste foutmelding was een feit.

    Error1

    De DLL kon hij wel vinden, maar de method was niet beschikbaar. Ik heb 10 keer gekeken of ik geen typfout gemaakt had, maar dit is precies hoe het in de documentatie stond. Misschien was de documentatie fout? Was de naam toch anders in mijn versie van de DLL? De VS CommandLineTool DumpBin /exports NtrigISV.dll bracht uitkomt:

    image

    De method heet niet NtrGesturesConnect, maar die heet ?NtrGesturesConnect@@YAPAXXZ. Stom van me. Natuurlijk. Uhm.. WTF?

    Oh ja. Een ontwikkelaar die een DLL maakt met functies die geexporteerd gaan worden, moet dat wel even netjes aangeven met _declspec(dllexport) tijdens compileren: de C++ compiler genereert voor iedere functie een unieke naam om er voor te zorgen dat overloading blijft werken. Maar dat wil je niet bij geexporteerde functies. de _declspec(dllexport) zorgt ervoor dat de naam niet wijzigt. En dat is precies wat ik nodig had.

    Nou ja, geen probleem: je kunt functies ook uit een DLL halen op basis van hun volgnummer. De ordinals staan er keurig bij. De code wordt nu dus:

    class Digitizer
    {
        [DllImport(@".\NtrigISV.dll", EntryPoint="#1")]
        public static extern IntPtr NtrGesturesConnect();
     
        [DllImport(@".\NtrigISV.dll", EntryPoint="#2")]
        public static extern void NtrGestureDisconnect(IntPtr handle);
     
        [DllImport(@".\NtrigISV.dll", EntryPoint="#3")]
        public static extern bool NtrGesturesRegister(IntPtr handle, TNtrGestures data, IntPtr hWnd);
     
        [DllImport(@".\NtrigISV.dll", EntryPoint="#4")]
        public static extern IntPtr NtrGesturesUnRegister();
     
        [DllImport(@"user32.dll"]
        public static extern uint RegisterWindowMessage(string lpString);
    }

    De EntryPoint geeft aan hoe de functie in de DLL heet. Je kunt dus in je C# code andere namen gebruiken dan de schrijver van de DLL bedacht heeft. Ook kun je door een # te gebruiken de ordinal aangeven: feitelijk zeg ik hier: haal functie 1 op en noem hem NtrGesturesConnect. En dat werkte prima.

    Ik kan connecten! Het werkt als een trein! Nou ja, ik krijg geen foutmelding en dat is al heel wat! Stap 1 en 2 zijn gedaan (importeren en connecten), stap 3 is simpel (maak een instance van je struct aan, zet de juiste waardes op true). Nu stap 4. Registreer een Windowsmessage.

    De messageloop uitgelegd

    Ok. Als je niet weet wat Windows Messages zijn volgt hier een korte uitleg. Weet je het wel, sla dit dan gerust over.

    Windows werkt als volgt: het Operating System, de drivers en alle applicaties sturen elkaar voortdurend berichten. Ieder window kan een dergelijk bericht ontvangen en versturen. Events bestaan niet in Windows, het zijn allemaal messages. Iedere message heeft een nummer, ieder window (dat zijn dus alle windows op je scherm, maar ook alle dialogs en vrijwel alle controls ook: ja, ook een button is een window), heeft een unieke identifier, hWnd genaamd (oftewel Handle to WiNDow => hWnd).

    In je applicatie maak je een messageloop, die niets anders doet als de volgende pseudocode:

    Message = GetMessage();
    while( Message != WM_QUIT )
    {
      // Process message
    }

    Als windows vindt dat een applicatie moet stoppen, stuurt deze de WM_QUIT message naar je window en dan stopt de messageloop en ook je applicatie. Een Window kan ook alle messages voor zijn childwindows krijgen (de de window kan de message krijgen die aangeeft dat er op een button geklikt wordt).

    Feitelijk is dit wat er gebeurd in je Application.Run() aanroep in je main van je .net applicatie.

    Goed, dit is wel een enorme versimpeling van hoe het allemaal onder water werkt, maar voor nu is het genoeg.

    De messageloop in een WPF applicatie

    Hoe vangen we nu een message af in WPF? Onder water is ieder WPF form gewoon een window, dus er zit een messageloop ergens. Maar we kunnen er niet bij... Voor dit soort gevallen kent Windows het concept MessageHooks. Dit zijn methods die aangeroepen worden vanuit de messageloop en zorgen ervoor dat de messages ook terecht komen op de plek waar je er wel bij kunt.

    In de Window_Loaded event handler van je WPF form plaats je de volgende code:

    HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
    source.AddHook(new HwndSourceHook(this.WndProc));

    Met behulp van de WindowInterHelper class haal je de Handle van dit window op, met HwndSource.FromHwnd maak je een wrapper om de standaard windows window aan. Vervolgens roep je AddHook aan met een HwnSourceHook die de hook plaatst. De this.WndProc is mijn method die aangeroepen wordt als je een message ontvangt.

    public IntPtr WndProc(
        IntPtr hwnd, 
        int msg, 
        IntPtr wParam, 
        IntPtr lParam, 
        ref bool handled)
    {
        // Doe iets met de message...
        // als je hem afhandelt en niet
        // wilt dat Windows er nog iets mee
        // doet, zet je handled op true.
        return IntPtr.Zero;
    }

    Probeer dit eens en zet eens een breakpoint op deze method. Scrhik niet van de hoeveelheid messages die je ontvangt.... honderden per seconde is geen uitzondering. Uiteraard zijn we niet geinteresseerd in alle messages, alleen in de message die aangeeft dat er een multi-touch ding gebeurt is. Welke message is dat? Tja... die is niet bekend binnen Windows, tenminste niet tot we Windows 7 hebben.

    Door de Windows API RegisterWindowMessage aan te roepen kunnen we die message krijgen. Deze functie krijgt een string mee. Als deze functie voor het eerst sinds Windows is opgestart is wordt aangeroepen, zoekt Windows een nummer op die nog niet gebruikt is en geeft die terug. Als het al eerder aangeroepen is met deze string, krijg je de al eerder gegenereerde message id (want dat is het) terug. Het maakt dus niet uit wie als eerste RegisterWindowMessage aanroept, als iedereen dat maar met dezelfde string doet. Komt 'ie:

    _NTrigMessage = Digitizer.RegisterWindowMessage("NtrOnGestureWindowsMessage");

    We krijgen nu een Message Id terug, die de DLL zal gebruiken om ons te informeren over de gestures die gedaan worden. We moeten in onze messagehook (this.WindProc) deze even afvangen door een if(msg == _NTrigMessage).... te doen.

    wParam en lParam casten

    Op het moment dat er een message binnen komt, staat in de wParam wat er gebeurt is. De SDK defnieert een enum, die 1 op 1 over te zetten is naar C#:

    public enum ENtrGestureType
    {
        ScrollV,
        ScrollH,
        Zoom,
        Rotate,
        DoubleTap
    }

    We kunnen de wParam casten naar een ENtrGestureType en dan zien we wat er gebeurd is: was er een zoom, een rotate, iets anders? Maar we hebben daar niet genoeg aan. Als we een zoom binnenkrijgen, dan willen we ook weten hoeveel zoom er dan is. Is het inzoomen? Uitzoomen? Hoeveel? Die informatie wordt door de DLL in een struct teruggegeven:

    public struct TntrGestureZoom
    {
        public double mAmount;
        public ushort X;
        public ushort Y;
        public ushort Width;
        public ushort Height;
    }

    Rotate, ScrollH, ScrollV en DoubleTap hebben vergelijkbare structs met de relevante informatie.

    Maar hoe krijgen we die nou in onze applicatie? De voorbeeld code is simpel: ze casten de lParam naar een TntrGestureZoom*. Een pointer dus. Maar hoe doen we dan in C#? Op zich is het niet zo moeilijk: lParam is immers al een IntPtr oftewel een pointer. Maar die kun je niet eenvoudig omzetten naar iets wat wij kunnen gebruiken. De oplossing ligt in het gebruik van de Marshal class. Deze class bevat een aantal helpers die het werken met COM en P/Invoke vergemakkelijkt. Je moet even zoeken, maar dan vind je uiteindelijk de volgende oplossing.

    TntrGestureZoom data =(TntrGestureZoom) Marshal.PtrToStructure(tntrGestureZoom, typeof(TntrGestureZoom));

    Marshal.PtrToStructure maakt van de pointer naar de structure een echte C# structure van het juiste type. En nu kunnen we data uitlezen en kijken wat er gebeurdt.

    Vol spanning start ik de applicatie, doe een zoom met mijn vingers en....

    Ja! Het werkt! Ik krijg data door dat ik in of uitzoom, en hoeveel! Ik kan er iets mee! Ok, nu even roteren doen. Ik doe hetzelfde trucje met de Marshal.PtrToStructure maar nu voor de rotate struct, en probeer het weer. En weer. En nog een keer. En wat ik ook doe: geen enkel effect. Alleen de zoom werkt. Geen rotate, geen Scroll, geen DoubleTab.

    Zou mijn computer stuk zijn? Ik heb even de standaard HP software opgestart maar die werkt prima. Oh wacht even: werkt die wel op dezelfde manier? Even met Spy++ gekeken welke messages er naar de applicatie gestuurd worden en inderdaad: de officiele HP software roept niet dezelfde DLL aan. Zucht. Is de DLL misschien niet goed?

    Ik heb uiteindelijk mijn applicatie herschreven in C++. En wat schetst mijn verbazing? Het werkt! Rotate komt nu ook binnen! Het goede nieuws is dus dat mijn hardware goed is en dat de DLL zijn werk doet. Alleen in mijn C# applicatie doet het niet goed.

    Wees gerust: ik heb het opgelost. Het kostte me veel moeite, maar uiteindelijk kreeg ik het voor elkaar.

    Structs en booleans

    Ik vond het verdacht dat alleen Zoom het deed: dat is precies de eerste boolean waarde in de struct die aangeeft welke gestures ik wilde ontvangen. Zou de struct niet goed doorgegeven worden aan de DLL? Ik weet dat structs die naar dll gestuurd worden een bepaalde layout in het geheugen nodig hebben (alle velden staan keurig achter elkaar). Nou kan je dat expliciet aangeven dus dat heb ik maar even gedaan (hoewel het volgens MSDN niet nodig is!)

    [StructLayout(LayoutKind.Sequential)]
    struct TNtrGestures{   
        bool ReceiveZoom;    
        bool UseUserZoomSettings;    
        bool ReceiveScroll;    
        bool UseUserScrollSettings;    
        bool ReceiveFingersDoubleTab;    
        bool UseUserFingersDoubleTabSettings;    
        bool ReceiveRotate;    
        bool UseUserRotateSettings;
    }

    Ik geef hier aan dat ik alle velden sequentieel in het geheugen op wil slaan. Maar helaas. Ook dit hielp niet. Als ik ReceiveZoom op false zette en de rest op true, kreeg ik helemaal niets meer binnen. De struct werd dus wel doorgegeven. Maar wat is het dan?

    En toen wist ik het. Wat is een boolean eigenlijk? Hoe wordt dat doorgegeven? Na lang spitten kwam ik er achter dat een C# bool (alias voor System.Boolean) wanneer hij aan een C++ dll gegeven wordt, gecast wordt naar een int. En een int is 4 bytes groot. Een bool in c/c++ is 1 byte groot.... Even proberen: ik maak in mijn struct geen gebruik meer van bools maar van bytes. Alles wat ik op true wil hebben, zet ik op 1 en de rest op 0. Zo werkt dat immers in c/c++. En jawel hoor. De rotates en de zooms vlogen me om de oren.

    Toch was ik hier niet tevreden mee: het is immers geen byte in die struct, maar een bool! Ik wil in mijn WPF forms gebruik kunnen maken van boolean waardes en niet van bytes. Dus moet ik een wrapper class maken die de boel (woordgrapje, sorry) omzet?

    Nee. Er is een attribuut die je mee kunt geven om aan te geven hoe types gemarshalled (oftewel omgezet) kunnen worden. Bijna alle artikelen daarover zeggen dat het bijna nooit nodig is, want C# is zelf zo slim om de types juist om te zetten. Maar in die ene enkele gevallen waar het niet goed gaat... Affijn: dit is de struct geworden:

    public struct TNtrGestures
    {
        [MarshalAs(UnmanagedType.I1)]
        public bool ReceiveZoom;
        [MarshalAs(UnmanagedType.I1)]
        public bool UseUserZoomSettings;
        [MarshalAs(UnmanagedType.I1)]
        public bool ReceiveScroll;
        [MarshalAs(UnmanagedType.I1)]
        public bool UseUserScrollSettings;
        [MarshalAs(UnmanagedType.I1)]
        public bool ReceiveFingersDoubleTap;
        [MarshalAs(UnmanagedType.I1)]
        public bool UseUserFingersDoubleTapSettings;
        [MarshalAs(UnmanagedType.I1)]
        public bool ReceiveRotate;
        [MarshalAs(UnmanagedType.I1)]
        public bool UseUserRotateSettings;
    }

    En nu werkt alles zoals het moet. Ik krijg je juiste messages binnen, ik kan de lParam casten en alles werkt.

    Nu nog even uitzoeken hoe je een WPF ViewPort3D kan roteren en zoomen en  verschuiven zonder helemaal gek te worden van de Quaternion berekeningen. En nee: de standaard Rotate en Translate werkt niet.....

Meer Berichten Volgende pagina »

This Blog

Post Calendar

<March 2010>
SuMoTuWeThFrSa
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Syndication

Powered by Community Server, by Telligent Systems