Otázky a odpovědi

Programátorská poradna

Časová náročnost (min):

Začátečník

Pokročilý

Profesionál

Použitý operační systém : Hlavní vývojový nástroj :

Další vývojový software :

Jiný software :

Windows 2000 SP4

Visual C# .NET 2003

Visual C++ .NET 2003

Žádný

 

 

Vážení čtenáři,

 

jelikož je naším cílem, abyste se při čtení otázek a odpovědí cítili ještě příjemněji než kdykoliv předtím, rádi bychom vám představili některé novinky, které by měly zabezpečit rychlou a efektivní práci s množstvem informací, které se nachází na následujících řádcích. A o jaké změny jde? Zde je jejich seznam:

 

 

o        Dotazy pro začínající programátory (modrá barva)

o        Dotazy pro pokročilé programátory (oranžová barva)

o        Dotazy pro profesionální programátory (červená barva)

 

 

 

Obsah

Obtížnost

Čas (min)

Jak vytvořit přetíženou metodu

Nahrazení originální ikony aplikace uživatelskou ikonou

Odvození třídy z bázové třídy napsané v řízeném C++ a zavolání metody bázové třídy z konstruktoru podtřídy

Charakteristika techniky boxing a programová ukázka aplikace této techniky

Volání funkce Windows API z aplikace napsané v C#

Vhodnost programovacího jazyka C# pro programátora ve Visual Basicu .NET

Vystředění formuláře za běhu aplikace

Vytváření zpracovatelů událostí v režimu návrhu a běhu aplikace

 

 

Býval jsem programátorem v C, ovšem teď jsem se začal učit C#. Potřeboval bych do své aplikace implementovat přetížené metody, a proto bych se vás chtěl zeptat, zdali je možné v C# přetížit metodu, resp. funkci. Za odpověď vám předem děkuji.

 

Ano, je to možné. Přetěžování metod je užitečná technika, která dovoluje programátorům vytvořit několik exemplářů metody se stejným názvem, ovšem rozdílnou sadou formálních parametrů. Ačkoliv je nutné, aby všechny verze přetížené metody disponovaly stejným názvem a rozdílnou signaturou, není nutné, aby se lišili v typu návratové hodnoty či v deklaraci modifikátoru přístupu. Ukažme si zdrojový kód, který pracuje s přetíženou metodou:

 

using System;

 

namespace Pokusy

{

       /// <summary>

       /// Třída demonstruje použití přetížené metody.

       /// </summary>

       public class A

       {

             public A()

             {

                    //Tělo konstruktoru.

             }

            

             //První varianta přetížené metody, která vrací název aplikace

             //v podobě textového řetězce.

             public string Metoda()

             {

                    return System.Windows.Forms.Application.ProductName;              

             }

 

             //Druhá varianta přetížené metody, která zabezpečí spuštění

             //aplikace, jméno které zadá programátor.

             public void Metoda(string NázevAplikace)

             {

                    System.Diagnostics.Process Proces;

                    Proces = new System.Diagnostics.Process();

                    Proces.StartInfo.FileName = NázevAplikace;

                    Proces.Start();

             }

       }

}

 

Jestliže vytvoříte instanci třídy a budete chtít použít metodu, technologie IntelliSense vám nabídne seznam přetížených variant dané metody:

 

 

Obr. 1 - Bublinová nápověda se seznamem variant přetížené metody

 

 

Zpět na obsah

 

Standardní ikona, kterou C# přiřazuje každé aplikaci typu Windows Application, se mi nelibí. Mohl bych tuto ikonu nahradit svou vlastní? A pokud ano, tak jak?

 

Máte pravdu, implicitní ikona aplikace není nijak zvlášť pohledná. Naštěstí, C# vám nabízí rychlý a efektivní způsob, jak nahradit původní ikonu svým vlastním výtvorem. Zaměřte svou pozornost na dialogové okno Solution Explorer a poklepejte na položku s názvem App.ico:

 

 

Obr. 2 – Položka App.ico v okně Solution Explorer

 

Okamžitě se otevře vestavěný editor pro tvorbu grafických ikon, který vám umožní modifikovat podobu implicitní ikony aplikace. S pomocí dostupných grafických nástrojů, jejichž ikony se nacházejí na příslušném panelu nástrojů, můžete buď upravit stávající ikonu, nebo všechno smazat a začít s kreslením své vlastní ikony takříkajíc „na zelené louce“. Ukázková podoba modifikované ikony může vypadat například i takto:

 

 

