Jarda Jirava

Vývojář a architekt řešení postavených na technologii .net framework. Zabývám se jak vývojem webových aplikací za pomoci asp.net, tak také desktopových aplikací winform. Při návrhu řešení a samotném vývoji pak využívám dlouholetých zkušeností se zpracováním obchodní logiky a pravidel aplikací získaných z vývoje komerčních aplikací pro finanční a bankovní instituce.

Microsoft MVP

Microsoft MVP - Client App dev

Silverlight minesweeper

Get Microsoft Silverlight

Navrhi COOL design a vyhraj zkušební let po Evropě!

Poslední příspěvky

22
I

MaximumWidth pro DataGridViewColumn

Otázky a odpovědi. Při hledání vhodného řešení si občas člověk užije a prověří svoje schopnosti. Ne vždy je odpovědí optimální řešení, ale jak nás učili na škole, lepší vybírat mezi suboptimálním řešením, než žádným. A právě jedna taková otázka se objevila na builderu, týkala se maximální šířky sloupečku v DataGridView. Jelikož jsem se při odpovědi maličko více rozepsal, rozhodl jsem se odpověď uveřejnit jako příspěvek.

Možné řešení maximální šířky sloupce je celkem prosté a vycházím z toho, že DataGridView publikuje několik událostí při změně šířky sloupečku. Zároveň je však důležité přidat do definice sloupce informaci, zda má sloupec povolenu max. šířku a případně její hodnotu.

SizingDataGridViewTextBoxColumn

Nejdříve jsem si tedy vytvořil potomka po DataGridViewTextBoxColumn a přidal jsem mu vlastnost MaximumWidth, která uchovává hodnotu o maximální šířce sloupečku. Dále bylo nutné přepsat metodu GetPreferredWidth, tak aby tato vracela požadovanou šířku v daných případech.

SizingDataGridView

Dále jsem podědil třídu DataGridView, kde bylo nutné přepsat dvě metody, ke kterým dochází v průběhu změny šířky sloupce. Jedná se o metody OnColumnDividerDoubleClick a OnColumnWidthChanged.

Proto, abych si ulehčil maličko práci a výsledný kód splňoval alespoň nějaké podmínky pro rozšíření jsem dodefinoval ještě interface, který implementují všechny sloupečky, které mají mít nastavenu maximální šířku. Nazval jsem jej ISizingDataGridViewColumn. Na toto rozhraní se odvolávám právě u obou přepsaných metod.

Zdrojové kódy

Ještě zbývá uvést zdrojové kódy jednotlivých, zde zmíněných tříd a interface. Jelikož se jedná o poměrně malé části kódu, uvádím je v plném znění bez komentářů.

ISizingDataGridViewColumn:
public interface ISizingDataGridViewColumn
{
  int MaximumWidth { get; set; }
}
SizingDataGridViewTextBoxColumn:
public class SizingDataGridViewTextBoxColumn : DataGridViewTextBoxColumn, ISizingDataGridViewColumn
{
  private int _maximumWidth;
             
  public int MaximumWidth
  {
    get { return _maximumWidth; }
    set
    {
      if (_maximumWidth != value)
      {
        _maximumWidth = value;
      }
    }
  }

  public override int GetPreferredWidth(DataGridViewAutoSizeColumnMode autoSizeColumnMode, bool fixedHeight)
  {
    int width = base.GetPreferredWidth(autoSizeColumnMode, fixedHeight);
    int currWidth = this.Width;
    if (MaximumWidth < width)
    {
      width = MaximumWidth;
    }
    if (currWidth > width)
    {
      return width;
    }
    return currWidth;
  }
}

SizingDataGridView

public class SizingDataGridView : DataGridView
{
  protected override void OnColumnDividerDoubleClick(DataGridViewColumnDividerDoubleClickEventArgs e)
  {
    if (this.Columns[e.ColumnIndex] is ISizingDataGridViewColumn)
    {
      this.Columns[e.ColumnIndex].Width = ((ISizingDataGridViewColumn)this.Columns[e.ColumnIndex]).MaximumWidth;
    }
    base.OnColumnDividerDoubleClick(e);
  }

  protected override void OnColumnWidthChanged(DataGridViewColumnEventArgs e)
  {
    base.OnColumnWidthChanged(e);
    if (e.Column is ISizingDataGridViewColumn)
    {
      this.AutoResizeColumns();
    }
  }
}
A to je vše. Jak jsem se již zmínil na začátku, určitě se nemusí jednat o řešení optimální, spíše se jedná o nástin možného řešení, které je třeba rozvést a otestovat pro všechny stavy, které mohou u DataGridView nastat.
Publikováno pod: .net technology , builder.cz
4
I

