Daily Archives: 2008.04.19. 8:09

Word dokumentum generálása adatkötéssel – 4. rész: Kapcsolat

Ahogy az előző részben láttuk, a content control-ok vagy más néven a structured document tags szolgáltatás az Office dokumentumokban lehetővé teszi a formázás és az adatok elkülönítését. Két korlátozó körülményt azonban mindenképpen meg kell említenünk:

  1. Ez a szolgáltatás egyelőre csak a Word 2007-ben érhető el, az Office család más termékeiben nincs ilyen lehetőség.
  2. Elég fájó, de sajnos nincs táblázat vezérlő, sőt az ismétlődéseket (pl. felsorolásokban) sem tudja kezelni ez a funkció. Mivel ez sokaknak fáj, ezért várhatóan az Office 14-ben vagy talán már egy javítócsomagban megkapjuk ezt is.

Nem beszéltünk még arról, hogy hol tárolódnak az adatok és hogyan kapcsoljuk azokat a vezérlőkhöz. Az adatok a DOCX állományon belül egy önálló XML fájlban tárolódnak, alapértelmezés szerint a customXml mappában.Itt nyers XML-t kell elképzelni, semmi Open XML specifikus elem nincs benne, az viszont praktikus, ha van egy önálló, egyedi névtere. Ha például a dokumentumunk egy levél, amelyben a címzett és a feladó adatait programozottan akarjuk kitölteni, akkor a szükséges adatokat betehetjük a customXmlitem1.xml fájlba az alábbi formában:

    <?xml version="1.0" encoding="utf-16"?>
    <Contact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                     xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                     xmlns="http://www.msdnkk.hu/samples/Contact">
        <FirstName>György</FirstName>
        <LastName>Balássy</LastName>
        <Company>MSDN Kompetencia Központ</Company>
        <City>Budapest</City>
        <Zip>1117</Zip>
        <Address>Magyar Tudósok krt. 2.</Address>
        <Sender>Feladó Ferenc</Sender>
    </Contact>

Ennek az XML fájlnak az írása és olvasása megoldható a korábban már említetett Packaging API segítségével, hiszen ez is egy Open XML document part.

Hogyan kapcsoljuk ezt a fájlt a csomag többi részéhez? A word_relsdocument.xml.rels fájlt kell kiegészítenünk az alábbiakkal:

    <?xml version="1.0" encoding="utf-8"?>
    <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
        <!-- Sok Relationship elem van itt már... -->
        <Relationship 
            Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml" 
            Target="../customXml/item1.xml" 
            Id="R0fbcbf7dffdc49b6" />
    </Relationships>

A [Content_Types].xml fájlhoz nem kell nyúlnunk, mert abban már szerepel egy definíció, amely magában foglal minden XML kiterjesztésű állományt. Kiegészíthetjük viszont egy XML properties résszel:

    <?xml version="1.0" encoding="utf-8" ?>
    <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
        <Default Extension="xml" ContentType="application/xml" />
        <!-- A dokumentum többi része itt Override elemekben -->
        <Override 
            PartName="/customXml/itemProps1.xml" 
            ContentType="application/vnd.openxmlformats-officedocument.customXmlProperties+xml" />
    </Types>

Az XML properties fájlban további tulajdonságokat adhatunk meg, például egy ún. data store ID-t:

    <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
    <ds:datastoreItem 
        ds:itemID="{70372b4c-0b6e-4f5d-9fa2-39118fe7a889}" 
        xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml" />

Ha több customXml partunk is van, akkor még egy ds:schemaRefs elem segítségével összekapcsolhatjuk a data store-t egy adott XML sémával. Ennek akkor van jelentősége, ha egyébként a dokumentumban több azonos sémájú XML part is van, mert így meg tudjuk adni, hogy pontosan melyikhez kívánunk kapcsolódni.