Obr. 3 – Potenciální podoba modifikované ikony aplikace

 

Budete-li s grafickou úpravou vaší aplikační ikony spokojen, můžete vydat povel na sestavení aplikace. Podíváte-li se do složky se spustitelným (.EXE) souborem aplikace, uvidíte, že tento je již opatřen novou ikonou:

 

 

Obr. 4 – Nová podoba ikony aplikace

 

 

Zpět na obsah

 

Dobrý den, chtěl bych vás požádat o pomoc při řešení svého problému. Potřeboval bych z třídy, kterou mám připravenou v řízeném C++, odvodit podtřídu v C# a z konstruktoru této podtřídy zavolat metodu bázové třídy. Můžete mi, prosím, poradit?

 

Poradit vám samozřejmě můžu a také to ihned udělám. Předpokládejme, že kód třídy v řízeném C++ vypadá následovně:

 

Poznámka

Visual C++ .NET se při generování kostry projektu Managed C++ Class Library chová poněkud svérázně. Veškerý programový kód třídy je totiž umístěn do hlavičkového souboru (.h), přičemž odkaz na tento hlavičkový soubor je vložen do implementačního souboru (.cpp). Některým programátorům tento model nemusí vyhovovat, ovšem my budeme dodržovat standardní linii. 

 

//Tento programový kód se nachází v hlavičkovém souboru (.h)

//řízené třídy.

 

#pragma once

//Import metadat z assembly System.Windows.Forms.dll.

#using <System.Windows.Forms.dll>

 

//Import jmenných prostorů.

using namespace System;

using namespace System::Windows::Forms;

 

//Deklarace jmenného prostoru třídy.

namespace RizeneCPP

{

       //Deklarační příkaz řízené třídy s názvem TridaCPP.

       public __gc class TridaCPP

       {

 

             //Veřejně přístupný konstruktor třídy.

             public: TridaCPP()

                           {

                                              

                           }

            

                    // Metoda, která bude volána z kódu jazyka C#.

                    void Metoda(void)

                           {

                                  //Aktivace metody Show třídy MessageBox, které

                                  //je předán řízený textový řetězec znaků.

                                  MessageBox::Show(S"Metoda byla aktivována.");

                           }

       };

}

 

Budete-li chtít dědit z této třídy v C#, můžete použít tento kód:

 

using System;

 

namespace JmennyProstorCS

{

       /// <summary>

       /// Třída je podtřídou třídy vytvořené v řízeném C++.

       /// </summary>

      

       //Deklarační příkaz, jenž vytváří podtřídu z třídy

       //napsané v řízeném C++.

       public class TridaCS : RizeneCPP.TridaCPP

       {

             //Konstruktor třídy.

             public TridaCS()

             {

                    //Použití klíčového slova base, které umožňuje volat

                    //metody bázové třídy z odvozených tříd.

                    base.Metoda();

             }

       }

}

 

Aktivaci metody bázové třídy zabezpečuje klíčové slovo base, za kterým následuje tečka a pojmenování cílové metody, kterou budete chtít zavolat. Aby třída v C# věděla, od jaké třídy je odvozená, je nutné do projektu s podtřídou začlenit referenci na dynamicky linkovanou knihovnu (DLL), v níž je uložen kód řízené třídy napsané v C++.

 

Poznámka

Řízené C++ a také C# podporují pouze jednoduchou dědičnost. To znamená, že není možné vytvořit v C# podtřídu, která by byla odvozena od více než jedné třídy. Implementace jenom jednoduché dědičnosti vychází z požadavku společné jazykové specifikace (Common Language Specification) platformy .NET Framework.

 

Finálním krokem je vytvoření instance podtřídy ve zvoleném zpracovateli události (např. button1_Click):

 

private void button1_Click(object sender, System.EventArgs e)

       {

             JmennyProstorCS.TridaCS Objekt = new JmennyProstorCS.TridaCS();

       }

 

 

Zpět na obsah

 

Dočetl jsem se, že C# podporuje tzv. boxing, ovšem nevím, co tento termín znamená. Chtěl bych vás proto poprosit o vysvětlení a také programovou ukázku. Děkuji pěkně.

 

