Falls kein Datenprovider vorhanden ist, der die Auswahl bietet, kann man einen eigenen Datenprovider implementieren. Dafür sind zwei Klassen notwendig, zum einen der Datenprovider selbst und zum anderen seine Eigenschaften.
Eigenschaften des Datenproviders
Die Eigenschaften
- Die Klasse muss die Basis Klasse
ControlDataProviderPropertiesBase
erweitern. - Die Eigenschaften sollten prinzipiell simple Datentypen sein. Komplexe Datentypen sollten dringend vermieden werden.
Beispielsweise sollte die Guid einer Konfiguration, anstatt die Konfiguration selbst, definiert werden. - Die Properties-Klassen der DataProvider dürfen keine Referenzen auf veränderliche Datentypen enthalten.
Andernfalls kommt es bei der Implementierung von DataProvider-Modifier-Methoden zu schwer zu findenden Fehlern mit undefiniertem Verhalten, weil Änderungen an den Listen sich dauerhaft auf Masken aller Benutzer auswirken. - Sinnvoll ist es mit
Guid
,GuidSet
, etc. zu arbeiten, auch wenn diese nicht in den Attributen angeben werden können. Die Umwandlung, sollte dann direkt im Konstruktor erfolgen. - WICHTIG: Der vollständige Klassenname des eigentlichen Datenproviders muss in die Eigenschaft DataProviderTypeFullName gesetzt werden.
Beispiel
public class CDPEnumValuesProperties : ControlDataProviderPropertiesBase
{
public Guid MasterGuid { get; set; }
public bool DisplayIcon { get; set; } = true;
public EnumEntryActiveState ActiveState { get; set; }
public GuidSet WantedValues { get; set; }
public CDPEnumValuesProperties(string masterGuid = null, bool displayIcon = true, string activeState = null, string[] wantedValues = null) : base()
{
DataProviderTypeFullName = typeof(CDPEnumValues).FullName;
if (!string.IsNullOrEmpty(masterGuid))
MasterGuid = masterGuid.ToGuid();
DisplayIcon = displayIcon;
if (activeState != null || activeState.IsGuid())
ActiveState = Api.Enum.GetEnumValue<EnumEntryActiveState>(activeState.ToGuid());
WantedValues = GuidSet.Parse(wantedValues);
}
}
Der Datenprovider
- Er muss das Interface
IControlDataProvider
implementieren. - In
Properties
stehen die Eigenschaften zur Verfügung. - Die Methode
GetRows()
liefert das Ergebnis zurück.- Es ist sinnvoll Datenprovider so zu implementieren, dass diese selbst erweitert werden können. In diesem Beispiel wurde eine virtuelle Methode
AddWhere()
implementiert. Diese kann überschrieben werden, und dadurch können weitere Filter implementiert werden. - Die Parameter enthalten den Filter, der in der UI vom Anwender eingegeben wurde. Dieser Filter muss auf die Ergebnisliste angewendet werden. In diesem Beispiel in der Methode
AddFilter()
.
- Es ist sinnvoll Datenprovider so zu implementieren, dass diese selbst erweitert werden können. In diesem Beispiel wurde eine virtuelle Methode
- Die Methode
GetByKeys()
liefert für eine gegebene Menge von Schlüsseln die Einträge zurück. Diese aus zwei Gründen nicht unbedingtGetRows()
aufrufen.- Wenn das Zeitverhalten durch eine direkte Implementierung zu erwarten besser ist.
- Wenn Schüssel vorkommen können, die nicht in der Auswahl vorhanden sind. Beispiel: Können gewählte Auswahlwerte nicht in der Auswahlliste vorhanden sein. Mögliche Gründe sind, das sie inaktiv gesetzt worden sind oder nur bestimmte Personen bestimmte Auswahllistenwerte wählen können.
public class CDPEnumValues : IControlDataProvider
{
public ControlDataProviderPropertiesBase Properties { get; set; }
public virtual IQueryable<ControlDataRow> GetRows(ControlDataProviderParameter parameter = null)
{
if (Properties != null && Properties is CDPEnumValuesProperties prop)
{
IEnumerable<ValueEnum> enumValues = AddWhere(Api.Enum.GetEnumValues(prop.MasterGuid));
IEnumerable<ControlDataRow> values = enumValues.Select(CreateRow);
values = AddFilter(values, parameter?.Filter);
return values.AsQueryable();
}
if (Properties == null)
throw new ArgumentNullException("Data provider: The properties are NULL");
throw new ArgumentException(String.Format("Data provider: The properties are {0} and not {1}", Properties.GetType().FullName, typeof(CDPEnumValuesProperties).FullName));
}
public override IEnumerable<ControlDataRow> GetByKeys(IReadOnlyCollection<string> keys)
{
foreach (string key in keys)
if (key != null && Guid.TryParse(key, out Guid guid) && Api.Enum.GetEnumValue(guid) is ValueEnum value)
yield return CreateRow(value);
}
public virtual IEnumerable<ValueEnum> AddWhere(IEnumerable<ValueEnum> list)
{
if (Properties is CDPEnumValuesProperties prop)
{
return list.Where(ff => (prop.OnlyTheseValues == null || prop.OnlyTheseValues.Contains(ff.ValueGuid))
&& ((prop.WantedValues != null && prop.WantedValues.Contains(ff.ValueGuid))
|| ((prop.IncludeNonReadable || ff.CurrentUserCanSelect())
&& (prop.ActiveState == null || prop.ActiveState == EnumEntryActiveState.All || ff.IsActive == (prop.ActiveState == EnumEntryActiveState.Active)))));
}
return list;
}
protected virtual ControlDataRow CreateRow(ValueEnum value)
{
return new ControlDataRow
{
Key = value.GuidString,
Title = value.Translation_Guid.ToString().Translate(),
DataItem = value,
};
}
public virtual IEnumerable<ControlDataRow> AddFilter(IEnumerable<ControlDataRow> list, string filter)
{
if (string.IsNullOrWhiteSpace(filter))
return list; // no filter
string conditionFilterPart = filter.Replace("\"", "").ToLower();
return list.Where(ff => ff.Title != null && ff.Title.ToLower().Contains(conditionFilterPart));
}
}
Alternative Basisklassen für den Datenprovider
CDPBase
Die Basisklasse implementiertProperties
und stellt Hilfsmethoden zur Verfügung.SimpleCDPBase
ErweitertCDPBase
und implementiertGetByKeys
, so daß man nur noch eineGetByKey
Methode implementieren muss.StaticCDPBase
ErweitertCDPBase
und implementiert den Filter und die Sortierung. StattGetRows
implementiert man selbstGetRawRows
. Auch dieGetByKeys
ist schon implementiert. Nur zu empfehlen, wennGetRawRows
hochperformant alle möglichen Ergebnisse gesichert enthält.