V předchozím článku o serverových ovládacích prvcích jsme se naučili mapovat klientské události na serverové. Tentokrát si ukážeme, jak implementaci událostí optimalizovat. Na závěr upravíme jednoduchý serverový ovládací prvek z minula za účelem podpory optimalizovaných událostí.

Proč není vhodné používat pouze deklarace událostí

V případě, že serverový ovládací prvek obsahuje větší množství událostí, není efektivní události pouze deklarovat a nechat na .Net Frameworku registraci delegátů k události. Jak .Net Framework s událostmi pracuje? Deklarace události má následující strukturu:

<Modifikátor přístupu> event <Delegát události> <Název události>

Modifikátor přístupu určuje viditelnost události – události jsou většinou veřejné (public). Klíčové slovo event jazyka C# samozřejmě oznamuje, že deklarujeme událost. Delegát události determinuje signaturu metod, které mohou být zaregistrovány jako odběratelé události. Název je libovolný identifikátor události. Vždy, když kompilátor narazí na deklaraci události, vytvoří privátní člen typu <Delegát události>, jenž je použit k ukládání všech delegátů zaregistrovaných k události. Problémem je, že i když není k události zaregistrován žádný delegát, privátní člen každé instance serverového ovládacího prvku zabírá zcela zbytečně místo v paměti.

U událostí jsou navíc vytvořeny přístupové body bezpečné pro multithreading s názvy Add a Remove, sloužící k registraci a zrušení registrace delegátů. Protože multithreading je v ASP.NET aplikacích využíván zřídka (pokud vůbec někdy), je žádoucí eliminovat režii, která je daní za threadově bezpečný přístup.

Optimalizovaná implementace událostí

Naštěstí tvůrci ASP.NET si nepříjemné aspekty událostního modelu uvědomili a do třídy Control přidali chráněnou vlastnost Events, která vrací instanci třídy EventHandlerList, s jejíž pomocí můžeme deklarovat události efektivněji. Například hypotetickou událost Click imaginárního tlačítka bychom mohli implementovat následujícím postupem.

Vytvoříme pro událost unikátní klíč, jenž bude privátním (private) a statickým (static) členem serverového ovládacího prvku. Každý klíč je instancí třídy object. Z důvodu statické deklarace bude klíč sdílen všemi instancemi prvku.

private static object EventClickKey = new object();

Namísto pouhé deklarace události poskytneme také vlastní implementaci přístupových bodů pro přidání a odebrání delegáta:

public event EventHandler Click
{
  add
  {
    Events.AddHandler (EventClickKey, value);
  }
  remove
  {
    Events.RemoveHandler (EventClickKey, value);
  }
}

Třída EventHandlerList má metodu AddHandler, která v prvním argumentu přijímá klíč události a ve druhém delegáta, který má být zaregistrován k události. Když metoda AddHandler nenalezne pro zadaný klíč delegáta, je vytvořena nová položka s předaným klíčem a novým delegátem. Pokud metoda delegáta nalezne, je nový delegát zkombinován s existujícím delegátem. Metoda RemoveHandler podobným způsobem odstraní zaregistrovaného delegáta. Pokud se snažíme odstranit nezaregistrovaného delegáta, metoda náš nesmyslný pokus tiše ignoruje.

Dále musíme změnit chráněné metody odpovědné za vyvolání událostí, protože již nemáme přímý přístup k delegátu události. Delegáta události získáme předáním klíče události indexeru třídy EventHandlerList:

public virtual void OnClick(EventArgs e)
{
  EventHandler eh = (EventHandler) Events[EventClickKey];
  if (eh != null)
    eh(this, e);
}

Úprava serverového ovládacího prvku

Na serverovém ovládacím prvku s didaktickou funkcí, který jsme vytvořili v předchozím článku, byly demonstrovány možnosti serverových událostí. Nyní v něm změníme standardní události na optimalizované, abyste jej mohli používat jako referenční prvek vždy, když budete sami psát vlastní události ( viz zdrojový kód).

Nejprve vytvoříme unikátní klíče pro události Click a Change:

private static object EventClickKey = new object();
private static object EventChangeKey = new object();

Dále budeme registrovat delegáty k událostem přes vlastnost Events:

public event EventHandler Change
{
  add
  {
    Events.AddHandler(EventChangeKey, value);
  }
  remove
  {
    Events.RemoveHandler(EventChangeKey, value);
  }
}

Kód pro událost Click, který zde nebudu uvádět, se liší pouze klíčem události. Z toho můžete usoudit, že změnové i „akční“ události se optimalizují zcela identickým způsobem. Nakonec musíme ještě upravit chráněné metody odpovědné za vyvolání událostí – opět je uveden pouze výpis metody pro vyvolání události Change:

protected virtual void OnChange(EventArgs e)
{
  EventHandler eh = (EventHandler) Events[EventChangeKey];
  if (eh != null)
    eh(this, e);
}

V testovacím projektu si můžete ověřit, že z hlediska uživatele serverového ovládacího prvku se nic nezměnilo.

Po přečtení tohoto článku byste měli vědět o serverových událostech vše podstatné. Můžete tak vytvářet vlastní sofistikované ovládací prvky, které efektivním způsobem komunikují se svým okolím pomocí událostí.

Žádný příspěvek v diskuzi

Odpovědět