Výraz boxing označuje techniku přetypování hodnotového datového typu na objektový protějšek. Povězme, že máme deklarovanou a inicializovanou proměnnou x datového typu int:

 

int x = 100;

 

Typ int je primitivním a současně hodnotovým typem, což znamená, že je schopen uchovávat jenom platné celočíselné hodnoty ze stanoveného intervalu. Když vytvoříte proměnnou typu int, C# vyhradí v paměti počítače dostatek místa pro uložení hodnoty této proměnné. Paměťový prostor, do něhož jsou ukládány hodnoty hodnotových datových typů, se nazývá zásobník (stack). Zásobník je jednoduchá a značně efektivní datová struktura, která pracuje na principu LIFO (Last-In-First-Out, Poslední-Dovnitř-První-Ven). Podle tohoto principu je možné ze zásobníku brát jako první tu hodnotu, která byla na zásobník umístěna jako poslední. Na druhé straně existují referenční datové typy. Proměnné těchto typů, na rozdíl od jejich hodnotových kolegů, neobsahují hodnotu, nýbrž odkaz, neboli referenci, chcete-li. Z technického hlediska představuje odkaz paměťovou adresu. Máme-li tedy odkaz, víme, že na jisté paměťové adrese se nachází nějaká cílová entita. Touto entitou bývá zpravidla objekt. Referenční proměnné jsou zajímavé také z jiného důvodu: Ačkoliv ony samotné jsou ukládány na zásobník, entita, na níž ukazují, se nachází v jiné paměťové oblasti, které se říká řízená hromada (managed heap). Deklarace a inicializace referenční proměnné může mít tuto podobu:

 

Form y = this;  

 

Odkazová proměnná y může obsahovat odkaz na instance (objekty) třídy Form. Důkazem tohoto tvrzení je skutečnost, že proměnná y je okamžitě úspěšně inicializována pomocí klíčového slova this. Klíčové slovo this představuje odkaz na aktuální instanci třídy Form.     

 

Paměťová náročnost proměnných hodnotových typů je poměrně nízká (několik bajtů) a práce s nimi na zásobníku efektivní. V jistých případech by ovšem bylo vhodné, kdyby bylo možné s proměnnou hodnotového typu pracovat jako s proměnnou referenčního typu. A právě tuto situaci řeší boxing.

 

Podstata boxingu spočívá v tom, že proměnnou hodnotového typu „zaboxujeme“. Tuto operaci můžeme provést pomocí tohoto programového kódu:

 

object z = x;

 

Technika boxing probíhá přibližně v těchto krocích:

 

1.      Na řízené hromadě je vytvořen objekt třídy System.Object.

2.      Hodnota proměnné x je nakopírována do tohoto objektu.

3.      Je vrácena paměťová adresa, na které se řízený objekt nachází.

4.      Tato paměťová adresa je uložena do připravené referenční proměnné z.

 

Ano, tento algoritmus je reálný, i když přiznávám, že na první pohled vám může připadat zvláštní. Ovšem, jak je možné uvedené přetypování? Jednoduše proto, že všechny typy, s kterými v rámci .NET Framework Class Library pracujeme, jsou odvozeny od základního typu System.Object. Je-li tomu tak, pomocí indukce dojdeme k poznání, že když jsou všechny typy odvozeny od typu System.Object, je možné také všechny typy zpětně přetypovat na tento bázový datový typ. 

 

Obr. 5 – Grafická ilustrace techniky boxing

 

Pro programátory je k dispozici také opačná operace k boxingu, tzv. unboxing.

 

Nakonec dodejme, že s boxingem se můžete střetnout i v jiných programovacích jazycích platformy .NET, mezi které patří Visual Basic .NET či C++ s řízenými rozšířenými (managed extensions).

 

Poznámka

V jazyku C# je boxing realizován implicitně, tedy bez jakéhokoliv zásahu ze strany programátora. Pokud aplikační logika C# rozhodne, že je zapotřebí uskutečnit boxing, stane se tak. Na druhé straně, z výkonového hlediska je boxing zcela jistě méně efektivní jako pouhé umístění proměnné na zásobník. I z tohoto důvodu je boxing v některých jazycích (např. řízené C++) prováděn explicitně (boxing se neuskuteční automaticky, ale sám programátor musí vydat pokyn na jeho realizaci).

 

 