Jak na DesignMode a designer

Ač to může být pro zkušené vývojáře obehraná písnička, ještě stále se najde spousta nováčků, nebo i pokročilejších vývojářů, kteří mají problém s určením, kdy se jejich komponenta, nebo formulář nachází ve vývojovém prostředí designeru.

Malé odbočení na začátek

Dřív než začnu popisovat způsob, jak identifikovat, že se formulář nebo obecnějí komponenta nachází ve vývojovém prostředí v režimu designeru, dovolím si malou odbočku, jak a proč tento příspěvek vlastně vznikl.

Takovouto otázkou se zabýval jeden z přispěvatelů na .net fóru builder.cz - jak jistě víte, mém oblíbeném. V mé odpovědi jsem jej nasměroval na možné řešení. To se však nezdálo býti dostačující a tak se na mě obrátil i soukromě, zda bych mu neposkytl potřebný kód. Nebyl prvním, kdo takto učinil a nejednalo se ani o ojedinělý případ.

Co jsem si však v tu chvíli uvědomil, že za tyto poměrně kvalitní konzultace, bych mohl být odměněn. ;-) Když jsem mu toto navrhl, již nereagoval. Je to myslím škoda, a určitě se nebudu podobným konzultacím bránit, pokud budete mít konkrétní problém.

Jelikož k rozumné dohodě nedošlo a přispěvatel nejspíše problém vyřešil vlastními prostředky, zkusím se podělit o řešení aspoň touto cestou. Můžete to vzít, třeba jako referenci.

Zpátky k DesignMode

Jak jsem již v odpovědi na otázku uvedl, existuje několik možností zjištění, že je komponenta otevřena v designeru Visual Studia.

Testování DesignMode

První možností je testovat vlastnost DesignMode dané komponenty. To je funkční řešení do doby, než umístíme komponentu do nadřazeného kontejneru a pokusíme se tuto vlastnost otestovat. Vrátí nám hodnotu false. Což je nahlášeno jako bug. Samozřejmě jemožné projít všechny nadřezené komponenty a nakonec se správné hodnoty dobrat.

Testování Site

Další možností je také otestovat vlastnost Site, která vrací rozhraní ISite jenž je naplněna právě designerem (zjednodušeně řečeno).

Testování přítomnosti EntryAssembly

Třetí možností v řadě a nikoliv poslední je otestování toho, zda existuje vstupní Assembly. Vychází se z předpokladu, že designer spouští kód pro formulář nebo komponentu "po svém" a tak nedochází k nahrání vstupní assembly.

Zjištění přítomnosti služby IDesignerHost

Určitě ne poslední možností je zjištění přítomnosti konkrétní implementace rozhraní IDesignerHost, jenž zajišťuje služby designeru.

Pro lepší představivost uvedu kód, který určitě vydá za tisíce slov. Kód uvnitř podmínky se provede pouze v případě, že jsme v designeru:

if (Site != null) {
    System.Diagnostics.Debug.WriteLine("site");
}
if (Assembly.GetEntryAssembly() == null) {
    System.Diagnostics.Debug.WriteLine("entry assembly");
}
if (GetService(typeof(IDesignerHost)) != null) {
    System.Diagnostics.Debug.WriteLine("designer host service");
}
Snad to některým pomůže.
Publikováno pod: .net technology , builder.cz
1
I

Přidání obsahu do buňky v DataGridView

Uběhlo již mnoho času od chvíle, kdy jsem se naposledy věnoval některému z příspěvků na fóru o .net na serveru builder.cz. Nyní se však na tomto fóru objevilo několik začátečníků, kteří se nespokojí jen s ukázáním cesty, ale rádi by viděli i kus kódu, který jim vydláždí cestu k vytouženému cíly.

Jeden z požadavků uveřejníl i přispěvatel lopy123, který by rád věděl, jak je možné přidat obsah do buňky v DataGridView. Celou otázku a diskuzi je možné sledovat ve zmíněném vlákně. Já jsem otázku dlouhou dobu registroval, ale blíže jsem se jí nevěnoval a to hned z několika důvodů.

Jedním z oněch důvodů byl již požadavek samotný, kdy mi přišlo chování poněkud netypické a nestandardní. V případě, kdy požaduji vložit, resp. přidat text k již existujícímu textu, nejdříve vstoupím do buňky a až následně si vyberu místo, kam text vložím.

