Opdatering af UI via Extension Method

by Jesper marts 12, 2008 12:54

Jeg sad lige og så episode #105 på dnrTV, hvor emnet var: Hvordan Generics kan gøre din kode mindre, hurtigere og lettere at læse. Man lærer altid noget, ved at se hvordan andre bruger den teknologi, man selv bruger dag ud og dag ind. I episoden bliver der gjort stor brug af Extension Method, og jeg var lige ved at slukke, da jeg synes, jeg havde set nok om den nye feature i kompileren i DNF 3.5. Da var det emnet kom ind på opdatering af UI fra andre tråde. Her var der jo en, for mig, helt ny måde at bruge featuren på.

Jeg har i mit nuværende job ansvaret for en applikation, der fungerer som en service for en lang række industrimaskiner (Robotter). Disse maskiner rejser events i applikationen, og vi opdaterer UI med data fra disse events. Derfor har vi hundrede vis af linjer af kode, der ikke gør andet, end at checke for om den eksekverende tråd er UI-tråden, og i negativt fald; invoker en delegat der kan opdaterer UI:

[code=csharp] void tcc_Progress(object sender, EventArgs e) { TimeConsumingCalculations tcc = sender as TimeConsumingCalculations; // Check om det er en anden tråd der eksekverer if (this.InvokeRequired) { // Invoke på UI tråden med delegaten this.BeginInvoke( new UpdateTextBoxDelegate(UpdateTextBox), textBox1, tcc.CurrentValue); } else { // Vi er i i UI tråden UpdateTextBox(textBox1, tcc.CurrentValue); } } // Nødvendig erklæring af delegat, for at kunne kalde Invoke delegate void UpdateTextBoxDelegate(TextBox tb, string value); // Metode der udfører opdateringen void UpdateTextBox(TextBox tb, string value) { tb.Text = calculator.CurrentValue; } [/code]

Jeg synes selv at denne form for kode er triviel, (og det er en af de eneste ting jeg misunder VB.NET for). Der er alle mulige ting der kan gå galt, og koden er umulig at læse og forstå – alt dette for at opdaterer et UI…

Nu blev jeg gjort opmærksom på en pænere måde at udføre dette check på, af udviklerne på Advosol – de har en lidt mere kompakt måde at klare problemet på:

[code=csharp] void tcc_Progress(object sender, EventArgs e) { TimeConsumingCalculations tcc = sender as TimeConsumingCalculations; if (this.InvokeRequired) { this.BeginInvoke( new EventHandler(tcc_Progress), sender, e); return; } textBox1.Text = tcc.CurrentValue; } [/code]

Her udnytter man, at metoden altid har en delegat-erklæring, ellers kunne den jo ikke være eventhandler, og kalder Invoke rekursivt på metoden. Det fjernede behovet for en lang række delegat-erklæringer og opdateringsmetoder. Koden blev mindre og lettere at læse.

Nu fik jeg så øjnene op for Extension Method, og kan nu gøre koden endnu mere strømlinet. Jeg tager blot ovenstående trick og putter det i en Extension på selve Form objektet:

[code=cshrap] static class FormExtensions { public static void UpdateTextBox( this Form form, TextBox textBox, string value) { if (form.InvokeRequired) { form.BeginInvoke( new Action(form.UpdateTextBox), textBox, value); } else { textBox.Text = value; } } } [/code]

..og kalder nu min nye metode på formen:

[code=csharp] void tcc_Progress(object sender, EventArgs e) { TimeConsumingCalculations tcc = sender as TimeConsumingCalculations; this.UpdateTextBox(textBox1, tcc.CurrentValue); } [/code]

Med et slag fik vi reduceret delegat metoden til en linje. Denne ene feature, har reduceret vores kode med over 2000 linjer. Jeg ved godt at CLR koden ikke har forandret sig, og at applikationen ikke er blevet mere effektiv, men koden er da blevet meget lettere at læse og vedligeholde. Det var en god refactoring.

Hvad er så ulempen ved Extension Method featuren? Man kan jo forledes til at kode løs, og lave metoder til alt. Ja faktisk, kan man typisk fjerne alle sine hjælpe klasser med denne feature, og jeg har da også selv gjort det nogle gange – f.eks. min ToJson extension. I blogssfæren bliver der også gjort forsøg med featuren – se f.eks. Deldy og Daniel. Problemet er det faktum, at man ikke har styr på den kode man laver tilføjelser til. Her har jeg lavet en tilføjelse til System.Windows.Forms.Form objektet, og jeg synes selv at min koder er blevet 100 gange pænere, men jeg har måske skabt mig selv problemer i fremtiden. Hvad nu hvis DNF 4.0 har udvidet Form med en metode der kaldes UpdateTextBox? Og hvad nu hvis den metode har samme form som min extension, men bare udfører noget helt andet funktionalitet? Så har jeg et stort problem med min kode. Den kan i værste fald være fuldstændig ubrugelig. Så uanset hvor fed den feature er, så skal man bruge den med omtanke, og sørge for at begrænse brugen. Min ToJson metode, er en udvidelse til Object – det vil sige at jeg får problemer hvis bare én af klasserne i DNF implementerer en metode med det navn.

Carry on implementing…

Kommentarer

12-03-2008 13:04:15 #

Signe

For at undgå det potentielle sammenfald med fremtidige opdateringer, kunne du jo blot give dine extensions navne der med garanti ikke vil blive brugt:
object.ICoderToJson()

Signe Denmark

12-03-2008 13:40:45 #

IMan

Det var selvfølgelig en måde at klare problemet på.
Jeg er bare ikke sikker på om jeg ikke bedre kan lide at lave en statisk hjælpe-klasse med metoden, uden Extension. Så er man sikker på at der ikke kommer sammenfald.
Jeg overvejer stadig Smile

IMan Denmark

13-03-2008 03:48:50 #

Daniel

Hej Jesper.
Rigtig god post synes jeg, men pas nu paa du ikke overdriver. Det er sandt nok at MS kan tilfoeje nye metoder med samme navn, men hvor mange gange er du rendt ind i det, i din karrier :0)