Zpět na obsah

 

Chtěl bych z aplikace napsané v C# zavolat API funkci Windows, ovšem nemůžu najít způsob, jak to provést. Mohl byste mi poradit?

 

Budete-li se pokoušet volat z řízené aplikace neřízenou funkci aplikačního programovacího rozhraní (API) Windows, budete muset splnit před samotným použitím vámi požadované funkce několik podmínek:

 

1.      Deklaraci API funkce musí předcházet použití speciálního atributu DllImportAttribute, který se nachází ve jmenném prostoru System.Runtime.InteropServices. Atribut DllImportAttribute naznačuje, že bude importována API funkce s neřízeným kódem. Ve skutečnosti je atribut pouze jiným označením pro speciální třídu se stejným názvem (DllImportAttribute). Konstruktor této třídy pracuje s jedním parametrem typu string, kterým je název DLL knihovny, ve které je uložen kód API funkce, kterou chcete použít.

 

2.      Deklarační příkaz API funkce musí obsahovat klíčová slova static a extern.

 

3.      Deklarace API funkce v řízeném kódu musí přesně odpovídat prototypu funkce v neřízeném kódu. To znamená, že deklarace musí obsahovat stejné jméno, dále stejnou signaturu s příslušnými datovými typy formálních parametrů funkce a také stejnou návratovou hodnotu (pokud existuje).

 

Jestliže budou splněny tyto podmínky, bude API funkce úspěšně naimportována do kódu vaší řízené aplikace. S API funkcí můžete posléze pracovat jako s jakoukoliv jinou funkcí. Podívejme se na ukázku použití API funkce operačního systému Windows:

 

             // ... Tento programový kód se nachází uvnitř třídy Form1.

             static void Main()

             {

                    Application.Run(new Form1());

             }

 

             [System.Runtime.InteropServices.DllImport("User32")]

                    private static extern bool MoveWindow(int hWnd,

                    int X, int Y, int nWidth, int nHeight, bool bRepaint);

 

             [System.Runtime.InteropServices.DllImport("User32")]

                    private static extern bool AnimateWindow(int hWnd,

                    uint dwTime, uint dwFlags);

 

             private void button1_Click(object sender, System.EventArgs e)

             {

                    frm = new Form();

                    frm.Load += new EventHandler(frm_Load);

                    frm.Show();

             }

            

             Form frm;

 

             private void frm_Load(object sender, System.EventArgs e)

             {

                    int handle = frm.Handle.ToInt32();

                    MoveWindow(handle, 362, 234, 300, 300, true);

                    AnimateWindow(handle, 200, 0x00080000);

             }

             // ... zde pokračuje kód třídy Form1.

 

Ukázkový programový kód používá pro přesun a animaci nově vytvořené instance třídy Form dvě API funkce: MoveWindow a AnimateWindow. Před každou z funkcí se nachází atribut DllImport se jménem dynamicky linkované knihovny (DLL), ve které je uložen kód dané funkce (obě zde použité funkce jsou uloženy v souboru User32.dll). Velmi důležité je, aby byl atribut zapsán v hranatých závorkách. Za atributem se nachází samotný deklarační příkaz, který je složen z modifikátoru přístupu (private), klíčových slov static a extern, typem návratové hodnoty funkce a její signaturou (datové typy přitom musí odpovídat datovým typům použitím v neřízeném kódu API funkce). Ve výše uvedené programové ukázce je dále deklarována referenční proměnná frm s oborem třídy, která může uchovávat referenci na instance třídy Form.  V událostní proceduře button1_Click je vytvořena nová instance třídy Form, přičemž dochází také k vytvoření systémového delegáta (EventHandler) pro zpracovatele události Load nově vytvořené instance. Jakmile bude aktivována metoda Show objektu frm, delegát usměrní program tak, aby byl uskutečněn programový kód, jenž se nachází ve zpracovateli události frm_Load. Když dojde k události Load objektu frm, bude vykonán kód zpracovatele frm_Load (k události dojde po zavolání metody Show příslušné instance). Zpracovatel události frm_Load obsahuje následující řádky programového kódu:

 

private void frm_Load(object sender, System.EventArgs e)

       {

             int handle = frm.Handle.ToInt32();

             MoveWindow(handle, 362, 234, 300, 300, true);

             AnimateWindow(handle, 200, 0x00080000);

       }

 

