Progress Bar komponent

Tags:    c#
Skrevet af Bruger #2730 @ 18.11.2004
Denne artikel gennemgår hvordan man selv bygger en .NET komponent i C# og tilføjer den til sin Toolbox i Visual Studio. Den komponent vi vil bygge er en almindelig progressbar, der har en 3D effekt.

Design af komponenten


Som ved alle de udviklingsprojekter man laver bør man inden man sætter sig til tastaturet for at kode designe hvordan det færdige resultat skal se ud. Dette gøres for at minimere det overhead der kan være ved at komme i tanke om en central del af sin løsning når man er 80% færdig. Den komponent vil vil bygge skal bestå af en tekst streng, en progressbar og et tal der indikerer hvor mange procent vores progressbar viser. Det vi skal have bygget skal i sidste ende komme til at se ud som nedenstående tegning:



Vi vil altså skrive en tekst i starten af vores komponent. Vi Skal derefter have tegnet vores progressbar, den består af en sort ramme på 1 pixels bredde, vi skal have skrevet hvor mange procent den viser, der skal tegnes en 3D effekt der består af en lysere farve for oven samt en mørkere farve forneden til at give den rigtige 3D effekt.

Begyndelsen


Når man starter med at skrive sin egen visuelle komponent laver man for det meste et nyt projekt af typen "Windows Control Library", dette vil compile til en .NET assembly (.dll fil) som så kan referes som alle andre komponenter.



Når vi har fået lavet et nyt projekt er det første skridt at navngive vores komponent til noget som giver mening, og ikke bare UserControl1. I dette tilfælde navngiver vi den "ProgressBar".



Bemærk at når vi navngiver vores nye kontrol skal vi ændre navnet tre steder (de røde pile) både på selve filnavnet, klasse navnet samt constructoren. Den blå pil viser vores namespace, der i dette tilfælde er det samme som vores klassenavn. Den grønne pil viser at vores kontrol arver fra System.Windows.Forms.UserControl klassen. Det er nødvendigt, hvis vi skal bygge vores egen komponent.

Properties


Det er nu tid til at sætte properties på vores komponent. Vi skal bruge 4 properties, der henholdsvis symboliserer:

* Den første farve
* Den anden farve
* Teksten foran progressbaren
* procentsatsen der skal vises

Disse 4 properties laver vi private, således vi kan begrænse adgangen til den (hvis vi ønsker det) fra vores klasse.



For overskuelighedens skyld laver vi en #region til at skjule vores implementering af de enkelte properties. En #region er en speciel Visual Studio feature, der gør det muligt at opdele sin kode i visuelle elementer, der kan foldes ud og ind. Der er altså ingen funktionalitet forbundet med disse #region elementer.



For overskuelighedens skyld har jeg blot lavet en kommentar inde i min region, for at vise hvordan den virker. Bemærk at der er kommet et +/- tegn i venstre side (pilen) der viser at man kan folde denne #region sammen, meget praktisk. Selve implementeringen af koden kommer til at se således ud:

Fold kodeboks ind/udKode 

Bemærk at vores tekst foran selve progressbaren blot er en label. Der er ingen grund til at lave en propety på selve labelen, da det reelt kun er teksten vi er interesseret i at hente og sætte, derfor opererer vores "LabelText" property direkte på labelens Text property.

Constructoren initialiserer vores elementer


For at kunne komme videre er vi nødt til først at placere vores label på vores kontrol. Dette er nemt og hurtigt, da vi blot "Docker" den i venstre side. Samtidig laver vi lige en hvid baggrund. Alt dette sker i vores constructor.

Fold kodeboks ind/udKode 

som det ser ud på nuværende tidspunkt benytter vores komponent en enkelt graphics buffer, hvilket kan give lidt "flimren" i grafikken når man bruger denne komponent, dette løser vi hurtigt ved at slå dobbelt buffering til med denne kommando:

Fold kodeboks ind/udKode 



At tegne komponenten


Hvis vi deler vores tegnerutine lidt op, således vi kan koncentrere os om en ting ad gangen, vi deler derfor tegnerutinen op i følgende:

* Tegne vores sorte line rundt om vores progressbar (se eventuelt første billede)
* Tegne vores procentsats i selve progressbaren
* Tegne vores 3D bar

Alt det vi tegner laver vi i vores paint event. Marker selve komponenten og i højre side finder vi vores events, dobbeltklikker på "paint" og straks springer Visual Studio ind i koden der hvor selve implementeringen skal finde sted.
Det første vi skal gøre er at få fat i vores "Graphics" da det er den vi skal tegne på. Heldigvis tager "paint" eventen en PaintEventArgs parameter med ind i metoden, den kan vi udnytte.

Fold kodeboks ind/udKode 


Nu kan vi tilgå vores graphics og tegne vores sorte kasse. Det første vi skal finde ud af er hvor meget plads vi har at tegne på. Det vil sige at vi skal finde ud af hvor vores label stopper og hvor vi skal tegne.

Fold kodeboks ind/udKode 

Det første der sker er at vi får fat i vores Graphics fra vores PaintEventArgs. Dernæst opretter vi en ny Pen til at tegne med, den bliver sort og 1 pixel bred. Derefter kan vi tegne et rektangel. Det første parameter i "DrawRectangle" er vores pen. Den anden parameter er x koordinatet for øverste venstre hjørne, det falder sammen med højre side af vores tekstlabel. Den tredje parameter er y koordinatet for øverste venstre hjørne, det sætter vi til 1, da det er lige så bredt som vores Pen. Den fjerde parameter er bredden på det rektangel vi er ved at tegne, vi beregner bredden ved at trække vores labels bredde fra selve kontrollens bredde og fra dette resultat trække 1 mere fra (der skal jo være plads til at tegne en sort pixel linie i højre side også). Den sidste parameter er højden på den rektangel vi tegner, den beregner vi ved at trække 2 fra højden på kontrollen (da den skal 1 pixel ind på i toppen og i bunden).[p]
Næste projekt er at tegne selve vores procentsats midt i det rektangel vi netop har tegnet. Det vi lvil gøre er at skrive vores property "Percentile" da det således bliver den man setter og getter for at se hvor mange procent der er udført af en given opgave.

Fold kodeboks ind/udKode 

Vi skal have skrevet noget på vores Graphics, til dette formål skal vi først have lavet en brush, brushen laves sort og massiv (vi skal senere lave en anden type). Det er ingen sag at skrive teksten, vi laver først en Verdana font med størrelsen 8,25 (8.25f er engelsk notation med punktum i stedet for komma, og et f bagefter for at vise at det er en float). Derefter kalder vi metoden DrawString, der tager 5 parametre med ind. Den første parameter er selve den streng vil vil tegne, her benytter vi vores "Percentile" property og typecaster den til en streng. Den anden parameter er vores font. Den tredje paremeter er vores brush. Fjerde og femte parameter er henholdsvis x og y koordinatet for øverste venstre hjørne af den tekst vi tegner, for nemheds skyld tegner vi lige i midten 4 pixels nede i forhold til vores top.[p]
Næste projekt er at tegne selve vores progressbar. Her skal vi til at regne lidt, vi vil tegne et fyldt rektangel, men kun i forhold til den størrelse og den percentile vi har i vores kontrol.

Fold kodeboks ind/udKode 

Det første vi gør er at gemme størrelsen på det rektangel vi har at arbejde med. Derefter beregner vi en floating point værdi af bredden af den nye rektangel vi skal tegne. Så konner lidt "eye candy" hvis vores bredde af det rektangel vi skal tegne er lige med nul (altså hvis vi skal vise 0.4%) så runder vi op til 1, således brugeren kan se at der sker noget. Det samme gør vi hvis vores division giver en bredde der er større end selve bredden af vores arbejdsområde, så trækker vi 1 pixel fra vores rektangel, således man altid vil kunne se den sorte kant hele vejen rundt. Når vi har disse tal kan vi nemt beregne det rektangel vi skal tegne inden i vores sorte-streg rektangel. Vi laver også lidt "eye candy" der gør at hvis vores "percentile" er 100% (altså færdig) så maler vi vores indre rektangel grønt i stedet for blåt. Den sidste metode vi kalder er den der reelt tegner vores fyldte rektangel med en LinearGradient brush (den der laver 3D fornemmelsen).

