Code implementieren

Dialogschritte werden gemäß des MVVM-Musters implementiert.

1. Das Design der Daten-ViewModels orientiert sich am Design der Services.

Schleupen.AS.MT.BIB.Buecher.EntityService_3.2

So wird im Schritt "BuecherAusleiheBestaetigenStep" das Buch des BuchEntityService zur Anzeige gebracht, gekapselt durch das BuchViewModel.

Es gilt folgende Namenskonvention für ViewModel: <Name Entity>ViewModel

ViewModels repräsentieren UI-spezifische Datenmodelle die zur DataBinding benötigt werden. Diese definieren typisierte Eigenschaften wie beliebige .NET-Typen oder andere ViewModels. Des Weiteren können die Validierungsregeln beinhalten (das wird wir im Kapitel Validierung erläutert)

My Code

Für dieses Beispiel werden folgende ViewModels: "BuchViewModel", "BenutzerViewModel" und "BenutzerReferenceViewModel" angelegt, siehe das UML-Diagramm oben. Diese ViewModels werden in CodeBehind-Dateien angelegt und als Klassen ausgeprägt.

Im Folgenden wird das Projekt erst gegen Ende kompilierfähig!

2. Wir müssen zunächst eine CodeBehind für das "BuchViewModel" anlegen, indem wir den "BucherausleiheBestätigenStep" selektieren und im Kontextmenu den Eintrag "Add Class"

wählen.

Für jedes ViewModel lege jetzt eine neue CodeBehind-Datei als Klasse an, sodass du folgendes Resultat erhalten solltest:

BuchViewModel.cs

// Copyright...:  (c)  Schleupen SE

// ReSharper disable once CheckNamespace
namespace Schleupen.AS.mal.bal.bap.BuecherAusleihen.BuecherAusleiheBestaetigenStep.V3_1
{
	using System;
	using Schleupen.CS.PI.PR.ViewModels;

	// ReSharper disable once CheckNamespace
	public class BuchViewModel : ViewModel
	{
		private Guid id;
		private string titel;
		private DateTime? erscheinungsdatum;
		private string isbn;
		private string sprache;
		private string autor;
		private string genre;

		public Guid Id
		{
			get { return id; }
			set { SetFieldValue(ref id, value); }
		}

		public string Titel
		{
			get { return titel; }
			set { SetFieldValue(ref titel, value); }
		}

		public DateTime? Erscheinungsdatum
		{
			get { return erscheinungsdatum; }
			set { SetFieldValue(ref erscheinungsdatum, value); }
		}

		public string Isbn
		{
			get { return isbn; }
			set { SetFieldValue(ref isbn, value); }
		}

		public string Sprache
		{
			get { return sprache; }
			set { SetFieldValue(ref sprache, value); }
		}

		public string Autor
		{
			get { return autor; }
			set { SetFieldValue(ref autor, value); }
		}

		public string Genre
		{
			get { return genre; }
			set { SetFieldValue(ref genre, value); }
		}
	}
}

BenutzerViewModel.cs

// Copyright...:  (c)  Schleupen SE

// ReSharper disable once CheckNamespace
namespace Schleupen.AS.mal.bal.bap.BuecherAusleihen.BuecherAusleiheBestaetigenStep.V3_1
{
	using System;
	using Schleupen.CS.PI.PR.ViewModels;

	public class BenutzerViewModel : ViewModel
	{
		private Guid id;
		private string sid;
		private string name;

		public Guid Id
		{
			get { return id; }
			set { SetFieldValue(ref id, value); }
		}

		public string Sid
		{
			get { return sid; }
			set { SetFieldValue(ref sid, value); }
		}

		public string Name
		{
			get { return name; }
			set { SetFieldValue(ref name, value); }
		}
	}
}

BenutzerReferenceViewModel.cs

// Copyright...:  (c)  Schleupen SE

// ReSharper disable CheckNamespace
namespace Schleupen.AS.mal.bal.bap.BuecherAusleihen.BuecherAusleiheBestaetigenStep.V3_1
{
	using Schleupen.CS.PI.PR.Engine.Validation.Runtime.UsedByGeneratedCode;
	using Schleupen.CS.PI.PR.ViewModels;

	public class BenutzerReferenceViewModel : ViewModel
	{
		private BenutzerViewModel benutzerReference;
		private string text;