Co ve skutečnosti tento kód provádí? Tak především, je získán handle okna instance třídy Form. Handle představuje jednoznačný identifikátor, pomocí kterého Windows přistupují k vytvořené instanci (hodnota identifikátoru handle je v tomto případě převedena do podoby 32bitového celého čísla pomocí metody ToInt32). Handle okna potřebujeme získat, neboť jej využijeme v obou API funkcích. Abyste přesně věděli, co uvedené API funkce provádějí, představíme si je podrobněji:

 

1.      API funkce MoveWindow má tuto všeobecní podobu (v C/C++):

 

BOOL MoveWindow(

  HWND hWnd,      // Handle okna

  int X,          // Horizontální pozice okna

  int Y,          // Vertikální pozice okna

  int nWidth,     // Šířka okna

  int nHeight,    // Výška okna

  BOOL bRepaint   // Volba, která určuje, zdali bude po přemístění realizováno                                   

                  // také překreslení okna.

);

 

Podoba naší funkce je následovní:

 

MoveWindow(handle, 362, 234, 300, 300, true);

 

Funkce zachovává implicitní velikost okna instance třídy Form (300x300 pixelů), ovšem mění pozici levého horního bodu okna na bod se souřadnicemi (362, 234). Poslední parametr (bRepaint) je nastaven na hodnotu true, což znamená, že ihned poté, co se okno instance přesune, bude provedeno jeho překreslení.

    

2.      API funkce AnimateWindow má tuto všeobecní podobu (opět v C/C++):

 

BOOL AnimateWindow(

  HWND hwnd,     // Handle okna

  DWORD dwTime,  // Doba trvání animace okna

  DWORD dwFlags  // Typ animace

);

 

A opět se podívejme na naší implementaci funkce AnimateWindow:

 

AnimateWindow(handle, 200, 0x00080000);

 

Prvním parametrem funkce je handle okna, které bude animováno. Druhý parametr (dwTime) je datového typu DWORD (typ DWORD představuje 32bitové celé číslo bez znaménka, jehož maximální hodnota je 232-1). V C# se typ DWORD samozřejmě nepoužívá, ovšem jeho ekvivalentem je datový typ uint, jenž disponuje stejným rozsahem platných celočíselných hodnot. Parametr dwTime odpovídá době trvání animace, která se udává v milisekundách. V našem případě bude animace trvat 200 milisekund, což je doporučená hodnota daná způsobem práce operačního systému. Nejhrozivěji pravděpodobně vypadá třetí parametr (dwFlags), jehož hodnotou je podivně vyhlížející číslo v šestnáctkové soustavě 0x0008000. Numerická hodnota 0x0008000 odpovídá interní konstantě AW_BLEND, která se používá v případě, kdy má být okno animováno pomocí tzv. fade efektu. Fade efekt znamená plynulé animování zobrazení okna, přičemž na začátku je okno takřka průhledné a postupně se „zaplňuje“ do standardního barevného schématu a podoby.  

 

Tip

Pokud přemýšlíte nad tím, jak vyjádřit číslo 0x0008000 v desítkové soustavě, zde je návod:

 

1.      Z numerické hodnoty 0x0008000 nejprve odstraníme prefix 0x, který vizuálně připomíná, že pracujeme s číslem v šestnáctkové soustavě. Tím pádem získáváme hodnotu 0008000.

 

2.      Hodnotu 0008000 přetypujeme na nám srozumitelné číslo podle tohoto vzorce:

 

0008000 = 0*167+0*166+0*165+8*164+0*163+0*162+0*161+0*160

 

3.      Z celého vzorce nakonec získáme pouze jedinou hodnotu, kterou je číslo 524 288 (8*164=524 288).

 

 

Zpět na obsah

 

Doposud jsem programoval ve Visual Basicu .NET. Myslíte, že bych se mohl naučit programovat také ve Visual C#?

 

