Szumma #071 – 2016 51. hét

Az elmúlt hét legfontosabb/hasznosabb linkjeit szedtem össze.

“Szumma #071 – 2016 51. hét” olvasásának folytatása

Reklámok

Word – mezők használata kódból

Ezúttal az eddigiektől kicsit eltérő dologról lesz szó. Annyiban kapcsolódik a korábbiakhoz, hogy ebben is lesz egy kis kódolás, amivel egy konkrét problémára találunk megoldást. 🙂

Ha valaha készítettek már körlevelet a Worddel (omg, nekünk ez komoly tananyag volt gimiben), vagy elhelyeztetek oldalszámot stb.-t egy doksiban, akkor már ismerős lehet a wordmezők vagy űrlapmezők fogalma. Nemrég egyik barátom feladatul kapta, hogy olyan programot kell készítenie, amely előre elkészített, mezőket tartalmazó word doksikat dolgoz fel, és a mezők helyére beilleszt valamit – szöveget, képet -, amit a program logikázott ki. Segítségemet kérte, így jött szembe a probléma, hogy tulajdonképpen még sosem kellett ilyen “template”-ekkel dolgoznom, általában az utolsó betűig kódból generáltam a doksikat. 🙂

Űrlapmező létrehozásaElső lépésként hozzunk létre egy word dokumentumot, és helyezzünk el benne néhány mezőt. (Így visszagondolva ez volt talán a legbonyolultabb része a feladatnak. 🙂 A Word beállításai közé kell bemászni, és valahol, egy jól eldugott helyen létrehozni egy új fület a ribbonon… Fájl, Beállítások, Menüszalag testreszabása, majd a baloldali listán az “Űrlapmező” parancsot kell megkeresni, és átrakni a jobb oldali listába.) A mezőknek lehetőleg adjunk értelmes nevet. Nálam ez “alma”, “béka” stb. lett.*

A program elkészítésének első lépése természetesen a szükséges Word Interop dll beemelése a program referenciái közé:  Microsoft.Office.Interop.Word.dll – vigyázzunk, mert általában mindjárt 2-4féle van a gépünkön. Ez után pedig az azonos nevű névtér beusingolása. (Nyelvújítunk, na…)

using Microsoft.Office.Interop.Word;

A Word elindítása és a korábban elkészített doksi megnyitása a szokásos (az elérési utat lerövidítettem, amúgy egy abszolút út):

var word = new Application();
Document doc = word.Documents.Open(@"c:\Users\...\tesztdoksi.docx");

Jön a lényeg, a mezők feltöltése. A mezőket a dokumentum FormFields listáján keresztül tudjuk elérni. A Name tulajdonságot megvizsgálva tudjuk kiválasztani a nekünk tetszőt, illetve, ha adtunk neki (alapértelmezett) értéket, azt a Result tulajdonságból kapjuk meg, és itt is tudjuk megváltoztatni:

foreach (FormField ff in doc.FormFields)
{
    if (ff.Name == "alma")
    {
        ff.Result = "ez itten kódbul van...";
    }
    //...
}

Ennek a megoldásnak egy apró hátulütője, hogy a mező bent marad a dokumentumban (szürke háttere lesz a szövegnek). Ha ténylegesen be akarjuk illeszteni a szöveget a mező helyére, akkor a legegyszerűbb, ha nem a Resultot állítjuk be, hanem kiválasztjuk az egész mezőt, és lecseréljük a szövegre. Valahogy így:

foreach (FormField ff in doc.FormFields)
{
    if (ff.Name == "alma")
    {
        ff.Select();
        word.Selection.Text = "ez itten kódbul van...";
    }
    //...
}

Ha most mentjük a doksit, látható, hogy a mezők eltűntek, és kicserélődtek magára a szövegre. Helyzetfüggő, hogy melyik megoldást mikor érdemes alkalmazni…