A tárolást tehát megoldottuk, következő probléma, hogy az egyes vezérlőket hogyan kapcsoljuk az XML fájlban lévő elemek valamelyikéhez. A megoldás a cikksorozat címében oly sokszor említett adatkötés. Nem is akármilyen, hanem kétirányú! Tehát akár kódból módosítjuk az XML állományt, akár a felhasználó ad Wordben új értéket valamelyik vezérlőnek, a másik automatikusan frissül, ezzel semmilyen további munkánk nincsen!

Az adatkötés megadása a worddocument.xml fájlban történik az egyes w:sdtPr elemekbe ágyazott w:dataBinding elemekkel. Itt két dolgot kell megadnunk:

  1. Egy névtér aliast a w:prefixMappings attribútumban.
  2. A névtér aliast használó és az XML dokumentumban egy elemet azonosító XPath kifejezést a w:xpath attribútumban.
  3. Ha több azonos névterű XML partunk is van, akkor még egy data store ID-t, ami alapján a Word megtalálja majd az XML partot. Ezt a w:storeItemID attribútumban lehet megadni.

Végül például egy Keresztnév  értéket bekérő vezérlő, amely a fent bemutatott XML dokumentum FistName mezőjéhez van kötve így festhet:

    <w:sdt>
        <w:sdtPr>
            <w:dataBinding 
                w:prefixMappings="xmlns:ns0='http://www.msdnkk.hu/samples/Contact'" 
                w:xpath="/ns0:Contact[1]/ns0:FirstName[1]" 
                w:storeItemID="{70372b4c-0b6e-4f5d-9fa2-39118fe7a889}" />
            <w:rPr>
                <w:i />
            </w:rPr>
            <w:alias w:val="Keresztnév" />
            <w:tag w:val="Keresztnev" />
            <w:id w:val="370331103" />
            <w:placeholder>
                <w:docPart w:val="DefaultPlaceholder_22675703" />
            </w:placeholder>
            <w:text />
        </w:sdtPr>
        <w:sdtContent>
            <w:r w:rsidR="00136851" w:rsidRPr="00136851">
                <w:rPr>
                    <w:i />
                </w:rPr>
                <w:t>Keresztnév</w:t>
            </w:r>
        </w:sdtContent>
    </w:sdt>

A jó hír az, hogy mindezt nem kell kézzel odaheggesztenünk minden egyes vezérlőhöz. Bár sem a Wordben, sem pedig a Visual Studioban nincs erre eszköz, szerencsére a CodePlexről letölthetjük a Word 2007 Content Control Toolkitet, ami sokat segíthet a munkában. Egyetlen képernyős alkalmazásról van szó és mivel Windows Formsban készült, kiválóan olvasható Reflectorral (megjegyzem tanulni is lehet belőle, például nagyon érdekes, hogyan vezérli ez a külső alkalmazás a Word kurzorát):

Content Control Toolkit

Az alkalmazás használata nagyon egyszerű:

  1. Készítsük el Wordben a sablon dokumentumot és tegyük bele a vezérlőket a Developer fülről.
  2. Töltsük be a Word dokumentumot a Content Control Toolkit (CCT) eszközbe, ami után bal oldalon megjelennek a vezérlők.
  3. A jobb alsó Create a new Custom XML Part linkre kattintva adjunk új XML partot a dokumentumhoz.
  4. Készítsük el azt az XML dokumentumot például Visual Studioban, amit egyszerűen elő tudunk állítani később kódból, és amilyen formátumú fájlt majd a DOCX állományba szeretnénk helyezni.
  5. Másoljuk be az XML tartalmát az Edit View fülön lévő mezőbe.
  6. Váltsunk vissza Bind View nézetre, ahol megjelenik az XML hierarchia.
  7. Jelöljük ki a bal oldali listában valamelyik vezérlőnket (ez kell), majd a jobb oldali hierarchiában fogjuk meg a hozzá illő XML elemet és dobjuk rá a vezérlőre. Ekkor elkészül az adatkötés. Ha inkább kézzel szerkesztenénk a paramétereken, akkor kattintsunk duplán bármelyik vezérlő sorára és a felbukkanó ablakban adjuk meg az adatokat.
  8. Végül ne felejtsük el menteni a dokumentumot.

