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

.net technology

27
V

Binding source a jeho použití

V minulém příspěvku jsem se věnoval propojení objektu BindingSource s LINQ to SQL. Jelikož z několika příspěvků, týkajících se bindování dat na zobrazovací prvky vyplívá, že ne všichni jsou s objektem BindingSource plně srozuměni, rád bych napsal krátký návod, jak jej použít.

Co je BindingSource

Z pohledu 10000 stop si můžeme představit BindingSource jako komponentu, která poskytuje rozhraní mezi daty a vázanými prvky uživatelského rozhraní. Požití je tedy takové, že komponenta přebírá jako svůj datový zdroj data ze servisní, nebo datové vrtstvy a na tuto komponentu jsou poté navázány zobrazovací prvky. Tím, že vložíme mezi data a zobrazovací prvky komponentu BindingSource, umožní nám to vložit zároveň s tím i služby (události, metody a vlastnosti), které nemusí poskytovat data samotná.

Pokud se sneseme o něco níže a podíváme se na komponentu zblízka, zjistíme, že BindingSource obaluje třídu CurrencyManager a přidává několik dalších "vychytávek", které nám umožňují snažší práci s uživatelským rozhraním. Ti, kdož si pamatují práci s CurrencyManager případně třídou BindingManagerBase ve verzích .net frameworku 1.x, uvidí poměrně velký krok kupředu a ulehčení práce.

Co vývojáři přinese použití BindingSource

Určitě si každý nyní řekne, proč vlastně takovou komponentu používat, vždyť bindovat uživatelské prvky na data mohu i tak, proč tedy používat nějaký další prvek, který mi vše může znepřehlednit. Opak je spíše pravdou, právě díky tomu, že mezi data a UI vložíme tuto abstraktní vrstvu, získáme několik výhod, které nemusí být na první pohled patrné.

IBindingList

Prvním přínosem je zpřístupnění interface IBindingList i pro seznamy, které toto rozhraní nepodporují. Pokud se podíváte na toto rozhraní, zjistíte, že poskytuje hned několik metod a vlastností, které můžete využít při bindování třeba na DataGridView, jak bylo zmíněno v předchozím příspěvku.

Jenže zpřístupněním samotného rozhraní vše nekončí, naopak, máme k dispozici ještě něco více a to ve spojistosti právě s rozhraním IBindingList. Je to metoda AddingNew, která se vyvolá v okamžiku, kdy je zažádáno o přidání nového objektu do seznamu. Přihlášení k odběru k této události využijeme třeba v případě, kdy objekty tvoříme přes nějakou factory třídu a chceme mít tak vytváření nových instancí plně pod kontrolou.

Zabalený CurrencyManager

Jak jsem se již zmínil výše, BindingSource nám obaluje dříve používanou třídu CurrencyManager a tím také vyvolávání událostí CurrentChanged a PositionChanged. Nyní se tak k těmto událostem dostaneme přehledněji a z jednoho místa, ale nejedná se jen o zmíněné události ale též metody a vlastnosti CurrencyManagera.

Mezi ty, které bylo nutné používat patřily metody ResumeBinding a SuspendBinding, jenže ty měly efekt pouze na tzv. Simple binding, tedy bindování na jednoduché prvky (např. TextBox). Použitím komponenty BindingSource se vše zjednodušilo a nastavením vlastnosti RaiseListChangedEvents na hodnotu false se zruší bindování jak na jednoduché prvky, tak i na prvky komplexní, jako je třeba DataGridView.

Pro ty, kteří rádi vidí pod pokličku uvedu, že k přerušení bindování dojde z toho důvodu, že přestane být vyvolávána metoda ListChanged.

Tváří se typově

Lépe to vystihnout nedokáži, ale lepší, než kdyby se tvářil kysele, že? Co si pod tím pojmem představit? Pokud chcete v design time navrhnout vzhled a rozmístění ovládacích prvků, potřebujete vědět, na co mají být prvky navázány - jakého typu bude daný objekt. Obdobně pak třeba u DataGridView, když chcete bindovat sloupečky. A právě proto je tu BindingSource, aby vám ulehčil vaši činnost. Stačí jako datový zdroj uvést

bindingSource.DataSource = typeof(MujObjekt);

a rázem vám jsou zpřístupněny vlastnosti objektu MujObjekt. Tudíž BindingSource se tváří, jako by byl instancí tohoto objektu.

Zjednodušuje binding

neříkejte mi, že jsem to neříkal celou dobu. Dostávám se k poslednímu bodu, že se vám to zdá podivné, když vše předchozí uvedené zjednodušilo binding už dostatečně?  Jenže, kdo by nechtěl ještě víc.

Určitě znáte ten klasický scénář, kdy si vrátíte objekty s daty z nějaké služby a ty přímo nabindujete na zobrazovací prvky. Poté však zjistíte, že musíte napsat spoustu obslušného kódu okolo, protože tyto objekty a bindování na ně není stálé. A tak vám samotné použití designeru nestačí, musíte se vrhnout do kódu a přepisovat již jednou vytvořené.

Jenže nyní již nemusíte, víte, že existuje komponenta BindingSource, která je vám nápomocná při zobrazování a editaci dat a tak použijete ji jako datový zdroj k bindování.

V jednoduchosti je síla