Izgalmasabb a dolog, ha egy adatforráshoz kapcsolt dokumentum adatmezőit akarjuk ilyen módon feltölteni. Jellemzően ez a helyzet körlevelek esetén. Ezek a mezők nem a FormFields listába kerülnek, hanem a Fields listába. Ha név alapján akarjuk kiválasztani őket, akkor pedig számítanunk kell arra, hogy a nevüket is kiegészíti a Word: a nevet a Field objektum Code tulajdonságának Text tulajdonságában találjuk, de  a Word hozzáfűzi a saját okosságát is, így az “alma” néven létrehozott mező neve ” MERGEFIELD \”alma\” ” lesz. Az egyszerűség kedvéért most nem vagdalkozunk, csak azt vizsgáljuk, hogy a mező neve tartalmazza-e a keresett szót. A többi már egyezik:

foreach (Field f in doc.Fields)
{
    if (f.Code.Text.Contains("alma"))
    {
        f.Select();
        word.Selection.Text = "ez itten kódbul van...";
    }
    //...
}

Gondolom, mondanom sem kell, hogy a Contains metódus használhatósága drámaian csökken, ha mondjuk van egy alma és egy almabéka nevű mezőnk is, ahogy az nálam gyakran előfordul. 🙂

Ezután menthetjük a dokumentumot, bezárhatjuk a wordöt stb, a lényeg, hogy a mezők segítségével sikerült összeraknunk egy olyan template-et, amelynek kimaradt részeit utána kódból egyszerűen feltölthettük.

*: Ha nagyon nem akarunk kattintgatni, akkor létrehozhatjuk a mezőket Word Interoppal is. A fentebb bemutatott FormFields tulajdonság Add metódusát felhasználva beszúrhatunk ilyeneket kódból is.

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

Najó, most már kötelezőnek érzem… Szóval: és most vissza kódolni. 🙂

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

ObjectDumper – fordítsuk ki Caerbannog gyilkos nyulát!

Akkor így a nyúl-, tojás- és sonkaünnep (szigorúan nem nyúltojás- és nyúlsonka!) vasárnapján megosztok egy pici, hasznosnak gondolt kis osztályt.

Az ObjectDumpernek elkeresztelt kis valami arra lesz képes, hogy egy objektum belső állapotát – azt is, ami tényleg belső, privát – egy kellő mértékben formázott stringként adja a külvilág tudtára. Elsősorban hibakeresésre szánjuk az osztályt: nem kell a locals ablakban turkálni, csak hívni egy Dump()-ot egy objektumon, és kész is. A munka során megismerkedünk néhány reflectionnel kapcsolatos dologgal.

Kezdjük szokás szerint egy testreszabott osztállyal, ami az állatorvosi ló szerepét tölti majd be. A jeles alkalomra való tekintettel a ló most legyen nyúl.

A nyúl

Mindössze egy pici osztályra lesz szükség, ami itt-ott “furán néz ki”. Hogy megfelelően tesztelhető legyen az ObjectDumper, olyan osztályra lesz szükség, ami pl. rendelkezik olyan tulajdonsággal, ami csak lekérdezhető, vagy épp csak beállítható. Rakjuk össze a nyulat!

public class Rabbit
{
    public string Name { get; private set; }
    public DateTime BirthDate { get; set; }
    private int killedKnights;
    public int KilledKnights
    {
        set { killedKnights = value; }
    }
    private string favColor;
    private string FavouriteColor
    {
        get { return favColor; }
    }
    public Rabbit(string name, DateTime bDate
        int killedKnights, string favColor)
    {
        this.Name = name;
        this.BirthDate = bDate;
        this.killedKnights = killedKnights;
        this.favColor = favColor;
    }
}

Látható, hogy a nyuszinak lesz egy neve, egy születési dátuma, illetve beállítható lesz rajta, hogy eddig hány lovagot ölt meg. Viszont ez kívülről nem kérdezhető le, így egy lovag, amikor először meglátja, nem fogja tudni, mivel áll szemben. Ezen felül pedig lesz egy kedvenc színe is a nyúlnak, azonban ez nem fontos, hacsak nem akar hidakon átkelni.

