Download presentation
Presentation is loading. Please wait.
1
Arkitektur, klasser og ansvar
MVVM Starter Arkitektur, klasser og ansvar
2
Arkitektur
3
App View View Model Validators Controllers Filters Model
4
View XAML Bruger-interaktion Bindings Kontakt til ViewModel
Ingen kontakt til Model MVVMStarter: skabelon til Master/Details view Studerende: Et view for hver domæne-klasse View
5
View Model C# Udstiller properties som Views kan binde til
Transformationer fra domæne- objekter til ViewModel-objekter Kontakt til Model MVVMStarter: Base-klasser Studerende: ~5 (små) klasser per domæne-klasse View Model
6
Model C# Singleton-adgang til collection af domæne-objekter
Kontakt til source for objekter MVVMStarter: Base-klasser Studerende: To (små) klasser per domæne-klasse Model
7
App C# Overordnet navigation Konfiguration Fil-persistens
MVVMStarter: Veldefinerede entry-points for nye domæne- klasser Studerende: <5 (små) tilføjelser ved entry-points App
8
Validators Validering på property-niveau int: interval
string: længde, indeholder MVVMStarter: statiske metoder for generisk validering, præsen- tation med undo-funktion Studerende: Afhængig af krav til validering Validators
9
Controllers Controllers out-of-the-box for CRUD-operationer
Aktiveres via Commands Meget små (<5 linjer C#) MVVMStarter: Controllers kan tilføjes/overrides Studerende: Afhængig af krav til forretningslogik Controllers
10
Filters Muligt at addere et antal filtre til et Catalog.
Filter: domæne-objekt -> bool Filtre kan programmatisk slås til og fra MVVMStarter: Generiske Filter og FilterManager klasser Studerende: Afhængig af krav til forretningslogik Filters
11
Model
12
Properties af simple typer (int, string,…) Kan tilføjes validering
Egen domæne-klasse Properties af simple typer (int, string,…) Kan tilføjes validering Car
13
Car public class Car { public string LicensePlate { get; set; }
// …etc }
14
Car : DomainClassBase public class Car : DomainClassBase {
public string LicensePlate { get; set; } // …etc public override void SetDefaultValues() LicensePlate = "(not set)"; } Car : DomainClassBase
15
DomainClassBase public abstract class DomainClassBase {
public int Key {…} protected DomainClassBase() SetDefaultValues(); } public abstract void SetDefaultValues(); public virtual DomainClassBase Clone() return (DomainClassBase)MemberwiseClone(); DomainClassBase
16
Rummer en collection af domæne-objekter Fil-baseret persistens (JSON)
Load- og Save-metoder Metoder for operationer på collection (Insert, Delete, …) Catalog CollectionBase<Car> Car FileSourceBase<Car> CarModel.dat
17
CollectionBase<Car> Car
Catalog CollectionBase<Car> Car public class Catalog : CatalogBase<Car> { // Generic singleton code private Catalog() : base(new CollectionBase<Car>(), new FileSourceBase<Car>()) } FileSourceBase<Car> CarModel.dat
18
CollectionBase<TDomainClass>
public class CollectionBase<TDomainClass> { private Dictionary<int, TDomainClass> _collection; public List<TDomainClass> All {…} public void Insert(TDomainClass obj) {…} public bool Delete(int key) {…} public void DeleteAll() {…} // plus key management } Dictionary<int, TDomainClass>
19
FileSourceBase<TDomainClass>
public class FileSourceBase<TDomainClass> : SourceBase<TDomainClass> { public CollectionBase<TDomainClass> Load() {…} public void Save(CollectionBase<TDomainClass> coll) } CarModel.dat (JSON)
20
CatalogBase<TDomainClass>
CollectionBase<TDomainClass> public class CatalogBase<TDomainClass> { public List<TDomainClass> All {…} public void Insert(TDomainClass obj) {…} public bool Delete(int key) {…} public void DeleteAll() {…} public bool Modified {…} public void Load() {…} public void Save() {…} } FileSourceBase<TDomainClass>
21
ViewModel
22
View Location Berlin AX In EU now Yes Create Update Delete Read
23
<Grid> <StackPanel> <StackPanel> <StackPanel>
<Image> <TextBlock> <TextBlock> <TextBox> <StackPanel> <Button> <StackPanel> <RadioButton>
24
MasterDetails ViewModel Master ViewModel Details ViewModel Item ViewModel Commands (actions) Commands (states)
25
MasterDetails ViewModel Master ViewModel Details ViewModel Item ViewModel Catalog CollectionBase<Car> Car
26
Item ViewModel Details ViewModel ItemPropertyA ItemPropertyB ItemPropertyC DetailsPropertyA DetailsPropertyB DetailsPropertyC Car Car
27
Collection<ItemViewModel>
Master ViewModel ItemViewModel CreateItemViewModel(Car obj) Catalog CollectionBase<Car> Car
28
CatalogBase<Car>
MasterDetails ViewModel ViewModel Factory Master ViewModel Item ViewModel Details ViewModel Create() Create(Car obj) Create(Car obj) CatalogBase<Car> CollectionBase<Car> obj Car
29
ItemViewModelCollection ItemViewModelSelected ItemSelectorEnabled
<Page> DataContext = MasterDetailsViewModel <Grid> MasterDetails ViewModel <ListView> ItemViewModelCollection ItemViewModelSelected ItemSelectorEnabled ItemSelectorVisible <StackPanel> DetailsViewModelSelected ViewControlStates
30
View MasterDetails ViewModel Master Details CreateCommand UpdateCommand DeleteCommand Commands (actions) ViewControlStates SelectCreateCommand SelectReadCommand SelectUpdateCommand SelectDeleteCommand Commands (state)
31
Objekt vil referere til et enkelt domæne-objekt
ItemViewModelBase<Car> Definition af, hvorledes et domæne-objekt præsenterer sig i en liste-orienteret GUI kontrol (f.eks. ListView) Objekt vil referere til et enkelt domæne-objekt Et antal virtuelle properties kan overrides Item ViewModel FontSize ImageIsVisible ImageSize Car Description ImageSource
32
ItemViewModelBase<Car>
<StackPanel> Item ViewModel <Image> <TextBlock> FontSize ImageIsVisible ImageSize public override int FontSize { get { return 24; } } public override string ImageSource get { return DomainObject.PhotoSource; } public ItemViewModel(Car obj) DomainObject = obj; Car Description ImageSource
33
ItemViewModelBase<Car>
<StackPanel> Item ViewModel <Image> <TextBlock> FontSize ImageIsVisible ImageSize <ListView.ItemTemplate> <DataTemplate DataType="ItemViewModel"> <StackPanel Orientation="Horizontal"> <Image Source="{Binding ImageSource}" Visibility="{Binding ImageVisibility}" Width="{Binding ImageSize}" Height="{Binding ImageSize}" /> <TextBlock Text="{Binding Description}" FontSize="{Binding FontSize} /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> Car Description ImageSource
34
Objekt vil referere til et enkelt domæne-objekt
DetailsViewModelBase<Car> Definition af, hvorledes data fra et domæne-objekt skal præsenteres i et Details-view Objekt vil referere til et enkelt domæne-objekt Simple properties: en-til-en mapping til properties på domæne-objekt (get/set) Aggregerede (beregnede) properties: Kun get Details ViewModel Car Location SimplePropB SimplePropC InEU AggrPropB Location SimplePropB SimplePropC
35
DetailsViewModelBase<Car> Location
In EU now Details ViewModel Car public string Location { get { return DomainObject.Location; } set DomainObject.Location = value; OnPropertyChanged(); } public string InEU get { return DomainObject.InEU(DomainObject.Location); } // …etc public DetailsViewModel(Car obj) DomainObject = obj; Location SimplePropB SimplePropC InEU AggrPropB Location SimplePropB SimplePropC
36
DetailsViewModelBase<Car> Location {Binding …}
In EU now Details ViewModel Car <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding …}"/> <TextBox IsEnabled="{Binding …}” Visibility="{Binding …}" Text="{Binding DetailsViewModel.Location, Mode=TwoWay}" /> </StackPanel> Text="{Binding DetailsViewModel.InEU, Mode=OneWay}" /> Location SimplePropB SimplePropC InEU AggrPropB Location SimplePropB SimplePropC
37
Transformation af en collection af domæne- objekter til en collection af ItemViewModel-objekter
Transformation af det enkelte domæne-objekt er defineret i ItemViewModel MasterViewModelBase<Car> Master ViewModel
38
MasterViewModelBase<Car>
public class MasterViewModel() : MasterViewModelBase<Car> { } Master ViewModel public virtual List<ItemViewModel> CreateItemVMCollection( CatalogBase<Car> catalog, ViewModelFactoryBase<Car> factory) { _itemViewModelCollection.Clear(); foreach (Car obj in catalog.All) _itemViewModelCollection.Add(factory.CreateItemVM(obj)); } return _itemViewModelCollection;
39
ListView MasterDetails ViewModel Master ViewModel ItemVMC
public List<ItemViewModel> ItemViewModelCollection { get return _masterVM.CreateItemVMCollection( _catalog, _viewModelFactory); } ViewModel Factory ItemVMC Master ViewModel Catalog Car CreateItemVMC(catalog, factory) public virtual List<ItemViewModel> CreateItemVMCollection( CatalogBase<Car> catalog, ViewModelFactoryBase<Car> factory) { _itemViewModelCollection.Clear(); foreach (Car obj in catalog.All) _itemViewModelCollection.Add(factory.CreateItemVM(obj)); } return _itemViewModelCollection; List<ItemViewModel> List<ItemViewModel>
40
Holder sammen på alle ViewModel-objekter
MasterDetails ViewModel Holder sammen på alle ViewModel-objekter Udstiller properties, som View kan binde sig til Bliver DataContext for View
41
MasterDetails ViewModel
public class MasterDetailsViewModel() : MasterDetailsViewModelBase<Car> { public MasterDetailsViewModel() : base(new ViewModelFactory(), Models.Domain.Car.Catalog.Instance) StateManager.AddViewControlState(…); // …etc }
42
View
43
View Location Berlin AX In EU now Yes Create Update Delete Read
44
<Page> <Grid> <StackPanel> <StackPanel>
<Image> <TextBlock> <TextBlock> <TextBox> <StackPanel> <Button> <StackPanel> <RadioButton>
45
<Page> <Grid> MasterDetails ViewModel Details Master
<Page.DataContext> <MasterDetailsViewModel> </Page.DataContext> <Page.Resources ...> <Grid> <!-- (Master) --> <ListView ...> <!-- (Details) --> <StackPanel ...> <!-- (Action buttons) --> <!-- (State buttons) --> </Grid> <Page> <Grid> Details Master Action buttons State buttons MasterDetails ViewModel
46
<ListView> MasterDetails ViewModel Master ViewModel Item
ItemsSource="{Binding ItemViewModelCollection}" SelectedItem="{Binding ItemViewModelSelected, Mode=TwoWay}" Visibility="{Binding ItemSelectorVisible}" IsEnabled="{Binding ItemSelectorEnabled}" > <ListView.ItemTemplate ...> </ListView> MasterDetails ViewModel Master ViewModel Item ViewModel
47
Item ViewModel <ListView.ItemTemplate>
<DataTemplate DataType="ItemViewModel"> <StackPanel Orientation="Horizontal"> <Image Source="{Binding ImageSource}" Visibility="{Binding ImageVisibility}" Width="{Binding ImageSize}" Height="{Binding ImageSize}" /> <TextBlock Text="{Binding Description}" FontSize="{Binding FontSize} /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> Item ViewModel
48
<StackPanel> <StackPanel> MasterDetails ViewModel Details
... <StackPanel Orientation="Horizontal"> <TextBlock Style="{StaticResource TextBlockStyle}" Text="{Binding ViewControlStates[Location].Description}"/> <TextBox Style="{StaticResource TextBoxStyle}" IsEnabled="{Binding ViewControlStates[Location].Enabled}" Visibility="{Binding ViewControlStates[Location].Visible}" Text="{Binding DetailsViewModel.Location, Mode=TwoWay}"/> </StackPanel> MasterDetails ViewModel Details ViewModel
49
<StackPanel> MasterDetails ViewModel <Button>
... <!--Delete button--> <Button Content="Delete" Style="{StaticResource ButtonStyle}" IsEnabled="{Binding ViewControlStates[Delete].Enabled}" Visibility="{Binding ViewControlStates[Delete].Visible}" Command="{Binding DeleteCommand}"/> </StackPanel> <StackPanel> <Button> MasterDetails ViewModel
50
<StackPanel> MasterDetails ViewModel <StackPanel> ...
<!--Create radiobutton--> <RadioButton Content=“Create" Style ="{StaticResource RadioButtonStyle}" Command ="{Binding SelectCreateCommand}"/> </StackPanel> <StackPanel> <RadioButton> MasterDetails ViewModel
51
Validering
52
View Model Validators Validation Exception Model
53
Car : DomainClassBase public class Car : DomainClassBase {
public string LicensePlate { get; set; } // …etc } Car : DomainClassBase
54
Car ValidationHandler public class Car : DomainClassBase {
private string _licensePlate; public string LicensePlate get { return licensePlate; } set ValidationHandler.ThrowOnInvalid<string>( Validator.ValidateLicensePlate, value); _licensePlate = value; } Car public static void ThrowOnInvalid<TValue>( Func<TValue,ValidationOutcome> validator, TValue value) { ValidationOutcome vo = validator(value); if (vo != null) throw new ValidationException(vo.Message); } ValidationHandler
55
Car Validator (in Domain.Car) ValidatorHandler set {
ValidationHandler.ThrowOnInvalid<string>( Validator.ValidateLicensePlate, value); _licensePlate = value; } Car public static ValidationOutcome ValidateLicensePlate(string value) { return ValidationHandler.ValidateStringMinLength(value, 3); } Validator (in Domain.Car) public static ValidationOutcome ValidateStringMinLength( string value, int minLength, [CallerMemberName] string propertyName = null) { string message = propertyName + " " + " must contain at least " + minLength + " characters"; return Validate<string>(value, (v => v.Length >= minLength), message); } ValidatorHandler
56
Details ViewModel Car public string LicensePlate {
get { return DomainObject.LicensePlate; } set DomainObject.LicensePlate = value; OnPropertyChanged(); } Car
57
Details ViewModel Car public string LicensePlate {
get { return DomainObject.LicensePlate; } set try DomainObject.LicensePlate = value; } catch (ValidationException e) PresentValidationError(e.Message, () => { OnPropertyChanged(); }); OnPropertyChanged(); Details ViewModel Car protected void PresentValidationError(string message, Action undo) { UserActionPresenter.PresentMessage( message, "Undo", new RelayCommand(undo)); }
58
License plate AX
59
throw new ValidationException(…)
MasterDetails ViewModel Details ViewModel Model Car License plate AX 43 52 set try { DomainObject.LicensePlate = value; } set get set { ValidationHandler.ThrowOnInvalid<string>( Validator.ValidateLicensePlate, value); _licensePlate = value; } throw new ValidationException(…) catch (ValidationException e) { PresentValidationError( e.Message, () => { OnPropertyChanged(); }); } Undo OnPropertyChanged()
60
throw ValidationException
MasterDetails ViewModel Details ViewModel Model Car License plate AX get throw ValidationException Undo OnPropertyChanged()
61
Controllers
62
View Action View Model Controllers Model
63
ICommand ControllerBase<TDomainClass>
public abstract class ControllerBase<TDomainClass> : ICommand { MasterDetailsViewModelBase<TDomainClass> MasterDetailsViewModel; CatalogBase<TDomainClass> Catalog; // etc. } public abstract void Execute(); ControllerBase<TDomainClass>
64
ICommand DeleteControllerBase<TDomainClass>
public override void Execute() { TDomainClass obj = MasterDetailsViewModel.ItemViewModel.DomainObject; Catalog.Delete(obj.Key); MasterDetailsViewModel.AfterModelDelete(obj); } DeleteControllerBase<TDomainClass>
65
AfterModelDelete(key)
Controller MasterDetails ViewModel Model Delete(key) AfterModelDelete(key) public virtual void AfterModelDelete(int key) { ItemViewModelSelected = null; OnPropertyChanged(nameof(ItemViewModelCollection)); } get public List<ItemViewModel> ItemViewModelCollection { get return _masterVM.CreateItemViewModelCollection( _catalog, _viewModelFactory); }
66
MasterDetails ViewModel Delete
private ControllerBase<TDomainClass> _deleteCommandController; … _deleteCommandController = new DeleteControllerBase<TDomainClass>(this, _catalog); public ICommand DeleteCommand { get { return _deleteCommandController; } } Delete
67
MasterDetails ViewModel Delete Controller Delete
<Button Content="Delete" Style="{…}" IsEnabled="{Binding …}" Visibility="{Binding …}" Command="{Binding DeleteCommand}"/> Delete Controller Execute Delete
68
Filters
69
Filter Filter Filter Catalog CollectionBase<Car> Car Car
Condition Filter Condition Filter Condition Car
70
CollectionBase<Car> Car
Catalog public class Catalog : CatalogBase<Car> { public Filter<Car> PriceFilter; private bool PriceCondition(Car obj) return obj.Price < ; } ... private Catalog() : base(...) PriceFilter = new Filter<Car>("PriceFilter", PriceCondition); AddFilter(PriceFilter); CollectionBase<Car> Car Filter
71
MasterDetails ViewModel public bool PriceFilterOn {
get { return CarCatalog.Instance.PriceFilter.On; } set CarCatalog.Instance.PriceFilter.On = value; OnPropertyChanged(nameof(ItemViewModelCollection)); } StateManager.AddViewControlState(new ViewControlState( "PriceFilter", "Price below 100k"));
72
View MasterDetails ViewModel
<TextBlock Text="{Binding ViewControlStates[PriceFilter].Description}"/> <ToggleSwitch IsOn="{Binding PriceFilterOn, Mode=TwoWay}"/> MasterDetails ViewModel
73
Udvidelser
74
Cross-domain logik Cross-property validering Database (Entity Framework) integration Web-services / Cloud Run-time konfiguration af views (show/hide Master…) Auto-generering af kode
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.