		public BenutzerViewModel BenutzerReference
		{
			get { return benutzerReference; }
			set { SetFieldValue(ref benutzerReference, value); }
		}

		public string Text
		{
			get { return text; }
			set { SetFieldValue(ref text, value); }
		}
	}
}

3. Als Nächstes definieren wir ein ViewModel für die View.

Dieses Model (das sogenannte Main-ViewModel, da es direkt hinter der View hängt) wird spezifisch für eine View ausgeprägt und kann nicht wiederverwendet werden. Das Main-ViewModel stellt die zu bindenden ViewModels bereit:

BuecherAusleiheBestaetigenStepViewModel.cs

// Copyright...:  (c)  Schleupen SE

// ReSharper disable once CheckNamespace
namespace Schleupen.AS.mal.bal.bap.BuecherAusleihen.BuecherAusleiheBestaetigenStep.V3_1
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using Schleupen.CS.PI.PR.Engine.Validation.Runtime.UsedByGeneratedCode;
	using Schleupen.CS.PI.PR.ViewModels;
	using Schleupen.CS.PI.PR.ViewModels.Collections;

	// ReSharper disable once CheckNamespace
	public class BuecherAusleiheBestaetigenStepViewModel : ViewModel
	{
		public const string DefaultCheckoutMessage = "Es wurde noch kein Benutzer ausgewählt.";


		private ViewModelCollection<BuchViewModel> auszuleihendeBuecher = new ViewModelCollection<BuchViewModel>();
		private BenutzerReferenceViewModel selectedBenutzer = new BenutzerReferenceViewModel();
		private string checkoutMessage;

		public BuecherAusleiheBestaetigenStepViewModel()
		{
			AuszuleihendeBuecher = new ViewModelCollection<BuchViewModel>();
			SelectedBenutzer = new BenutzerReferenceViewModel();
			CheckoutMessage = DefaultCheckoutMessage;
		}

		public ViewModelCollection<BuchViewModel> AuszuleihendeBuecher
		{
			get { return auszuleihendeBuecher; }
			set { SetFieldValue(ref auszuleihendeBuecher, value); }
		}

		[Required]
		public BenutzerReferenceViewModel SelectedBenutzer
		{
			get { return selectedBenutzer; }
			set { SetFieldValue(ref selectedBenutzer, value); }
		}

		public string CheckoutMessage
		{
			get { return checkoutMessage; }
			set { SetFieldValue(ref checkoutMessage, value); }
		}
	}
}

Das Main-ViewModel kann ein Gateway etc. als Member haben, um Logik anzubinden, Daten zu laden etc. definieren.

4. Füge als Nächstes die "BuecherAusleiheBestaetigenStepStepActivity.cs"- CodeBehind hinzu. Diese Datei ist eine partial class und somit ein Teil von der View.

Im Visual Studio öffnen wir die View "BuecherAusleiheBestaetigenStep" per Doppelklick auf die Datei "BuecherAusleiheBestaetigenStep_3.1.ds".

<?xml version="1.0" encoding="utf-8"?>
<DialogStep xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Namespace="Schleupen.AS.mal.bal.bap.BuecherAusleihen" Name="BuecherAusleiheBestaetigenStep" Version="3.1.0.0" Title="Ausleihe bestätigen" HelpPageUrl="NoHelpPage" xmlns="urn://Schleupen.CS.PI.PR.DialogStep_2.1">
  ...

Im Xml definieren wir eine Property ViewModel als Instanz von BuecherAusleiheBestaetigenStepViewModel:

<?xml version="1.0" encoding="utf-8"?>
<DialogStep xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Namespace="Schleupen.AS.mal.bal.bap.BuecherAusleihen" Name="BuecherAusleiheBestaetigenStep" Version="3.1.0.0" Title="Ausleihe bestätigen" HelpPageUrl="NoHelpPage" xmlns="urn://Schleupen.CS.PI.PR.DialogStep_2.1">
  <Properties>
    <Property Name="ViewModel" Type="BuecherAusleiheBestaetigenStepViewModel" />
  </Properties>
  ...

In der Datei "BuecherAusleiheBestaetigenStepStepActivity.cs" wird das BuecherAusleiheBestaetigenStepViewModel instanziiert:

//   Copyright...:  (c)  Schleupen SE

