2 Comments

Upravo sam potrošio 4 sata na traženje buga u jednoj Silverlight aplikaciji koju trenutno radim. Pošto sam na kraju ipak uspio pronaći u kojem zecu leži grm, i kako sam siguran da će netko osim mene doći do istog problema jer se radi o često korištenom obrascu ravzijanja, bilo bi dobro podjeliti ovaj mali tips&tricks koji može spasiti par sati uzaludnog traženja internetom (koje mene nije dovelo do rješenja ipak).

Bug izgleda ovako:

ovo je jedna kontrola u razvoju, i njezin zadatak je da ispisuje njezin status, dali je minimizirana i maksimizirana. To ispisuje ListBoxu, koji radi na sljedeći načim:

- na UserControl je postavljena DataContext klasa (MVVM pattern)
- ta ViewModel klasa ima jednu listu stringova definiranu kao ObservableCollection<string> property
- pomoći Binding sposobnosti, ažurirane vrijednosti u tom propertyu se automatski osvježavaju u ListBoxu, odnosno ispisuje lista tih stringova.
Primjer XAML deklaracije ListBoxa:


    
        
            
        
    


Bug je desi kada dodate više od 3-4 stringova u listu, i pokušate selektirati jednog, u ListBoxu će ostati selektirani, ili nasumično se selektirati više stavaka, kao što je prikazano u screenshotu (ListBox nema omogućeno selektiranje više od jedne stavke).. [more]
Ono što je zanimljivo, bug se ne pojavljuje ako NE koristite binding, nego napravite običnu List<string> i pridodjelite ju ItemsSource propertyu od ListBox-a!
Razlog ovoj pojavi mi je i dalje ostao nepoznat, pa ga mogu pripisati jedino mamurnom programeru u Microsoftovom razvojmom timu, nedostatku unit testiva, ili zbog urote Adobe/Apple inflitriranih agenata u Microsoftovim redovima. Ja bi se kladio na ovo zadnje.

Rješenje je jednostavno: na ListBox se mora bindati objekt, a ne string! Ha! Jednostavno rješenje, zar ne? A koje sve solucije sam pronašao na internetu, to je strašno, hackove koje ulaze u tamne dubine Silverlighta, gdje još programerova ruka nije kročila.
Naša ViewModel klasa sada nema property ObservableCollection<string>, nego ObservableCollection<StateItem>, gdje je StateItem klasa koja ima jedan string property StateName.


    
        
            
        
    

2 Comments

Tuple je struktura podataka možda nepoznata dijelu .NET programerske publike, ali je svakako važan dio matematičke teorije i teorije struktura podataka. Pitajte Donalda Knutha ako mi ne vjerujete! Naime, radi se o nepromjenjivoj (immutable) listi elemenata enkapsuliranih u objekt. Tuple tip podataka je dosta korišten u Pythonu, dolazi sa .NET Frameworkom 4, ali u .NET 2/3.5 se moramo sami pobrinuti napraviti ga, što je vrlo jednostavan posao.

O čemu se tu radi uopće; sjetite se TryParse metode objekta Int32:

int value=0;
bool pretvorba = Int32.TryParse(“7”, out value);
// moglo bi se pisati i ovako:
// [bool] [int] = Int32.TryParse(“7”)

TryParse vraća dva podataka, bool vrijednost koja govori dali je string uspješno parsiran, i int vrijednost parsiranog stringa. Ovo je primjer gdje se može iskoristiti Tuple, pošto s njime možemo vratiti više enkapsuliranih objekata:

Tuple<bool,int> result = Int32.TryParse(“7”); 
Assert.AreEqual(true, result.Item1); 
Assert.AreEqual(7, result.Item2);

kao se može vidjeti iz primjera, kreirali smo Tuple koji sadrži bool i int objekte, i preko propertya Item1 i Item2 im pristupamo.  Ovakvih primjera vjerojatno ima još mnogo, a meni osobno se je prvo palo na pamet kao zamjena za mnoge DTO (data transfer objects) koje moram pisati za MVC aplikaciju kada šaljem podatke iz controllera u view. Ako sam do sada morao kreirati klasu koja enkapsulira List<Articles> i string Title, sada mogu preskočiti izradu klase i samo poslati Tuple<List<Article>,string).

Glavni nedostatak ovakvog pristupa upotrebe kao DTO objekta je što se apsolutno ne zna što taj Tuple sadrži, osim tipa podatka. Prije sam imenovao varijable u DTO klasi prema opisu njihove uloge u domeni, a sada samo znam da imam tri stringa, dva integera i slično, koje pozivam preko propertya Item1, Item2, itd. Čista programerska ljenost! Stoga koliko god njegova upotreba zvuči pimamljivo, i skrati par (desetaka) minuta posla, kod imalo većih projekata može zadati glavobolje i prouzrokovati brojne bugove. Upozoreni ste!
Slijedi jednostavna implementacija Tuplea za .NET Framework 2/3.5: [more]

public class Tuple<T1> 
{ 
    public Tuple(T1 item1) 
    { 
        Item1 = item1; 
    } 

    public T1 Item1 { get; set; } 
} 

public class Tuple<T1, T2> : Tuple<T1> 
{ 
    public Tuple(T1 item1, T2 item2) 
        : base(item1) 
    { 
        Item2 = item2; 
    } 

    public T2 Item2 { get; set; } 
} 

public class Tuple<T1, T2, T3> : Tuple<T1, T2> 
{ 
    public Tuple(T1 item1, T2 item2, T3 item3) 
        : base(item1, item2) 
    { 
        Item3 = item3; 
    } 

    public T3 Item3 { get; set; } 
} 

public static class Tuple 
{ 
    public static Tuple<T1> Create<T1>(T1 item1) 
    { 
        return new Tuple<T1>(item1); 
    } 

    public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) 
    { 
        return new Tuple<T1, T2>(item1, item2); 
    } 

    public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) 
    { 
        return new Tuple<T1, T2, T3>(item1, item2, item3); 
    } 
}

i par primjera upotrebe:

Tuple<int> t1=Tuple.Create(7);
Tuple<string,int,List<Product>> t2=Tuple.Create("Naslov", repository.Count(),repository.Products);