EventMaker

Idea: At repetere MVVM-arkitekturen fra 1 semester - Par-Programmering!
Background: Pensum fra 1. semester

I denne opgave arbejdes der med Par-Programmering.
Dvs 2 personer sidder ved samme maskine og skiftes ca (hver 20 min) til at sidde ved tastaturet. Der diskuteres hele tiden hvad der skal laves, hvordan det skal laves og hvad der sker i koden linie for linie.

I denne opgave skal der arbejdes med vores kerne-arkitektur til windows 10 App.
Der skal laves et simpelt Event-management system til administration af Events. Systemet skal baseres på MVVM arkitekturen og der skal benyttes klasser til Handler, Persistens, Dato/Tid-konvertering og RelayCommand, se klassediagram:

 

I de efterfølgende opgaver 1-5 bliver du guidet igennem en implementering af diagrammet.

Opgave 1
a) Opret et nyt Windows 10 App projekt (Blank App Universal Windows) : EventMaker

b) Slet MainPage.xaml

c) Add følgende mapper til projektet: View, ViewModel, Model, Persistency, Handler, Converter og Common

d) I View oprettes en ny Blank Page: EventPage.xaml

e) I Model oprettes en ny class Event (int Id, string Name, string Description, string Place, DateTime DateTime) med konstruktor og ToString metoder

Opgave 2
f) I Model oprettes en ny class EventCatalogSingleton - en singleton med en ObservableCollection af Events (lad konstruktor initialisere collection med et par Events - Hvorfor? - Diskuter!) og en Add-metode der kan addere en Event til collectionen.

Hint:
En singleton skal have en private konstruktør (Hvorfor private? - Diskuter!).
En singleton skal have et static instansfield _instance (backing field) og en static get-property (Hvorfor skal Instance-property være static? og Hvorfor må der ikke være en set-property? - Diskuter!)
Brug lazy initialisering (dvs _instance initialiseret til null og get opretter en ny instans når den kaldes 1. gang - benyt: ??-operatoren) (Hvad er forskellen mellem eager og lazy? - Diskuter!)

g) I ViewModel oprettes en class EventViewModel med en property der refererer til: EventCatalogSingleton

Hint:
Der skal være en default konstruktør til en ViewModel klasse (Hvorfor ? - Diskuter)
Konstruktøren skal initialisere propertyen med en instance af EventCatalogSingleton (Hvordan, Hvorfor? - Diskuter!)

Opgave 3
h) I EventPage tilføjes EventViewModel som DataContext, der tilføjes et ListView der bindes (itemsource) til Events fra EventCatalogSingleton via EventViewModel.
Der oprettes en DataTemplate til at "style" visningen af de enkelte Event-items (brug evt. Blend)

Hint:
Test at bindingen til Events virker før der oprettes en DataTemplate (Har i husket ToString( ) metoden i class Event? - Hvis der ikke er en ToString( ) hvad indeholder ListView da? - Diskuter!)
Blend: Højre klik på ListView controllen vælg: Edit Additional Templates -> Edit Generated Items -> Create Empty navngiv DataTemplaten fx EventDataTemplate
DataTemplaten kan fx bestå af en StackPanel med 4 TexBlock der bindes til de enkelte properties i class Event
- (Hint: Husk i starten at benytte Auto width og Auto Height under layout af de enkelte controls)




i) I View oprettes en ny Blank Page: CreateEventPage, med TextBlock/TextBox til Event-data (Id, Name, Description, Place, Date, Time).

Hint: Benyt DatePicker eller CalenderDatePicker og TimePicker controls til Dato og Tid.


j) EventViewModel udvides med følgende properties:

og der bindes til disse fra CreateEventPage.

Konstruktøren EventViewModel() opdateres så Date og Time initialiseres:

DateTime dt = System.DateTime.Now;

_date = new DateTimeOffset(dt.Year, dt.Month, dt.Day, dt.Hour, dt,Minute, 0, 0, new TimeSpan());
_time = new TimeSpan(dt.Hour, dt.Minute, dt.Second);


k) EventPage opdateres med en AppBarButton så der kan navigeres til CreateEventPage

Hint: I Blend kan pagenavigation tilføjes ved at lægge en NavigateToPageAction Behavior på AppBarButton med TargetPage sat til CreateEventPage (Bemærk: Behaviors skal først installeres, klik på NuGet-linket) - Test at det virker.

l) I Converter oprettes en ny class DateTimeConverter med metoden:

public static DateTime DateTimeOffsetAndTimeSetToDateTime(DateTimeOffset date, TimeSpan time)
{ return new DateTime(date.Year, date.Month, date.Day, time.Hours, time.Minutes, 0); }

