C# DataBinding del 3 – forretningsobjekter

Skrevet - Sunday, January 6th, 2008 kl. 21:26 | Kategori - * Kodning

Forretningsobjekter i den her sammenhæng er dem man også kalder Custom Business Objects eller Business Entities. Objekter, som har en forretningsmæssig sammenhæng – for vores Booking/Disponeringsapplikation er det typisk noget med nogle adresser, noget gods og nogle kunder. I forbindelse med DataBinding er forretningsobjekter noget sværere at have at gøre med i forhold til direkte kobling til en databasetabel.

Tag for eksempel følgende scenarie: En kunde har en række bookinger – hver booking har kun en kunde. Dvs. i en database var det en en-til mange relation. Forestil dig nu, at vi i en tabel vil vise en booking repræsenteret som en række i et DataGridView. For dem, der ikke lige har tid til at teste efter, kan jeg afsløre at den celle, der indeholder kunde-objektet blot vil skrive den absolutte objekt-type. Det er ikke særlig hensigtsmæssigt, men heldigvis nemt at rette op på. Den hurtige løsning er at override .ToString() på kundeobjektet, så den returnerer en noget mere sigende tekst (Fx kundens navn). Alternativt kan DataGridView’ets Format-event anvendes til at vise en helt fri tekst – og du kan have forskellige repræsentationer forskellige steder i applikationen. For eksempel kunne det være en fordel at regnskabsafdelingen får serveret kontonummeret for kunden, mens disponeringsafdelingen gerne vil have kundens navn efterfulgt af kontaktpersonen.

Næste problem er når en bruger, så vil rette kunden i DataGridViewet… uden undtagelse vil man få en grim exception kastet i hovedet. Problemet er at DataGridView’et arbejder med String-objekter og kunden er ikke et String-objekt. Der er en række muligheder for at fange dette. Den ene er at anvende Parse-eventet for DataGridView’et, hvor man manuelt konverterer indtastnings-String’en til det kunde-objekt, der passer til (Fx vha. databaseopslag osv.) Alternativt kan man Lave en ITypeConverter til kunde-objektet, som i princippet gør det samme, men kan anvendes til en række andre formål, samtidig med at det kun skal laves en gang.

Man kan også kombinere mulighederne, hvis man har et scenarie, hvor man 90% af tiden vil gøre det på en måde og de sidste 10% er special-tilfælde, hvor man så laver en ITypeConverter/.ToString() til at håndtere de 90% og så anvender Parse/Format eventet til de sidste 10%. Det er en elegant måde at klare problematikken med mindst mulig kode og samtidig have ekstrem fleksibilitet til forskellige bruger-roller.

Derudover har forretningsobjekter som udgangspunkt slet ingen af de dejlige interfaces implementeret. Når de skal vises i en liste, har man dog mulighed for at bruge Generics til at lave en liste, hvor der kan databindes til de enkelte properties. BindingList<T> er klart at foretrække (navnet siger det ligesom), når du arbejder i præsentationslaget. Den mangler dog et par ting – filterering, sortering og søgning. Ikke uvæsentlige ting, så i stedet for at skulle lave alle disse ting manuelt, er det klart en fordel at lave sin egen klasse til det, hvor man så arver fra BindingList og implementerer interfacet IBindingListView, som DataGridViews automatisk lytter på.

Hvis man kan leve med andres arbejde, kan jeg klart anbefale BLW på SourceForge. Der mangler .Filter via en SQL-streng, men den kan man så udvide med selv eller anvende den noget stærkere .Filter() de har implementeret. Derudover har jeg lavet en udvidelse af DataGridViewet, hvor jeg via XML styrer hvilke properties fra objektet, der skal vises… og i hvilken rækkefølge. For det første kan jeg opsætte kolonner osv. automatisk, når bare jeg har en Type med (Generics/System.Reflection er nu en fantastisk ting!) – og ham der laver UI skal ikke bekymre sig om opsætningen og jeg får et ensartet udseende hele vejen igennem applikationen. Det giver mig mulighed for at brugeren kan gemme sin egen opsætning. Samtidig har jeg samlet alt koden i det nye Grid, så jeg har det samme sted.

Når man først har fået lavet sin egen dejlige version af DataGridViewet samt en IBindingListView-implementation på en List<T>, er man rimelig langt. Så kan man begynde at bekymre sig om Interfaces… som del 4 er om.

Feed | Trackback |

2 Comments
  1. nckjox said,

    September 11, 2008 at 11:54

    Hvorfor bruger du List i stedet for at bruge BindingList? Med BindingList får man ICancelAddNew og IRaiseItemChangedEvents med i købet. Derudover håndterer BindingList CurrencyManager. På sin BindingList kan man implementere IBindingListView.

  2. GoblinHero said,

    September 22, 2008 at 8:58

    Det kommer an på min løsning – hvis jeg laver meget behind-the-scenes arbejde på listen, har jeg ikke lyst til at bruge BindingList, fordi den er for tung i implementeringen. Det er korrekt, at hvis den eneste funktionalitet jeg har brug for er i UI – så er BindingList (med BindingListView implementeret) klart at foretrække.

    Iøvrigt – hvis du bruger .Net 3.5, så kan ObservableList løse begge problemer – den kan tage en List som constructor-parameter, så den bliver ‘pakket ind’ i INotifyCollectionChanged som har nogenlunde samme funktionalitet som IBindingListView.

Post a Comment