A nyúlon túl

Mielőtt még nekilátnánk az ObjectDumpernek, szükségünk lesz néhány enumerációra, amivel majd szabályozhatjuk a működést. Elsőként: mezőket vagy tulajdonságokat jelenítsünk meg? Aztán: publikus vagy nem publikus tagokkal dolgozzunk? Végül: milyen plusz információt jelenítsünk meg? (Például a tag típusa, illetve az, hogy egy tulajdonság milyen accessorökkel rendelkezik.)

[Flags]
public enum DumpTarget : byte
{
    Fields = 0x01,
    Properties = 0x02
}
[Flags]
public enum DumpVisibility : byte
{
    Private = 0x01,
    Public = 0x02
}
[Flags]
public enum DumpAdditionalInfo : byte
{
    None = 0x00,
    Type = 0x01,
    PropAccessors = 0x02
}

Egy kis magyarázat: A FlagsAttribute jelzi, hogy itt egy bitflagről van szó, vagyis össze akarjuk majd kapcsolni az egyes értékeit az adott enumerációnak. (Tehát pl egyszerre akarunk publikus és privát tagokat megjeleníteni.) Ez most még annyira nem lényeges, de ha később szeretnénk kiterjeszteni az enumerációt plusz tagokkal, jól jöhet.

A byte, mint “ősosztály” itt azt jelenti, hogy az enumeráció mögötti tároló egy byte legyen. Max. 256 értéket vehet tehát fel az enum, cserébe negyedannyi helyen elfér, mint az alapértelmezett integer.

Az enumok tagjai után lévő hexaszámok csak a címke mögötti konkrét értéket jelzik.

Mehetünk tovább – kezdjük el fejleszteni a lényeget. 🙂

Minden objektum hozzon magával még egy metódust!

Alapvetően nem a legjobb dolog, ha a System.Objectre rakunk bővítőfüggvényt (hogy miért, arról majd később), de megtehetjük, és nekünk most logikailag ez a legmegfelelőbb. A bővítőfüggvények (extension methods) a C# 3.0-ban jelentek meg. Segítségükkel bármilyen osztályra felrakhatunk  plusz metódusokat – látszólag. Valójában az ilyen módon az osztályra rakott metódus továbbra sem lesz ténylegesen az osztály része; pusztán a C# engedi nekünk, hogy szintaktikailag egy példányon meghívjuk, de a háttérben a hívás nem a példányon történik, hanem a bővítőfüggvényt tartalmazó osztályon.

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

Elég a szóból, hozzuk létre az osztályt, benne a függvénnyel. Rögtön adjuk meg a paramétereket is: az első nyilvánvalóan az objektum, aminek a tartalmát dumpolni akarjuk, utána következzen egy TextWriter, ami a kimenetet tárolja majd, majd jöhet a 3 fentebb készített enumeráció argumentumként való fogadása. A paraméterlista összeállításakor izomból felhasználjuk a C# 4.0 opcionális/nevesített paraméterezési képességeit, vagyis ahol lehet, rögtön default értéket adunk a paramétereknek.

public static class ObjectDumper
{
    public static void Dump(this object o,
        TextWriter output = null,
        DumpTarget targets = DumpTarget.Fields | DumpTarget.Properties,
        DumpVisibility visibility = DumpVisibility.Public,
        DumpAdditionalInfo additionalInfo = DumpAdditionalInfo.None)
        {
        }
}
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

Tekintve, hogy bővítőfüggvényről van szó, egy public static osztályban public static módosítókkal kell létrehozni a metódust. A kódot picit később írjuk meg.

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

Hogy a formázást szeretnénk egyszerűen megoldani, érdemes lesz ezt is az osztály szintjén definiálni, így egy központi helyen lesz állítható. Csupán néhány stringet kell létrehozni:

public static string FieldsHeader = "---Fields";
public static string PropertiesHeader = "---Properties";
public static string PublicHeader = "\t---public";
public static string PrivateHeader = "\t---nonpublic";
public static string IndentChars = "\t";
public static string EqualitySign = " = ";

Most, hogy megvagyunk a körítéssel, írjuk meg a Dump metódus logikáját!

Először is ellenőrizzük, hogy nem null-referencián hívták-e a metódust. Ha igen, a metódus dobjon egy ArgumentNullExceptiont. Mindenki döntse el maga, hogy ez a legmegfelelőbb kivétel-e ebben a szituációban. Mivel bővítőfüggvényről van szó, amelynek első paramétere okozta a hibát, hajlok arra, hogy inkább ezt javasoljam, mint egy NullReferenceExceptiont.

Ha nem nullt kaptunk, kérdezzük le a kapott objektum típusát. A típusinformációk segítségével fogjuk felderíteni az objektum belsejét.

Ezután jöhet a StringBuilder létrehozása. Mivel nem akarjuk, hogy fél mega szemét maradjon a memóriában a metódus lefutása után, jobb lesz, ha nem stringeket konkatenálunk, hanem egy StringBuilderrel rakjuk össze a kimenetet. Ebbe az objektumba rögtön írjuk is be, hogy milyen típusú objektumot “dumpolunk” éppen.

if (o == null) throw new ArgumentNullException(
    "o", "Dump cannot be called on a null reference.");
Type t = o.GetType();
StringBuilder sb = new StringBuilder("Dumping ");
sb.AppendLine(t.Name);

Ezek után jöhet a mezők és a tulajdonságok felsorolása attól függően, hogy a hívó mit kért. Ezt ugye a targets paraméter alapján tudjuk eldönteni.

Tekintve, hogy lehetséges, hogy több értéket is megjelölt a hívó, nem tudunk egyszerű értékösszehasonlítást végezni, helyette a HasFlag metódust kell meghívni. Ugyanezt kell elvégeznünk a visibility paraméter vizsgálatakor is.

Ha megvolt a vizsgálat, indulhat a foreachelés egy megfelelően lekérdezett FieldInfo tömbön. A megfelelően lekérdezett itt azt jelenti, hogy a típusobjektumon meghívott GetFields metódusnak a BindingFlags enumeráción keresztül megmondjuk, hogy pontosan milyen láthatóságú tagokat kérünk. A munka oroszlánrészét, vagyis a kiíratást egy privát metódus oldja majd meg, melyet a következő lépésben definiálunk.

Mivel a tulajdonságok lekérdezésének ugyanez a logikája, csupán az információs osztályok típusa, illetve a belső logika változik, erre nem térek ki külön.

if (targets.HasFlag(DumpTarget.Fields))
{
    sb.AppendLine(FieldsHeader);
    if (visibility.HasFlag(DumpVisibility.Private))
    {
        sb.AppendLine(PrivateHeader);
        foreach (FieldInfo fi in t.GetFields(
            BindingFlags.NonPublic | BindingFlags.Instance))
        {
            getFieldString(sb, o, fi, additionalInfo);
        }
    }
    if (visibility.HasFlag(DumpVisibility.Public))
    {
        sb.AppendLine(PublicHeader);
        foreach (FieldInfo fi in t.GetFields(
            BindingFlags.Public | BindingFlags.Instance))
        {
            getFieldString(sb, o, fi, additionalInfo);
        }
    }
}

Kész is. A fenti elágazást – a megfelelő helyeken józan paraszti ész alapján módosítva – lemásoljuk, és ezzel lekérdezzük a tulajdonságokat is.

Már csak annyi van hátra a sok útelágazódás után, hogy a metódus végére telepakolt StringBuilder tartalmát a kapott TextWriter objektumba pakoljuk. Tekintve, hogy az output default értéke null, ezt le kell ellenőriznünk, mert valószínű, hogy lesz, aki így használja. Ha nullt kaptunk, kimenetnek megadjuk a konzolt. Ezek után pedig kiírjuk az sb változó tartalmát.