Ezzel még csak az adatkötés paraméterezése készült el, illetve az eszköz megoldja azt is, hogy a DOCX állományban létrejöjjön egy XML part. Ami még hátra van, az a DOCX állományban lévő XML tartalmának módosítása kódból. De ezt majd legközelebb, addig is ezt érdemes kipróbálni!

(folytatjuk)

Advertisements

NXT.NET for Lego Mindstorms

Néhány hónappal ezelőtt Dávid Zoli blogbejegyzése kapcsán figyeltem fel a Lego Mindstorms NXT készletére. Aki esetleg nem ismerné, ez egy olyan standard LEGO csomag, amiből programozható robotot építhetünk. A robot "agya" az ún. NXT Brick képes egyszerre négy szenzor jelét venni és három motort vezérelni, sőt a legszebb az egészben, hogy Bluetooth kapcsolatos keresztül távvezérelhető. Szóval nem csak egy gyerekjátékról van szó, sokkal több lehetőséget rejt ez a készlet magában. Nem véletlen, hogy a világban több helyen már ezt használják arra, hogy a diákokkal megszerettessék a programozást és elsajátíttassák a programozás alapjait. Aki nem hiszi, nézze meg ezt a videót egy Lego robotról, amelyik kirakja a Rubik kockát!

Mivel a Bluetooth kapcsolat soros portként látszik, ezért nem ördöngösség a .NET Framework SerialPort osztályán keresztül programozni. Bár ezt már többen megírták, én mégis nekiláttam, hogy életem első robotját a saját .NET alkalmazásomon keresztül távirányítsam. A dolog meglepően gyorsan működött, bár persze számos fejlesztői doksit kellett végigbújni, melyek szerencsére publikusan elérhetőek a Lego oldalán.

Az eredmény egy osztálykönyvtár lett, mely végül az NXT.NET nevet kapta. Teljes mértékben felügyelt kódban, C# 3.0-ban íródott és végül sikerült megoldani, hogy ugyanaz a forráskód változtatás nélkül csont nélkül forduljon .NET Framework 3.5-re és .NET Compact Framework 3.5-re is, tehát egyúttal a mobil változat is elkészült. A kód teljes mértékben angolul kommentezett, ide vezettem át mindent, amit a neten talált forráskódokból és dokumentációkból sikerült kiokoskodnom, így a C# fordító által generált XML kimenetből NDoc segítségével előállt az osztálykönyvtár fejlesztői CHM súgója, melyből íme egy képernyőfotó az elérhető típusok érzékeltetésére (ez is letölthető a CodePlexről):

Kattins a képre a teljes méret megtekintéséhez

A library teszteléséhez készült egy desktop és egy mobil alkalmazás, mindkettő természetesen felügyelt kódban. Bár még nem tud mindent, az alap kommunikáció, tulajdonságok lekérdezése, szenzorok konfigurálása és lekérdezése már megy. Ez látszik belőle Visual Studio 2008-ban:

NXT.NET desktop alkalmazás

Bár a motorok vezérlése még csak alapszinten implementált, elérkezettnek láttam az időt ahhoz, hogy megosszam az eredményt azokkal, akiket érdekel. A projekt súgóját és lefordított állományait kitettem a CodePlexre, onnan lehet letölteni őket. A forráskódokat egyelőre nem osztottam meg, de ha lesz érdeklődés a projekttel kapcsolatban, akkor tervezem azt is kitenni a netre.

Érdekel ez egyáltalán valakit rajtam kívül? Használ ma idehaza valaki Lego Mindstorms NXT-t?