Zcela jistě ano. Visual C# je velmi zajímavý jazyk, který vhodně kombinuje rychlý návrh aplikací, jenž je známý právě z Visual Basicu a flexibilní syntaxi, která je předností jazyka C++. Protože všechny jazyky platformy .NET využívají společné integrované prostředí, na první pohled možná ani nepostřehnete, že se nacházíte uvnitř Visual C#. Visual C# taktéž nabízí vizuální vývoj aplikací, takže grafickou podobu aplikace můžete navrhnout přesně tak, jak to děláte ve Visual Basicu .NET. Na druhé straně je pravdou, že zápis programového kódu se od Visual Basicu podstatně liší a zde vám zcela určitě pomůže předcházející zkušenost s jazykem C nebo C++ (případně s Javou). Pokud neznáte uvedené jazyky, nemusíte zoufat. Seriál Začínáme s jazykem C# vám poskytne všechny potřebné informace pro to, abyste mohli psát své první programy i ve Visual C#. Ve skutečnosti jsou jazyky Visual C# a Visual Basic .NET do velké míry podobné ve smyslu implementace stejných, nebo přinejmenším velmi podobných programovacích prvků. Ku příkladu, oba jazyky umožňují řídit tok programu pomocí rozhodovací konstrukce If (if v C#), ovšem zápis této konstrukce je v C# jiný než ve Visual Basicu (podobně je tomu také třeba při cyklech či prvcích OOP). Sečteno a podtrženo, jestliže dobře ovládáte Visual Basic .NET, při pilném studiu se do tajů Visual C# můžete dostat velmi rychle. Poněkud problematičtější je ovšem přechod k Visual C# pro programátory, kteří pracují s Visual Basicem verze 6. Ty totiž budou muset nejdříve zvládnout všechny inovace a modifikace, které přináší vývojová platforma .NET.          

 

 

Zpět na obsah

 

Pracuji s formulářem, který bych potřeboval vertikálně i horizontálně vycentrovat na obrazovce počítače. Vím, že v režimu návrhu mohu nastavit vlastnost StartPosition na hodnotu CenterScreen, co mám však udělat, když chci provést vystředění formuláře za běhu programu?

 

Událostní proceduru Load formuláře upravte do níže uvedené podoby:

 

       private void Form1_Load(object sender, System.EventArgs e)

             {

                    this.Top = (Screen.PrimaryScreen.Bounds.Height - this.Height) / 2;

                    this.Left = (Screen.PrimaryScreen.Bounds.Width - this.Width) / 2;

             }

 

Abyste mohli provést vystředění formuláře, musíte znát rozměry zobrazovací plochy obrazovky a rozměry samotného formuláře. Rozměry formuláře jsou známé, nakolik Visual C# implicitně vytváří formuláře s velikostí 300x300 obrazových bodů neboli pixelů. Při zrození instance formuláře jsou do vlastností Height a Width této instance uloženy hodnoty 300 pixelů. Pro zjištění rozměrů viditelné plochy obrazovky použijeme třídu Screen. Konstruktor třídy Screen ovšem není veřejný a proto není možné přímo vytvářet instance této třídy. Pokud ovšem zavoláme statickou vlastnost PrimaryScreen, podaří se nám získat instanci třídy Screen. Vrácená instance představuje hlavní zobrazovací jednotku počítačového systému (pokud systém pracuje jenom s jednou obrazovkou, bude vrácena tato, v opačném případě bude vrácena ta zobrazovací jednotka, která je nakonfigurována jako primární). Dále pokračujeme zavoláním vlastnosti Bounds vytvořené instance třídy Screen. Vlastnost Bounds vrací instanci třídy Rectangle (jde o objekt, jenž popisuje obdélníkový region hlavní zobrazovací jednotky). Máme-li instanci třídy Rectangle, můžeme konečně použít vlastnost Height (resp. Width) pro zjištění výšky (resp. šířky) viditelné plochy obrazovky. Předpokládejme, že vlastníte 17palcový monitor a používáte rozlišení 1024x768 obrazových bodů. Za těchto podmínek vrátí příkaz Screen.PrimaryScreen.Bounds.Height hodnotu 768 a příkaz Screen.PrimaryScreen.Bounds.Width zase vrátí hodnotu 1024. Od takto získaných hodnot posléze odečteme hodnoty, které reprezentují výšku (resp. šířku) formuláře a finální výsledky vydělíme dvěma. Do vlastnosti Top formuláře bude po provedení všech nastíněných operací uložena hodnota 234, zatímco vlastnost Left bude obsahovat hodnotu 362 (obr. 6).

 

        

Obr. 6 – Grafická ilustrace vystředění formuláře na obrazovce s rozlišením 1024x768 obrazových bodů

 

 