if (output == null) output = Console.Out;
output.WriteLine(sb.ToString());

A tartalom lekérdezése

A következő lépés a getFieldString metódus, illetve párja, a getPropertyString metódus megírása lesz. (A név egy kicsit megtévesztő lehet: nem stringgel térnek vissza, hanem az eredeti StringBuildert töltik fel további adatokkal.)

private static void getFieldString(StringBuilder output,
    object dumpedObj, FieldInfo fInfo, DumpAdditionalInfo adtnl)
{
    output.Append(IndentChars);
    if (adtnl.HasFlag(DumpAdditionalInfo.Type))
        output.AppendFormat("[{0}]\t", fInfo.FieldType);
    output.AppendFormat("{0}{1}{2}{3}", fInfo.Name, EqualitySign,
        fInfo.GetValue(dumpedObj) ?? "{null}", Environment.NewLine);
}

Mit csinálunk itt?

Először is behúzzuk a sört. Csak, hogy jobb legyen a kedv. (Ja, húsvét van?) Aztán a sort, hogy olvashatóbb legyen a kimenet.

Ezután, ha a a hívó kérte, a FieldInfo FieldType tulajdonságának segítségével kiírjuk a mező típusát. Ez opcionális.

Utolsó körben pedig jöhet lényeg: szépen formázva kiírjuk a mező nevét, majd tartalmát, majd törjük a sort. Közben annyira kell még ügyelnünk, hogy ha esetleg a mező tartalma null lenne, írjunk ki helyette egy normál stringet. (null coalescing op ftw!)

Nagyon hasonló, amit a tulajdonságokkal el kell játszani, de van néhány lényeges különbség.

A tulajdonságok meglehetősen összetettek. Gyakorlatilag 1 vagy 2 metódusunk van – elképzelhető olyan szituáció is, amikor csak set van, vagyis a tulajdonság kívülről nem kérdezhető le, csak beállítható. Ráadásul ezek a metódusok nem feltétlenül publikusak; saját láthatóságuk van. Ezen felül akár még kivételt is dobhatnak…

Lássuk, mit tehetünk!

private static void getPropertyString(StringBuilder output,
    object dumpedObj, PropertyInfo pInfo, DumpAdditionalInfo adtnl)
{
    output.Append(IndentChars);
    if (adtnl.HasFlag(DumpAdditionalInfo.Type))
        output.AppendFormat("[{0}]\t", pInfo.PropertyType);
    output.AppendFormat("{0}{1}{2}", pInfo.Name, EqualitySign,
        pInfo.GetGetMethod() != null ? pInfo.GetValue(dumpedObj, null)
        ?? "{null}" : "{no public get accessor");
    if (adtnl.HasFlag(DumpAdditionalInfo.PropAccessors))
    {
        output.AppendFormat(" [{0}{1}]",
            pInfo.GetGetMethod(true) != null ? "get;" : string.Empty,
            pInfo.GetSetMethod(true) != null ? "set;" : string.Empty);
    }
    output.AppendLine();
}

Csak egy kicsit bonyolultabb, na. 🙂 Az elejére ne vesztegessünk szót, nem sok változás van a korábbiakhoz képest.

Az érték kiírásánál már figyelnünk kell arra, hogy egyáltalán lekérdezhetjük-e az értéket. Ha nincs get accessor, meg sem próbáljuk.

Ezek után, ha a hívó kérte, kiírjuk, hogy milyen accessorökkel rendelkezik a tulajdonság. A PropertyInfo GetGetMethod és GetSetMethod metódusának lekérdezése éppen megfelelő lesz erre.

Készen vagyunk, teszteljük le, mit alkottunk!

“Egy nyúlpörkölt rendel.”

Készítsünk egy nyulat, és hívjuk meg rajta a metódust!