Her er hele koden til tegnerutinen
Fold kodeboks ind/udKode 


Afslutning


Det sidste vi skal gøre før vi begynder at bruge vores komponent er at give den nogle properties og et ikon der kan bruges i vores toolbox i Visual Studio samt i vores property inspector. Over hver property tilføjes nu disse attributter:
Fold kodeboks ind/udKode 

Disse attributter fortæller til property editoren i højre side at Visual Studio hvad den skal vise af elementer for denne komponent. Dette er et eksempel på hvordan vores farver kan se ud med attributter:

Fold kodeboks ind/udKode 

Når vi har disse attributter på vil vi kunne redigere direkte i vores komponents properties fra vores property editor, da den vil reflektere disse attributter:



Det sidste vi skal gøre er at tilføje et ikon til denne komponent. Det er igen kun "eye candy", men det giver et indtryk af at denne komponent er lavet færdig. Start med at tilføje et nyt bitmap til denne solution



Tegn herefter et billede der passer til denne komponent.



Sørg for at dette billede kun er 16 x 16 pixels stort, med 16 farver



Dette billede skal compiles med i vores komponent, derfor skal "Build Action" sættes til "Embedded Resource"



Dette betyder at nu compiles vores bitmap med ind i vores .dll fil. Det eneste vi mangler er stort set kun at fortælle at vores ToolBox at den kan bruge denne komponent vi lige har bygget. Det gøres igen med attributter, denne gang på vores klasse:
Fold kodeboks ind/udKode 

Som det ses knytter vi i den anden attribut vores bitmap på vores komponent, første parameter er typen af denne klasse, det andet parameter er titlen på vores bitmap. Visual Studio sætter selv namespaceet foran navnet på billedet, det betyder at vi skal referere det med namespace.navn. Som det aller sidste skal vi tilføje vores element til vores toolbox. Højreklik på din toolbox og vælg "Add/remove items", derefter vælges "Browse" under .NET komponent fanen og der browses nu ind til den assembly vi netop har bygget. Når den er fundet vælges Open, og derefter OK. og vi kan nu se at vores komponent er klar i vores toolbox, og vi kan bruge den lige som alle de andre komponenter.



Sådan ser min progress bar ud når den kører (har skåret min tekst væk):




Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (5)

User
Bruger #479 @ 18.11.04 21:12
Endu en velskrevet artikel fra din side.
Når du er forfatteren til en artikel, er det nærmest en garanti for kvalitet :)
User
Bruger #2649 @ 30.11.04 14:27
Helt enig med Jesper.. Han sætter en ret høj standard for artikler.. Tror roligt man kan sige at Brian er den bedste til at skrive artikler/den har der skrevet flest.. 5 her fra.. Kanont stykke arbejde!
User
Bruger #846 @ 15.03.05 20:41
Da jeg skulle bruge LinearGradientBrush stødte jeg ind i et mindre problem. Da den ikke ligger i System.Drawing måtte jeg tilføje System.Drawing.Drawing2D til uses. Dette er ikke nævnt nogle steder i artiklen. Ellers helt perfekt artikel, rigtig, rigtig flot skrevet! :)
User
Bruger #5426 @ 16.05.05 11:42
Jeg synes artiklen så meget spændende, men jeg siddder med Visual C# 2005 betaen, og der er der ikke ikke en skabelon der hedder Windows Control Library, og derfor ved jeg ikke hvilken jeg ellers skal vælge :( Hvad kan jeg så gøre for at få det til at virke?
User
Bruger #10009 @ 06.06.06 12:35
God artikel, kunne være sjovt med et eksempel hvor man benytter den.
Du skal være logget ind for at skrive en kommentar.
t