Zpět na obsah

 

Chtěl bych se zeptat, jak je možné ve Visual C# vytvářet zpracovatele události, a to jak v režimu návrhu, tak i za běhu aplikace. 

 

V režimu návrhu aplikace vytvoříte zpracovatele události takto:

 

1.      Na formuláři vyberte ten ovládací prvek, pro který chcete vytvořit zpracovatele události.

2.      V okně Properties Window klepněte na tlačítko Events ().

3.      Vyhledejte položku s názvem požadované události (např. Click) a poklepejte na tuto položku.

4.      Visual C# okamžitě vygeneruje programovou kostru událostní procedury a otevře okno editoru pro zápis programového kódu.

5.      Vyplňte tělo vytvořené událostní procedury vhodným programovým kódem.

 

Jestliže budete chtít spojit událost s jejím zpracovatelem za běhu programu, budete muset všechny potřebné operace provést přímo z programového kódu. Aby bylo možné vytvořit spojení mezi událostí a příslušným zpracovatelem, musíte vytvořit systémového delegáta, který bude zodpovědný za to, aby událost našla svého zpracovatele.

 

Následující fragment kódu byl vyňat ze třídy Form1. Můžete si v něm všimnout událostní proceduru button1_Click. V této proceduře dochází k vytvoření nové instance třídy Button (s názvem btnTlačítko1), dále jsou nastaveny některé klíčové vlastnosti nově vytvořené instance a instance je přidána do kolekce ovládacích prvků formuláře.

 

Spojení mezi události Click tlačítka btnTlačítko1 a zpracovatelem této události (btnTlačítko1_Click) zabezpečuje systémový delegát EventHandler. Při této programové operaci je velmi důležité správné použití operátorů += a new. Nakonec už stačí jenom napsat událostní proceduru btnTlačítko1_Click, která ovšem musí disponovat stejnými prvky, jako systémový delegát (nesmí vracet hodnotu a musí pracovat se dvěma parametry typu object a System.EventArgs). Pokud máte zkušenosti s jazykem C nebo C++, můžete si delegáta představit jako funkční ukazatel, který je ale v jazyku Visual C# zcela typově bezpečný. Delegát tak ve skutečnosti obsahuje runtime adresu funkce, v našem případě zpracovatele události, a tohoto zpracovatele aktivuje vždy, když je o to požádán (neboli vždy, když uživatel klepne na tlačítko).   

 

             private void button1_Click(object sender, System.EventArgs e)

             {

                    Button btnTlačítko1 = new Button();

                    btnTlačítko1.Text = "Tlačítko";

                    btnTlačítko1.Location = new Point(10, 100);

                    btnTlačítko1.Size = new Size(200, 100);

                    this.Controls.Add(btnTlačítko1);

                    btnTlačítko1.Click += new System.EventHandler(btnTlačítko1_Click);

             }

 

             private void btnTlačítko1_Click(object sender, EventArgs e)

             {

                    MessageBox.Show("Právě jste klepli na tlačítko.");

             }

 

Graficky můžeme vztah mezi událostí, jejím zpracovatelem a systémovým delegátem znázornit takto:

 

 

Obr. 7 – Znázornění vztahu mezi událostí, systémovým delegátem a zpracovatelem události

 

 

Zpět na obsah

 

 

 

Právě jste dočetli Otázky a odpovědi.

 

Pokud se chcete dozvědět více informací o programování v C#, neváhejte a navštivte i další součástí rubriky Visual C# .NET:

 

Začínáme s jazykem C# - Je určen především zájemcům o studium základních a pokročilých programovacích prvků v jazyku C#. Jestliže se chcete začít učit programovat právě v jazyku C#, nebo patříte-li k programátorům, kteří přecházejí z prostředí jiného programovacího jazyka, naleznete v jednotlivých dílech seriálu vše, co budete potřebovat ke snadnému zvládnutí jazyka C#.

 

Dobrodružství v C# - Součást rubriky, ve které najdou zalíbení zejména programátoři s dobrodružnou povahou a jiskrou v očích. Na tomto místě zažijete mnohá dobrodružství a dozvíte se, jak odkrýt i ta nejtajnější zákoutí programovacího jazyka C#. Mějte ovšem na paměti skutečnost, že při některých experimentech jde skutečně o život!

 

 

Autor: Ján Hanák