Právě v jednoduchosti a snadnosti použití komponenty BindingSource je síla, kterou můžete využít ve svůj prospěch. Není snad nic lepšího pro vývojáře, než mít snadno čitelný a udržovatelný kód a k tomu právě BindingSource přispívá. Snad vám k tomu pomohl i tento článek.

Publikováno pod: .net technology
21
IV

LINQ to SQL a BindingSource

Je to jen pár měsíců, co je na světě .net framework verze 3.5 a s ním spoustu cukrátek, které potěší nejednoho vývojáře na .netím frameworku. Někteří z nás sice vzhlížejí ještě kousek dál - třeba k ADO.NET Entity Frameworku, ale pro ty, kteřím stačí současný stav a pohrávají si s LINQ to SQL, tu mám jeden tip.

Přestože jsme na builderu nedokázali odhalit přesnou příčinu nefunkčnosti nad položenou otázkou LINQ + SQL + datagridview - uložení změn do db, snažil jsem se přijít na důvody, proč u tazatele daná kombinace nebyla funkční. Přiznám se hned na začátku, že jsem na rozumné vysvětlení nepřišel.

Jak propojit data na DataGridView

Vhodnou cestou jak napojit data z datového zdroje, v tomto případě tedy entit vytvořených pomocí LINQ to SQL, na DataGridView je použít objektu BindingSource. Při nastavení vlastnosti DataSource dojde k provázání dat se zobrazovacím prvkem a v případě, že máme povoleno na DataGridView přidávání, případně mazání řádků máme vše hotovo.

Skutečně nám tedy stačí, ve vhodnou chvíli volat událost SubmitChanges nad stejnou instancí DataContextu, jakou jsme naplnily BindingSource a o vše se postará interní logika. Není tak třeba registrovat se k žádným událostem - snad až na jedinou a tou je událost pro přidání nového záznamu AddingNew, a to jen v případě, že požadujeme mít nově přidaný objekt uživatelsky nainicializovaný.

Stejně tak není třeba notifikovat DataContext, lépe řečeno Table<TEntity> kolekci o nově přidaných objektech pomocí metody InsertOnSubmit, stejně tak jako psát kód navíc, abychom zjistili odstraňovanou položku z kolekce a tu mohli předat do metody DeleteOnSubmit.

Ukázka

Jak tedy může taková jednoduchá práce s DataGridView a jeho napojením na data vypadat? Následující část kódu je skutečné minimum:

// metoda pro získání dat z datového zdroje LINQ to SQL
private IEnumerable provideData() {
 var result = from data in _db.TestRows
  select data;
 return result;
}
// metoda pro uložení editovaných dat
private void saveClick(object sender, EventArgs e) {
  _db.SubmitChanges();
}

... // tam kde potrebujeme nahrát data a napojit je na zobrazovací prvek
bindingSource.DataSource = provideData();
...
Publikováno pod: .net technology , builder.cz , Linq
8
IV

IClientApp.AddAward(JardaJirava MVP)

Interface pro tvorbu klientských aplikací byl vytvořen, předpis metody definován. Stačí tedy jen vytvořit správnou instanci a předat parametry, to se 1.dubna 2008 stalo a po prvotním špatném volání a vyhození Exception jsem dostal tento výsledek:

Congratulations! We are pleased to present you with the 2008 Microsoft® MVP Award! The MVP Award is our way to say thank you for promoting the spirit of community and improving people’s lives and the industry’s success every day. We appreciate your extraordinary efforts in Client App Dev technical communities during the past year.

Já k tomu mohu dodat jedno, díky patří také vám, že se ptáte a inspirujete mě tak k aktivitě a předávání těch něco málo znalostí a zkušeností, které mám s .net frameworkem.

Malé lákadlo

Vím. slibovat se příliš nevyplatí, ale rád bych zde prezentoval více právě v oblasti smart i rich client aplikací a něco málo již mám nachystáno ... takže buďte naladěni. Díky

Publikováno pod: .net technology
29
II

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

Včera v podvečer se uskutečnilo již třetí setkání přispěvatelů konference o .net technologii provozované na serveru builder.cz. Tentokrát jsme se všichni sešli v příjemném prostředí restaurace Bílá vrána, kterou doporučil jeden z účastníků Martin Vobr, díky.

Pokud bych se měl poohlédnout po průběhu setkání, tak se všichni bavili, dozvídali se nové věci a sdělovali si historky ze své každodenní práce, a nejen o práci se povídalo. Myslím, že ten, kdo přišel, udělal dobře a strávil příjemný večer se známými nicky a neokoukanými tvářemi. Počet vývojářů, kteří se přišli takto bavit se opět zvýšil a tentokrát nás bylo již deset, ano 10.

A jen tak na okraj, nebo spíše pod čáru. Ani Alt+Enter v Blendu bohužel Properties dialog nevyvolá, ach jo, a já se v tu chvíli tak zaradoval. Přinesl jsem si však i jiné rady, a také několik málo připomínek k setkání. Takže příště o něm budu informovat i tady na stránkách krátkým příspěvkem, aby se k vám dostala tato informace pomocí RSS čtečky. Jen přípomínka pro mě, nezapomenout pozvat i Jirku B.

Závěrem

Jak už jste se nejspíše dovtípili, setkání budou pokračovat, takže se s vámi budu těšit opět za nějaké čtyři měsíce.

Díky všem, kteří se zúčastnili, a příště třeba i s dalšími.

Publikováno pod: .net technology , builder.cz
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