Přejdu však k řešení, ke kterému jsem se nakonec odhodlal. Možná proto, že odpovědi, které jsem si postupně četl se přesunuly až k použití win API funkcí a to bylo v takovém případě celkem zbytečné.

Jednoduchý kód řešící problém

Výsledný kód řešící daný problém je vcelku jednoduchý. Je třeba se jen maličko zamyslet nad tím, co se vlastně v datagridview "děje", když uživatel chce editovat text uvnitř buňky.

Nejdříve si tedy registrujeme odběr události, ke které dochází při zobrazení editovacího prvku, konkrétně tedy EditingControlShowing. To můžeme udělat v okně Properties daného DataGridView, kdy se nám vygeneruje do obslužného kódu aplikace šablona metody. Do této šablony pak doplníme obsluhu události.

private void gridLopy_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
    TextBox txt = e.Control as TextBox;
    if (txt != null) {
        txt.KeyPress -= txt_KeyPress;
        txt.KeyPress += txt_KeyPress;
    }
}

Jediné, co v obsluze provádím je, že zjišťuji, zda editovacím prvkem je TextBox - pro ostatní prvky to nemá příliš význam (samozřejmě, pokud nebudeme implementovat nějaký vlastní textový editor). Poté, nejen pro jistotu, odregistrujeme událost stisku klávesy KeyPress a následně si zaregistrujeme její odběr.

Proč dochází nejdříve k odregistrování odběru události? Odpověď je opět velice jednoduchá. DataGridView používá vždy pouze jednu instanci editovacího prvku pro daný typ. Tudíž, pokud by nedošlo nejdříve k odregistraci události, tyto by se postupně vršili a docházelo by k jejich několikanásobnému vyvolávání, což je v tomto případě nežádoucí.

Poté je již dostačující vhodně ošetřit přidání znaku na potřebné místo. Samozřejmě by bylo možné implementovat lepší algoritmus, ale pro "nástřel" možného řešení jsem zvolil přidání znaků nebo číslic na konec textu.

void txt_KeyPress(object sender, KeyPressEventArgs e) {
    TextBox txt = sender as TextBox;
    if (txt != null) {
        if (char.IsLetterOrDigit(e.KeyChar)) {
            txt.Text = txt.Text + e.KeyChar;
            txt.SelectionStart = txt.Text.Length ;
            e.Handled = true;
        }
    }
}

Jak je vidět, výsledný kód není skutečně složitý. Co je však důležité, pochopit princip práce DataGridView. Snad to přispěvateli lopy123 a nejen jemu pomůže.

Publikováno pod: .net technology , builder.cz
4
XI

II. neformální setkání .net builder.cz

Ve čtvrtek se konalo již druhé neformální setkání přispěvatelů konference .net na serveru builder.cz, které se mi podařilo uspořádat. Oproti prvotnímu setkání jsme se tentokrát setkali v celkovém počtu 9 vývojářů a to na známém místě v prostředí restaurace Studna.

Probírala se nejrůznější témata, která mohou vývojáře při jeho profesní činnosti potkat. Co si dobře pamatuji, tak jedno z provotních témat byl vesmírný výtah, jeho konstrukce, možnosti a realizovatelnost.

Poté, co jsme se sešli ve větším počtu - ne každý byl dochvilný - proběhlo krátké představení každého účastníka setkání. Tím jsme se dostali k porovnání toho, jaký je rozdíl mezi kodérem a vývojářem.

Dále už následovalo jedno téma za druhým, většinou pak na některé z .net témat, asi nejvíce aktivní byl pak Jakub Müller.

Konec celého setkání se rychle přiblížil avšak ještě dříve než skončil, stačil dorazit i Jirka Zídek.

Jak a kdy příště

Příští setkání bych rád uskutečnil ještě v malinko větším počtu účastníků a také nejspíše v jiné restauraci, tak aby bylo možné si posedat dle zájmu každého účastníka a pohovořit si s každým. Alespoň dle ohlasů některých účastníků, by se další mohlo konat již brzy a to někdy na přelomu ledna a února příštího roku.

Na samotný závěr mi dovolte se ještě jednou omluvit, neboť jsem byl malinko zdravotně indisponován a tolik jsem se nezapojil do všech debat. Zrada byla v nové klimatizaci a hlavně pak mém hlase.

Publikováno pod: .net technology
3
X

Vývojáři, řekněte WoW!