namespace Schleupen.AS.mal.bal.bap.BuecherAusleihen.BuecherAusleiheBestaetigenStep.V3_1
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Schleupen.CS.PI.PR.Engine;
    using Schleupen.CS.PI.PR.Engine.Controls.UsedByGeneratedCode;
    using Schleupen.CS.PI.PR.Engine.ServiceModel;

	public partial class BuecherAusleiheBestaetigenStepStepActivity
	{
		protected override void OnInitialize()
		{
			ViewModel = new BuecherAusleiheBestaetigenStepViewModel();
		}		
	}
}

5. Jetzt können wir die ViewModels in "BuecherAusleiheBestaetigenStep" per Data Binding deklarativ an die Controls binden (z.B. Value="{ViewModel.SelectedBenutzer.BenutzerReference}"):

  <Form>
    <DataGrid Name="GridBuecher" Label="Auszuleihende Bücher" Items="{ViewModel.AuszuleihendeBuecher}" TabIndex="1" >
      <Selection />
      <Settings />
      <Columns>
        <TextColumn Property="Titel" Label="Titel" />
        <DateTimeColumn Property="Erscheinungsdatum" Label="Erscheinungsdatum" />
        <TextColumn Property="Isbn" Label="Isbn" />
        <TextColumn Property="Sprache" Label="Sprache" />
        <TextColumn Property="Autor" Label="Autor" />
        <TextColumn Property="Genre" Label="Genre" />
      </Columns>
    </DataGrid>
    <GridContainer Name="GridContainer1">
      <ReferenceLookup Layout="Row:1,Column:0" Name="RL_01" TabIndex="10" Value="{ViewModel.SelectedBenutzer.BenutzerReference}" TextValue="{ViewModel.SelectedBenutzer.Text}" Label="Benutzer" Placeholder="Benutzer auswählen" Width="200px" />
      <Label Layout="Row:0,Column:0,ColumnSpan:2" Name="LabelBenutzer" Value="Ausleihender Benutzer" Styles="label-header" />
      <GroupContainer Layout="Row:3,Column:0,ColumnSpan:2" Name="GroupContainer1" Collapsed="false" IsExpandable="false" HasBorder="false" ContentContext="Info" TabIndex="3">
        <TextBlock Name="Info" Value="{ViewModel.CheckoutMessage}" />
      </GroupContainer>
      <GridRows>
        <GridRow />
        <GridRow />
        <GridRow />
        <GridRow />
      </GridRows>
      <GridColumns>
        <GridColumn Width="50%" />
        <GridColumn Width="50%" />
      </GridColumns>
    </GridContainer>
  </Form>

Der Dialogschritt visualisiert noch keine Daten. Das wird noch in den nächsten Kapiteln vervollständigt.

6. Der Infotext "Es wurde noch kein Benutzer ausgewählt." zeigt zur Zeit nur den Defaultwert. Dieser sollte auch Benutzerspezifisch angezeigt werden. Um das zu erreichen, definieren wir in der "BuecherAusleiheBestaetigenStepStepActivity" einen UpdateTrigger.

	...
	[Schleupen.CS.PI.PR.Core.CustomAttributes.UsedByGeneratedCode.ExecuteWhenPropertyValueChanged("{RootAndChildren:ViewModel.SelectedBenutzer}")]
	public virtual void UpdateMessage()
	{
		ViewModel.UpdateMessage();
	}
	...

In

namespace Schleupen.AS.mal.bal.bap.BuecherAusleihen.BuecherAusleiheBestaetigenStep.V3_1
{
	...

	// ReSharper disable once CheckNamespace
	public class BuecherAusleiheBestaetigenStepViewModel : ViewModel
	{
		...

		public void UpdateMessage()
		{
			CheckoutMessage = !string.IsNullOrEmpty(SelectedBenutzer?.Text)
				? $"Wenn Sie diese Bücher für den angegebenen Benutzer '{SelectedBenutzer.Text}' ausleihen wollen, bestätigen Sie bitte die Ausleihe mit dem Button 'Fertigstellen'."
				: DefaultCheckoutMessage;
		}
	}
}

Um zu überprüfen, ob der UpdateTrigger aufgerufen wird, schreiben wir einen Test. Doch dazu müssen wir zunächst noch Libraries (z.B. mit einem Service-Gateway) und Verträge für den Datenaustausch erstellen und anbinden.

Chatbot not allowed
Cookie Consent mit Real Cookie Banner