Rabbit bugs = new Rabbit("Killer Rabbit of Caerbannog",
    new DateTime(1975, 4, 3), 90, null);
bugs.Dump(visibility: DumpVisibility.Private | DumpVisibility.Public,
additionalInfo: DumpAdditionalInfo.Type |
DumpAdditionalInfo.PropAccessors);

Futtassuk meg, és nézzük meg, mit rejtett a nyúl belseje!

Dumping Rabbit
---Fields
        ---nonpublic
        [System.Int32]  killedKnights = 90
        [System.String] favColor = {null}
        [System.String] k__BackingField = Killer Rabbit of Caerbannog
        [System.DateTime]       k__BackingField = 1975.04.03. 0:00:00
        ---public
---Properties
        ---nonpublic
        [System.String] FavouriteColor = {no public get accessor} [get;]
        ---public
        [System.String] Name = Killer Rabbit of Caerbannog [get;set;]
        [System.DateTime]       BirthDate = 1975.04.03. 0:00:00 [get;set;]
        [System.Int32]  KilledKnights = {no public get accessor} [set;]

Egész jó. Vajon hol vannak az easter eggek (=bugok)? 🙂 (Aki talál, kap csokitojást. Viccen kívül.)

Update: elfelejtettem letölthetővé tenni a kész kódot. Íme. 🙂

http://cid-0b0abf2a681faf43.office.live.com/embedicon.aspx/.Public/chevenix.wordpress.com/ObjectDumper.zip

További lehetőségek

Az osztály korántsem 100%-os, de arra bőven jó, hogy elinduljunk. Én olyan 85%-osnak mondanám, tekintve, hogy a formázás testreszabása sokkal bonyolultabb is lehetne. 🙂

Mit lehetne még beépíteni? Például a statikus tagokat abszolúte kihagytuk – elvileg ez nem gond, mivel mi egy konkrét példányt dumpolunk, de ha érdekel valakit, esetleg ezt is bele lehet rakni. Aztán a tulajdonságoknál lehetne még bonyolítani a dolgot jócskán. Valamint például beépíthetnénk elvárt/kizárt értékek megadását. Vagy a tagok attribútumait is beolvashatnánk. Jelezhetnénk, hogy az adott tulajdonságot ezen a típuson definiálták, vagy örökölte.

A végtelenségig lehetne tuningolni ezt a metódust és osztályt. Viszont még van pár másik program, amire rá kell néznem, és amelyekért talán pénz is jön, úgyhogy tartva magam ahhoz, ami lassan itt mottóvá válik…

…most vissza kódolni. 🙂

Fókusz áthelyezése egy WPF DataGridben

Nem rég szembejött a probléma, hogy egy sokablakos, bonyolult WPF-app működése során néha kézzel – vagyis kóddal – kellene a fókuszt egy DataGrid egy sorára helyezni. A DataGrid.Focus() és a SelectedIndex beállításának kombója nem járható út, ilyenkor maga a Grid kapja meg a fókuszt, nem lehet rögtön lépkedni benne a le/fel nyilakkal.

Mit tehet ilyenkor az ember? Kiválasztja az adott sort a Rows tulajdonságból, és meghívja azon a Focust. Igen ám, de nem. Nincs Row/Rows tulajdonság, amiből kiválaszthatnánk a sorokat, illetve nincs GetRow metódus. Itt kezdené visszasírni az ember a DataGridViewt. 🙂

(Amúgy nem. Épp valamelyik nap kellett vele dolgoznom, és így 2-3 év WPF-ezés után már érzi az ember, hogy a DataGrid barátibb. Bár ez ízlés dolga.)

Akkor mit lehet tenni?

