1. Wahl des passenden Basisrenderers,
Je nach Funktionsumfang des zu migrierenden Renderers muss die Basisklasse auf einer der folgenden abgeändert werden
ControlDefaultRendererBase
: Renderer OHNE Unterteilung in Read- und EditMode-Methoden und OHNE Bind-UnterstützungControlDefaultBindableRendererBase
: Renderer OHNE Unterteilung in Read- und EditMode aber MIT Bind-UnterstützungControlDefaultReadEditRendererBase
: Renderer MIT Unterteilung in Read- und EditMode-Methoden und OHNE Bind-UnterstützungControlDefaultReadEditBindableRendererBase
: Renderer MIT Unterteilung in Read- und EditMode-Methoden und MIT Bind-Unterstützung
Renderer, die migriert werden müssen, erben allerdings schon oftmals von einem anderen Core- oder CRM-Renderer, so dass sich diese Frage nicht stellt und die Migration entsprechend der übergeordneten Basisklassen erfolgen muss.
2. Renderer ohne Unterteilung in Read- und Edit-Methoden
Häufig gibt es in den alten Implementierungen Stellen, an denen die ReadMode-Methode einfach per => auf die EditMode-Methode verweist (oder umgekehrt). Gerade für dieses frühere Vorgehen ist die Nutzung dieser Basisklassen sinnvoll.
Die implementierende Methode solte in Render()
umbenannt und eine möglicherweise verweisende Methode gelöscht werden.
Dieser Schritt kann auch nötig sein, wenn der abgeleitete Core-/CRM-Renderer nun eine entsprechende Basisklasse verwendet.
3. Entfernen der Übergabeparameter von Read-/EditMode und Bind
Renderer sind nun stateful und die Übergabeparameter an ReadMode(), EditMode() und Bind() entfallen.
Das Äquivalent von “parametersUi” ist das Instanz-Property “RenderParameters”.
4. Entfernen der Variableninitialisierung
Viele Renderer-Methoden haben direkt am Anfang folgende Initialisierung:
FormControlRendererUiParameterModel parametersUi = (FormControlRendererUiParameterModel)parameters;
FormRenderingContextUi renderingContext = (FormRenderingContextUi)parametersUi.RenderingContext;
string namePrefix = RenderingUtils.GetUIReadyContextPrefix(renderingContext);
Eigentlich können diese Zeilen einfach weg genommen und die Zugriffe entsprechend auf die RenderProperties umgebogen werden.
Um Kompatibilität zum Rest der Implementierung zu wahren, kann der Block allerdings auch mit leichten Änderungen stehen bleiben:
FormControlRendererParameterModel parametersUi = RenderParameters;
FormRenderingContext renderingContext = parametersUi.RenderingContext;
string namePrefix = parametersUi.NamePrefix;
Konkrete Änderungen sind:
parametersUi
->RenderParameters
renderingContext
->RenderParameters.RenderingContext
namePrefix
->RenderParameters.NamePrefix
5. Optional: Abruf der Property-Inhalte in den Render-Methoden nach Konvention
Der Zugriff auf das Property, muss in jedem Fall über die Deskriptoren erfolgen. Ein direktes Auslesen beispielsweise über GetPropertyValue()
ist untersagt.
Für den Feldnamen des Controls auf dem Bind-Objekt wird garantiert, dass beim Abrufen von Daten zunächst GetValueFromModel()
und anschließend ConvertFromModelPropertyType()
aufgerufen wird.
Sollten weitere Werte aus dem Bind-Objekt benötigt werden, so werden diese ebenfalls immer unter Verwendung von PrepareBindProperty()
und GetValueFromModel()
abgerufen; der Aufruf auf ConvertFromModelPropertyType()
ist in diesem Fall optional und muss von der Methode unterstützt werden.
Hieraus folgt:
Direkte Zugriffe auf RenderParameters.BindData
sind immer kritisch zu betrachten. Hier ist man nur richtig, wenn tatsächlich der top-level-Datensatz verwendet werden soll. Das gültige Bind-Objekt für das aktuell angesteuerte Property ist BindObject
! Was beispielsweise auch ein Teil-Datensatz sein kann.
Beispiel:
Der Feldname des Controls ist "Addresses[1].AddressType"
, BindData ist OrmCRMCompany.
Durch den Aufruf PrepareBindProperty("Addresses[1].AddressType")
passiert folgendes:
RenderParameters.BindData
bleibt wie es war eine Instanz vonOrmCRMCompany
BindObject
wird auf den angesteuerten Teildatensatz verschobenPreparedProperty
beinhaltet nun denPropertyDescriptor
des Feldes"AddressType"
für den Typen des Teildatensatzes
6. Pflege des ViewStates
Der ViewState
ist neu und enthält wichtige Informationen für die Steuerelemente und insbesondere für das Binding. Folgendes muss gepflegt werden.
- Ist ein Client-Control aus irgendeinem Grund für den Benutzer nicht editierbar, so muss
ViewState.ShouldBind = false
gesetzt werden. ViewState.ViewStateData
muss, wenn möglich, unter dem SchlüsselBindKeys.ModelProperty
den serverseitig verwendeten Feldnamen (Property-Namen auf demBindObject
) enhalten. Ist das Control einIPropertyControl
mit der MethodeGetFieldName()
, so wird dies vom Framework automatisch gemacht.ViewState.ViewStateData
sollte unter dem SchlüsselBindKeys.ClientProperty
den clientseitig verwendeten Feldnamen (inkl.RenderParameter.NamePrefix
, also z.B. “DLG1.SearchNames”) enthalten.- Das zugehörige Control kann während des Bind-Vorgangs nicht verlässlich ermittelt werden; daher sollten Werte, die im Binding benötigt werden, ebenfalls unter eigenen Schlüsseln in
ViewStateData
abgelegt und während des Bindens wieder ausgelesen werden.
Erweitert der eigene Renderer nicht die Basisklassen, sondern einen Renderer vorhandener Steuerelementen, wird die Pflege schon durchgeführt, falls man gesichert die base.Render()
, base.ReadMode()
oder base.EditMode()
aufruft.
7. Optional: Eigenes Binden von Werten nach Konvention
Für den Feldnamen des Controls auf dem Bind-Objekt wird garantiert, dass beim Binden von Daten zunächst GetValueFromRequest()
, dann ConvertToModelPropertyType()
und schließlich WriteValueToModel()
aufgerufen wird.
Sollten weitere Werte in das Bind-Objekt geschrieben werden, so werden diese ebenfalls immer unter Verwendung von GetValueFromRequest()
, PrepareBindProperty()
und WriteValueToModel()
verarbeitet; der Aufruf auf ConvertToModelPropertyType()
ist in diesem Fall optional und muss von der Methode unterstützt werden.
Ansonsten gilt alles weitere aus Punkt 5.
8. Optional: Übertrag und ggf Anpassung von ICustomBindingControl.AssignValue nach ConvertFromModelPropertyType
Die Methode ICustomBindingControl.AssignValue
diente früher dazu, Werte auf eine angepasste Weise aus dem Orm in das FormModel zu übertragen. Diese Methode wird innerhalb der Renderer durch ConvertFromModelPropertyType()
abgelöst. Damit also beispielsweise der Renderer generisch mit einer List<Guid>
arbeiten kann, muss ConvertFromModelPropertyType()
dafür sorgen, dass der Wert, der hineingegeben wird, auch als List<Guid>
zurückgegeben wird, egal, ob das nun eine einzelne Guid
, ein String
mit oder ohne Kommas oder ein GuitSet
war.
9. Übertrag und ggf Anpassung von ICustomBindingControl.Bind nach ConvertToModelPropertyType
Wie Punkt 7 nur in Gegenrichtung.
Die Implementierung der Bind-Methode in den Basisrenderern ist für den Normalgebrauch vollkommen ausreichend. Es ist üblich, für einen eigenen Renderer die Convert-Methoden zu überschreiben, um Beispielsweise einen string
in eine Guid
oder eine Guid
in einen ValueEnum
umzuwandeln und damit weiterzuarbeiten. Weniger üblich – wenn auch dennoch valide – ist es, die WriteValueToModel-Methode zu überschreiben, wenn ein Wert beispielsweise gar nicht über ein einfaches SetValue
auf dem PropertyDescriptor
schreibbar ist, sondern vorher noch verarbeitet oder in mehrere Felder geschrieben werden muss. Am seltensten muss die Bind-Methode selbst überschrieben werden, und das auch nur, wenn zum Beispiel mehrere Werte zu einem Steuerelement gebunden werden müssen.