Keep it up, vi ses i kolding forresten!

/Daniel

Daniel Denmark

13-03-2008 10:32:37 #

IMan

Nej risikoen er nok ikke så stor, og man kan jo, som Signe nævner, bruge sit eget navn i navngivningen. Jeg har bare en dårlig smag i munden, når det kommer til extension metoder. Det har måske noget med design at gøre, og ligger nok lidt på linie med hvad Kodehovedet skrev i sin post om Hjælpeklasser: http://kodehoved.dk/?p=73 - Det er måske et udtryk for at man ikke har designet ordentligt.
Måske skal man bare give f... i de overvejelser, og bare bruge den nye feature vi har fået foræret Smile
NB: i det nye ctp af MVC frameworket, er der kommet en metode på ViewData objektet, som hedder: ToJson ta-dah!

IMan Denmark

13-03-2008 13:03:21 #

Signe

--> Jesper om ToJson metoden.
Hvad sagde jeg?
Hvis du havde kaldt den ICoderToJson, havde du haft fri i dag :-D

Signe Denmark

10-07-2009 09:18:56 #

trackback

InvokeRequired i WPF

InvokeRequired i WPF

ICoder

Kommentarerne er lukkede

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen | Modified by Mooglegiant

About

Mit navn er Jesper Jensen, og jeg arbejder til dagligt som web-udvikler hos DGI, hvor mit speciale er klientside applikationer. Før det var jeg nogle år i robotbranchen, hvor jeg arbejdede med 3D simulering og system koordinering. Jeg elsker webudvikling, og specielt JavaScript har min interesse. Jeg har blogget om mine oplevelser med udvikling siden 2004

Calendar

<<  september 2010  >>
mationtofr
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

RecentComments

Comment RSS