Nos, a DataGridnek, mint minden ItemsControlnak van egy Items tulajdonsága. Ezen keresztül elérhetjük az elemeket, amelyeket meg kell jelenítenie a gridnek. A probéma csak az, hogy ezek tényleg a megjelenítendő elemek. Az adatok a grid mögött, nem pedig a vizuális fában megjelenő sorok/cellák. Magyarán ez egy objectekből álló lista, tehát esélyünk sincs Focust hívni rajtuk, és kasztolni is max. az adattípusra tudjuk, amivel megint nem vagyunk beljebb.

Nem húzom tovább a dolgot (nem lenne mókás, ha végigvinnélek titeket azon a fél órás hajhulláson, amíg eljutottam a megoldásig 🙂 ), inkább prezentálom a végeredményt.

public static class DataGridExtender
{
    public static bool SetFocusOnDataGridRow(this DataGrid dg,
        int rownum = 0, bool setSelectedIndex = true)
    {
        if (rownum >= 0 && rownum < dg.Items.Count)
        {
            DataGridRow dgrow = (DataGridRow)dg.ItemContainerGenerator
                .ContainerFromItem(dg.Items[rownum]);
            if (setSelectedIndex) dg.SelectedIndex = rownum;
            return dgrow.Focus();
        }
        return false;
    }
}

Na, nézzük, mit látunk…

Ahogy látható, a C# 3.0 extension method (bővítőfüggvény) rendszerét használjuk, hogy a DataGrid osztálynak adjunk egy plusz metódust. A rownum paraméterrel várjuk, hogy mely sort akarják kiválasztani, a setSelectedIndex pedig azért “kell”, mert a fókuszáthelyezés és a grid kiválasztott elemének beállítása két külön dolog – ez a metódus képes lesz külön kezelni ezeket. A paraméterlistában kihasználom a C# 4.0-ás optional/named parameter fejlesztését, így a metódus gyakorlatilag paraméterek átadása nélkül is hívható lesz.

Ezek után jön a varázslat. A DataGrid ItemContainerGeneratorjának pontosan az a feladata, hogy egy adott adatelemhez (amit a fentebb ismertetett módon ki tudunk szedni a gridből) adjon nekünk egy olyan objektumot, ami a vizuális fában reprezentálja majd ezt az elemet. Vagyis eme objektum segítségével tudjuk áthidalni a szakadékot a megjelenítendő adat és a konkrét vizuális reprezentáció között.

A következő sor gondolom, világos: ha a programozó kérte, a selectedindexet is beállítjuk a sorra.

Ezután jön az, hogy akkor ki is jelöljük a sort, vagyis rárakjuk a fókuszt. Látható, hogy ez sem nehéz.

Ha kipróbáljátok, látni fogjátok, hogy azért nem tökéletes a leányzó fekvése. A sort kijelöli, a fókuszt is rárakja, de nem lehet rögtön mozogni a nyilakkal, mert a DataGridben cellánként megy az ugrálás – és most még nincs kijelölt cella.

A WPF-nek van egy nagyon szép bonyolult fókuszkezelő alrendszere, ami hajlamos igen randomisztikusan működni, de itt speciel pont jó lesz nekünk. Ha lecseréljük a “fókuszátrakó” sort a következőre, máris kijelöli az első cellánkat a fókusz rárakásánál:


return dgrow.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));

Ennyi. Máris azonnal lépkedhető a gridünk. Remélem, sikerül megspórolnom némi kollektív hajhullást. 🙂

A WorkItemek nem oldják meg magukat, úgyhogy most (megintcsak) vissza kódolni.

ui.: bocs a kódszöveg mérete miatt, még harcolok a wordpress-szel, hogy ne legyen satu.

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English

AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDetect languageDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddishAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBulgarianCatalanChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekHaitian CreoleHebrewHindiHungarianIcelandicIndonesianIrishItalianJapaneseKoreanLatinLatvianLithuanianMacedonianMalayMalteseNorwegianPersianPolishPortugueseRomanianRussianSerbianSlovakSlovenianSpanishSwahiliSwedishThaiTurkishUkrainianUrduVietnameseWelshYiddish

English (auto-detected) » English