Na tuhle chvíli určitě čekal kdekterý vývojář. Každý z nás si pomáhal jak mohl, a nejčastějším pomocníkem v našich otázkách a hledání odpovědí při řešení našich úkolů, pak byl reflector for .net.

Ten však již bzry nebude třeba, alespoň ne tedy pro assembly z .net frameworku 3.5. Scott Guthrie dnes na svém blogu přinesl velice potěšující zprávu. 

Zdrojové kódy pro .net framework 3.5 budou k dispozici a to již velice brzy. Navíc bude možné ladit skrz zdrojový kód těchto assemblies a to z prostředí nového VS 2008. Tak teď si konečně můžeme i my vývojáři říci WoW!

Publikováno pod: .net technology
13
VIII

ASP.NET Page pro začátečníky

Poměrně často přicházím do kontaktu se začátečníky, kteří se chtějí naučit pracovat s technologií .net. Jejich volba pak většinou míří na web a tedy použítí a tvorbu asp.net stránek.

Před takovými začátečníky však stojí poměrně velký znalostní kopec, který musí překonat, než pochopí, jak takovou stránku správně ovládat. Jelikož má asp.net stránka - třída Page - poměrně bohatý událostní model, není vždy úplně jasné a na první pohled zřejmé, co v kterou chvíli dělat a kam vlastně soustředit veškeré své úsilí.

Přestože jsem byl v prvních rocích též nadšen, obdobně jako třeba Michal Valášek - vzpomínám ještě na jeho první prezentaci o asp.net - s příchodem asp.net 2.0 toto mé nadšení malinko opadlo a já se začal dívat i na jiné možnosti. (To, jakou možnost jsem nakonec zvolil, nechám ještě chvilku v utajení, abyste si mohli zasoutěžit.)

A třeba i tento týden, kdy jsem napsal článek o tom, kdy získat a navázat data na zobrazovací prvky, mě jen utvrdil v tom, že pro začátečníky by to chtělo něco trošku jednoduššího.

ASP.NET beginner page

A tak mě napadlo, jak by tak mohla vypadat, alespoň co se týká událostního modelu taková beginner page, stránka určená pro začátečníky, nebo i pro ty, kteří nepotřebují využít všech nabízených událostí - a že se to zas tak často děje.

Co by taková třída měla umožnit. Stále je založena na implementaci page controlleru, stejně jako současná Page, avšak má jen potřebné události, které je nutné obsloužit a zároveň je malinko, logičtěji, uspořádává. Tím by mělo být zároveň zajištěno, že by nepřipustila, aby docházelo k poměrně častým, školáckým, chybám.

Posloupnost obsluhovaných událostí

  • Init - v této události má vývojář možnost ovlivnit / zrekonstruovat objektový model stránky ještě před tím, než budou dotažena data ze zaslaného requestu. Toto obnovení by v případě úplných začátečníků mohlo být nahrazeno uložením objektového stromu do ViewState. Pro vyvolání událostí pak použít AutoEventWireup a začátečníka událostí nezatěžovat.
  • Change a Command - zpracování reakcí na klientovo chování - interakci s aplikací. Jak už jsem se zmínil v předchozím článku, Obsluhu události Load můžeme vynechat, neboť data můžeme získat i později a s menší pravděpodobností výskytu chyby.
  • DataRetrieve - po zpracování reakcí od klienta je možné na jejich základě získat data a navázat je na zobrazovací prvky

Pro začátečníka myslím plně dostačující událostní model. Samozřejmě stále by měl možnost reagovat na události zobrazovacích prvků jako třeba GridView a jeho RowDataBound, které nesouvisí s událostmi stránky.

Teorie krásná věc

To co jsem výše popsal je jen moje teorie, která vznikla jako reakce na události uplynulých dnů a z otázek asp.net začátečníků. Jak ji však přenést do praxe? Je mi celkem jasné, že asi nepůjde jenom podědit třídu Page a skrýt události, ale bude to chtít vytvořit vlastní implementaci asp.net Page controlleru a zároveň zachovat veškerou funkcionalitu, která je v současné chvíli.

Takto popsané to vypadá velice jednoduše, ale co na takový první pohled takto vypadá, většinou se změní ve složitý oříšek, a pokud by se našel dobrovolník, který by chtěl pomoci, určitě se nebudu zlobit, když se zapojí a bude alespoň konzultantem. Zatím mám v hlavě nápad a chuť jej realizovat, teď ještě najít dostatek času a pustit se do toho.

Myslíte, že to má vůbec význam, se do toho pouštět a nebo vidíte nějaký neřešitelný zádrhel?

Publikováno pod: .net technology