Diskuter: Hvad gør metoden DateTimeOffsetAndTimeSetToDateTime(....), hvad skal den benyttes til?


m) I Handler oprettes en class EventHandler, klassen skal have en reference til EventViewModel og en konstruktør der kan initialisere referencen samt en metode CreateEvent der kan oprette et nyt Event via Properties i EventViewModel og addes til Events i EventCatalogSingleton (benyt metoden DateTimeOffsetAndTimeSetToDateTime til at konvertere Date og Time til et objekt af typen DateTime)

Hint: Oplever du problemer med navnet EventHandler? Ja - Diskuter hvad der er problemet!

Hint Hint: GUI i C# er event-baseret, derfor finder der naturligvis system klasser der hedder System.Event og System.EventHandler. Når du laver klasser med samme navn er der navnesammenfald og du skal give fuldt navn for at adressere din nye klasse dvs: Handler.EventHandler :)

 

n) EventViewModel opdateres med en property EventHandler af typen Handler.EventHandler og en property CreateEventCommand af typen ICommand. Opdater konstruktøren til EventViewModel EventHandler propertyen initialiseres med et nyt EventHandler objekt og CreateEventCommand propertyen initialiseres med et RelayCommand objekt, hvis action skal referere til metoden CreateEvent i EventHandler.

Hint: Du kan evt se klassen RelayCommand: Her (Download: RelayCommand.zip). Klassen placeres i mappen Common (du kan også tilføje RelayCommand ved at højre klikke på mappen Common og vælge Add->Existing Item og via stifinder vælge RelayCommand.cs fra et tidligere projekt. (Husk at opdatere namespace).
Da konstruktøren til EventHandler skal have vores EventViewModel som parameter, kaldes konstruktøren med this som argument.


o) CreateEventPage opdateres med 2 AppBarButton's en Add med en binding til CreateEventCommand så der kan oprettes nye Events og en Return der navigere tilbage til EventPage.
Hint: AppBarButton har under Common en property: Command - den skal bindes til CreateEventCommand.

Test :)

Opgave 4
p) I Persistency oprettes en ny class PersistencyService med metoderne:

Se evt.: WindowsAppSerializeTestV2.zip

Hint: Diskuter - hvorfor skal metoderne være af typen async og hvorfor returneres noget af typen Task?

q) EventCatalogSingleton opdateres så den benytter PersistencyService til at hente og gemme Event objekter

Hint: I EventCatalogSingleton oprettes en ny async metode: LoadEventsAsync( ), der kalder PersistencyService.LoadEventsFromJsonAsync( ) og som gennemløber resultatet og addere de hentede events til den ObservableCollection: Events. Add metoden i EventCatalogSingleton opdateres så den gemmer events via.: PersistencyService.SaveEventsAsJsonAsync(Events);

 

Opgave 5
r) Opdater EventCatalogSingleton med en Remove-metode der kan slette en Event fra collectionen (og opdatere filen).

s) Opdater EventHandler med en DeleteEvent-metode der kan kalde Remove-metoden fra EventCatalogSingleton (bemærk, der skal senere opdateres i EventViewModel med en static property SelectedEvent - så der kan refereres til den Event der skal slettes)

t) Opdater EventViewModel med følgende property: SelectedEvent og opdater EventHandler med metoden SetSelectedEvent der kan sette SelectedEvent i EventViewModel med en selectet Event. Opdater EventViewModel med en property: SelectedEventCommand ala

private ICommand _selectEventCommand;
public ICommand SelectEventCommand
{
get { return _selectEventCommand ?? (_selectEventCommand = new RelayArgCommand<Event>(ev => EventHandler.SetSelectedEvent(ev))); }
set { _selectEventCommand = value; }
}

(Download: RelayArgCommand.zip )

Der skal laves følgende binding i EventPage:

<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="SelectionChanged">
<Core:InvokeCommandAction Command="{Binding SelectEventCommand}" CommandParameter="{Binding SelectedItem, ElementName=listView}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>

Hint: I Blend "droppes" en Behavior af typen InvokeCommandAction på listview'et og Command-propertyen på InvokeCommandAction data-bindes til SelectEventCommand, og CommandParameter data-bindes til SelectedItem på listview'et (husk, det er Element name og ikke Datacontext).


u) Opdater EventViewModel med følgende property DeleteEventCommand

private ICommand _deleteEventCommand;
public ICommand DeleteEventCommand
{
get {return _deleteEventCommand ?? (_deleteEventCommand = new RelayCommand(EventHandler.DeleteEvent));}
set { _deleteEventCommand = value; }
}

 

v) Opdater EventPage med en AppBarButton til at slette en selected Event og lav en binding til DeleteEventCommand

 

Opgave 6
w) Lav dit eget DCD over dine klasser i EventMaker