Ich arbeite an einer WPF-Anwendung mit Ansichten, die zahlreiche Wertkonvertierungen erfordern. Zunächst meine Philosophie (inspiriert teilweise von dieser lebhaften Debatte über XAML Disciples war) , dass ich die Ansicht Modell streng über die Unterstützung der machen sollte Daten Anforderungen der Ansicht. Dies bedeutete, dass alle Wertkonvertierungen, die erforderlich waren, um Daten in Dinge wie Sichtbarkeiten, Pinsel, Größen usw. umzuwandeln, mit Wertkonvertern und Mehrfachwertkonvertern durchgeführt wurden. Konzeptionell schien dies ziemlich elegant. Das Ansichtsmodell und die Ansicht hätten beide einen bestimmten Zweck und wären gut entkoppelt. Eine klare Linie würde zwischen "Daten" und "Aussehen" gezogen.
Nun, nachdem ich dieser Strategie den "alten College-Versuch" gegeben habe, habe ich einige Zweifel, ob ich mich auf diese Weise weiterentwickeln möchte. Eigentlich denke ich stark darüber nach, die Wertkonverter zu entleeren und die Verantwortung für (fast) alle Wertkonvertierungen direkt in die Hände des Ansichtsmodells zu legen.
Die Realität der Verwendung von Wertkonvertern scheint einfach nicht dem scheinbaren Wert sauber getrennter Belange zu entsprechen. Mein größtes Problem bei Wertkonvertern ist, dass deren Verwendung mühsam ist. Sie müssen eine neue Klasse erstellen , den Wert oder die Werte implementieren IValueConverter
oder in den richtigen Typ umwandeln, auf (zumindest für mehrwertige Konverter) testen , die Konvertierungslogik schreiben und den Konverter in einem Ressourcenwörterbuch registrieren [siehe Aktualisierung unten ] und schließlich schließen Sie den Konverter mit ziemlich ausführlichem XAML an (was die Verwendung von magischen Zeichenfolgen sowohl für die Bindung (en) als auch für den Namen des Konverters erfordert)IMultiValueConverter
object
DependencyProperty.Unset
[siehe Update unten]). Der Debugging-Prozess ist auch kein Picknick, da Fehlermeldungen häufig kryptisch sind, insbesondere im Entwurfsmodus / Expression Blend von Visual Studio.
Das heißt nicht, dass die Alternative, das Ansichtsmodell für alle Wertkonvertierungen verantwortlich zu machen, eine Verbesserung ist. Dies könnte sehr gut darauf zurückzuführen sein, dass das Gras auf der anderen Seite grüner ist. Abgesehen davon, dass Sie die elegante Trennung von Bedenken verlieren, müssen Sie eine Reihe abgeleiteter Eigenschaften schreiben und sicherstellen, dass Sie die Basiseigenschaften gewissenhaft RaisePropertyChanged(() => DerivedProperty)
festlegen, was sich als unangenehmes Wartungsproblem erweisen kann.
Das Folgende ist eine erste Liste von Vor- und Nachteilen, die ich zusammengestellt habe, um Ansichtsmodellen den Umgang mit der Konvertierungslogik und die Beseitigung von Wertkonvertern zu ermöglichen:
- Vorteile:
- Weniger Gesamtbindungen, da Multikonverter entfallen
- Weniger magische Zeichenfolgen (Bindungspfade
+ Konverter-Ressourcennamen) Keine Registrierung mehr für jeden Konverter (plus Pflege dieser Liste)- Weniger Arbeit zum Schreiben jedes Konverters (keine Implementierung von Schnittstellen oder Casting erforderlich)
- Kann problemlos Abhängigkeiten einfügen, um die Konvertierung zu erleichtern (z. B. Farbtabellen)
- XAML-Markups sind weniger ausführlich und einfacher zu lesen
- Wiederverwendung des Konverters weiterhin möglich (obwohl eine gewisse Planung erforderlich ist)
- Keine mysteriösen Probleme mit DependencyProperty.Unset (ein Problem, das ich bei mehrwertigen Konvertern festgestellt habe)
* Durchgestrichene Symbole kennzeichnen Vorteile, die bei Verwendung von Markup-Erweiterungen nicht mehr angezeigt werden (siehe Update unten).
- Nachteile:
- Stärkere Kopplung zwischen Ansichtsmodell und Ansicht (z. B. müssen Eigenschaften Konzepte wie Sichtbarkeit und Pinsel behandeln)
- Weitere Gesamteigenschaften, um eine direkte Zuordnung für jede angezeigte Bindung zu ermöglichen
(siehe Update 2 unten)RaisePropertyChanged
muss für jede abgeleitete Eigenschaft aufgerufen werden- Muss sich weiterhin auf Konverter verlassen, wenn die Konvertierung auf einer Eigenschaft eines Oberflächenelements basiert
Wie Sie wahrscheinlich feststellen können, habe ich Sodbrennen in Bezug auf dieses Problem. Ich zögere sehr, mich dem Refactoring zu widmen, nur um festzustellen, dass der Codierungsprozess genauso ineffizient und mühsam ist, ob ich Wertkonverter verwende oder zahlreiche Wertkonvertierungseigenschaften in meinem Ansichtsmodell verfügbar mache.
Vermisse ich irgendwelche Vor- / Nachteile? Für diejenigen, die beide Mittel der Wertumwandlung ausprobiert haben, welche haben Sie für besser befunden und warum? Gibt es noch andere Alternativen? (Die Schüler erwähnten etwas über Typdeskriptor-Anbieter, aber ich konnte nicht verstehen, worüber sie sprachen. Einsichten darüber wären willkommen.)
Aktualisieren
Ich habe heute herausgefunden, dass es möglich ist, eine sogenannte "Markup-Erweiterung" zu verwenden, um die Notwendigkeit zu beseitigen, Wertkonverter zu registrieren. Tatsächlich müssen sie nicht nur nicht mehr registriert werden, sondern es wird auch eine intelligente Funktion zum Auswählen eines Konverters während der Eingabe bereitgestellt Converter=
. Hier ist der Artikel, mit dem ich angefangen habe: http://www.wpftutorial.net/ValueConverters.html .
Die Möglichkeit, eine Markup-Erweiterung zu verwenden, ändert das Gleichgewicht in meiner Auflistung der Vor- und Nachteile sowie in der obigen Diskussion etwas (siehe durchgestrichene Punkte).
Als Ergebnis dieser Enthüllung experimentiere ich mit einem Hybridsystem, in dem ich Konverter verwende BoolToVisibility
und das, was ich nenne, MatchToVisibility
und das Ansichtsmodell für alle anderen Konvertierungen. MatchToVisibility ist im Grunde ein Konverter, mit dem ich überprüfen kann, ob der gebundene Wert (normalerweise eine Aufzählung) mit einem oder mehreren in XAML angegebenen Werten übereinstimmt.
Beispiel:
Visibility="{Binding Status, Converter={vc:MatchToVisibility
IfTrue=Visible, IfFalse=Hidden, Value1=Finished, Value2=Canceled}}"
Grundsätzlich wird überprüft, ob der Status entweder "Fertig" oder "Abgebrochen" ist. Wenn dies der Fall ist, wird die Sichtbarkeit auf "Sichtbar" gesetzt. Andernfalls wird es auf "Versteckt" gesetzt. Es stellte sich heraus, dass dies ein sehr häufiges Szenario war und dass dieser Konverter mir ungefähr 15 Eigenschaften in meinem Ansichtsmodell (plus zugehörige RaisePropertyChanged-Anweisungen) ersparte. Beachten Sie Converter={vc:
, dass bei der Eingabe "MatchToVisibility" in einem Intellisense-Menü angezeigt wird. Dies verringert die Wahrscheinlichkeit von Fehlern merklich und macht die Verwendung von Wertkonvertern weniger mühsam (Sie müssen sich den Namen des gewünschten Wertkonverters nicht merken oder nachschlagen).
Falls Sie neugierig sind, füge ich den folgenden Code ein. Ein wichtiges Merkmal dieser Implementierung MatchToVisibility
ist , dass es überprüft , ob der gebundene Wert eine ist enum
, und wenn es ist, es überprüft , um sicherzustellen Value1
, Value2
usw. sind auch Aufzählungen des gleichen Typs. Dies bietet eine Entwurfs- und Laufzeitprüfung, um festzustellen, ob die Enum-Werte falsch eingegeben wurden. Um dies zu einer Überprüfung während der Kompilierung zu verbessern, können Sie stattdessen Folgendes verwenden (ich habe dies von Hand eingegeben, bitte verzeihen Sie mir, wenn ich Fehler gemacht habe):
Visibility="{Binding Status, Converter={vc:MatchToVisibility
IfTrue={x:Type {win:Visibility.Visible}},
IfFalse={x:Type {win:Visibility.Hidden}},
Value1={x:Type {enum:Status.Finished}},
Value2={x:Type {enum:Status.Canceled}}"
Das ist zwar sicherer, aber zu ausführlich, um es mir wert zu sein. Ich könnte genauso gut eine Eigenschaft für das Ansichtsmodell verwenden, wenn ich dies tun werde. Auf jeden Fall finde ich, dass die Entwurfszeitprüfung für die Szenarien, die ich bisher ausprobiert habe, vollkommen ausreichend ist.
Hier ist der Code für MatchToVisibility
[ValueConversion(typeof(object), typeof(Visibility))]
public class MatchToVisibility : BaseValueConverter
{
[ConstructorArgument("ifTrue")]
public object IfTrue { get; set; }
[ConstructorArgument("ifFalse")]
public object IfFalse { get; set; }
[ConstructorArgument("value1")]
public object Value1 { get; set; }
[ConstructorArgument("value2")]
public object Value2 { get; set; }
[ConstructorArgument("value3")]
public object Value3 { get; set; }
[ConstructorArgument("value4")]
public object Value4 { get; set; }
[ConstructorArgument("value5")]
public object Value5 { get; set; }
public MatchToVisibility() { }
public MatchToVisibility(
object ifTrue, object ifFalse,
object value1, object value2 = null, object value3 = null,
object value4 = null, object value5 = null)
{
IfTrue = ifTrue;
IfFalse = ifFalse;
Value1 = value1;
Value2 = value2;
Value3 = value3;
Value4 = value4;
Value5 = value5;
}
public override object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
var ifTrue = IfTrue.ToString().ToEnum<Visibility>();
var ifFalse = IfFalse.ToString().ToEnum<Visibility>();
var values = new[] { Value1, Value2, Value3, Value4, Value5 };
var valueStrings = values.Cast<string>();
bool isMatch;
if (Enum.IsDefined(value.GetType(), value))
{
var valueEnums = valueStrings.Select(vs => vs == null ? null : Enum.Parse(value.GetType(), vs));
isMatch = valueEnums.ToList().Contains(value);
}
else
isMatch = valueStrings.Contains(value.ToString());
return isMatch ? ifTrue : ifFalse;
}
}
Hier ist der Code für BaseValueConverter
// this is how the markup extension capability gets wired up
public abstract class BaseValueConverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public abstract object Convert(
object value, Type targetType, object parameter, CultureInfo culture);
public virtual object ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Hier ist die ToEnum-Erweiterungsmethode
public static TEnum ToEnum<TEnum>(this string text)
{
return (TEnum)Enum.Parse(typeof(TEnum), text);
}
Update 2
Seitdem ich diese Frage gestellt habe, bin ich auf ein Open-Source-Projekt gestoßen, das "IL-Weben" verwendet, um NotifyPropertyChanged-Code für Eigenschaften und abhängige Eigenschaften einzufügen. Dies macht die Implementierung von Josh Smiths Vision des Ansichtsmodells als "Wertkonverter für Steroide" zum Kinderspiel. Sie können einfach "Automatisch implementierte Eigenschaften" verwenden, den Rest erledigt der Weber.
Beispiel:
Wenn ich diesen Code eingebe:
public string GivenName { get; set; }
public string FamilyName { get; set; }
public string FullName
{
get
{
return string.Format("{0} {1}", GivenName, FamilyName);
}
}
... das wird kompiliert:
string givenNames;
public string GivenNames
{
get { return givenName; }
set
{
if (value != givenName)
{
givenNames = value;
OnPropertyChanged("GivenName");
OnPropertyChanged("FullName");
}
}
}
string familyName;
public string FamilyName
{
get { return familyName; }
set
{
if (value != familyName)
{
familyName = value;
OnPropertyChanged("FamilyName");
OnPropertyChanged("FullName");
}
}
}
public string FullName
{
get
{
return string.Format("{0} {1}", GivenName, FamilyName);
}
}
Das spart enorm viel Code, den Sie eingeben, lesen, durchblättern usw. müssen. Noch wichtiger ist jedoch, dass Sie nicht herausfinden müssen, welche Abhängigkeiten Sie haben. Sie können neue Eigenschaften hinzufügen, FullName
ohne die Abhängigkeitskette mühsam zu durchlaufen, um sie in RaisePropertyChanged()
Aufrufe einzufügen.
Wie heißt dieses Open-Source-Projekt? Die ursprüngliche Version heißt "NotifyPropertyWeaver", aber der Besitzer (Simon Potter) hat seitdem eine Plattform namens "Fody" für das Hosting einer ganzen Reihe von IL-Webern erstellt. Das Äquivalent zu NotifyPropertyWeaver unter dieser neuen Plattform heißt PropertyChanged.Fody.
- Anweisungen zum Einrichten von Fody: http://code.google.com/p/fody/wiki/SampleUsage (ersetzen Sie "Virtuosity" durch "PropertyChanged")
- PropertyChanged.Fody-Projektsite: http://code.google.com/p/propertychanged/
Wenn Sie sich für NotifyPropertyWeaver entscheiden möchten (das etwas einfacher zu installieren ist, aber in Zukunft nicht unbedingt über Fehlerkorrekturen hinaus aktualisiert werden muss), finden Sie hier die Projektsite: http://code.google.com/p/ notifypropertyweaver /
In beiden Fällen verändern diese IL-Weaver-Lösungen das Kalkül in der Debatte zwischen dem Ansichtsmodell für Steroide und den Wertkonvertern vollständig.
quelle
BooleanToVisibility
Nimmt einen Wert, der mit der Sichtbarkeit zusammenhängt (wahr / falsch) und übersetzt ihn in einen anderen. Dies scheint eine ideale Verwendung von a zu seinValueConverter
. Auf der anderen SeiteMatchToVisibility
ist die Codierung der Geschäftslogik inView
(welche Arten von Elementen sollten sichtbar sein). Meiner Meinung nach sollte diese Logik auf das heruntergedrückt werdenViewModel
, oder sogar noch weiter in das, was ich das nenneEditModel
. Was der Benutzer sehen kann, sollte sich im Test befinden.MatchToVisibility
schien eine bequeme Möglichkeit zu sein, einige einfache Modusschalter zu aktivieren (ich habe eine Ansicht, insbesondere mit einer Tonne von Teilen, die ein- und ausgeschaltet werden können. In den meisten Fällen sind Abschnitte der Ansicht sogar mit (mitx:Name
) beschriftet , um dem Modus zu entsprechen sie entsprechen.) Es ist mir nicht wirklich eingefallen, dass dies "Geschäftslogik" ist, aber ich werde Ihren Kommentar etwas überlegen.Antworten:
Ich habe
ValueConverters
in einigen Fällen die Logik verwendet undViewModel
in anderen die Logik eingesetzt . Ich habe das Gefühl, dass aValueConverter
Teil derView
Ebene wird. Wenn die Logik also wirklich Teil der Ebene ist, platziereView
sie dort, andernfalls platziere sie in der EbeneViewModel
.Persönlich sehe ich kein Problem mit dem
ViewModel
Umgang mitView
spezifischen Konzepten wieBrush
es, weil in meinen Anwendungen eineViewModel
nur als testbare und bindbare Oberfläche für dieView
. Einige LeuteViewModel
fügen jedoch eine Menge Geschäftslogik hinzu (ich nicht) und in diesem FallViewModel
ist das eher ein Teil ihrer Geschäftsebene, sodass ich in diesem Fall keine WPF-spezifischen Inhalte haben möchte.Ich bevorzuge eine andere Trennung:
View
- WPF-Zeug, manchmal nicht testbar (wie XAML und Code-Behind), aber auchValueConverter
sViewModel
- Testbare und bindbare Klasse, die auch WPF-spezifisch istEditModel
- Teil der Business-Schicht, die mein Modell während der Manipulation darstelltEntityModel
- Teil der Business-Schicht, die mein Modell als dauerhaft darstelltRepository
- verantwortlich für die PersistenzEntityModel
der DatenbankSo wie ich es mache, habe ich wenig Sinn für
ValueConverter
sDie Art und Weise, wie ich mich von einigen Ihrer "Con" verabschiedet habe, ist, meine
ViewModel
sehr generisch zu machen . Ein Beispiel, dasViewModel
ich genannt habe,ChangeValueViewModel
implementiert eine Label-Eigenschaft und eine Value-Eigenschaft. Auf derView
gibt es eineLabel
, die an die Label-Eigenschaft und eineTextBox
, die an die Value-Eigenschaft bindet.Ich habe dann einen,
ChangeValueView
derDataTemplate
von demChangeValueViewModel
Typ abgetastet ist . Wann immer WPF sieht, dassViewModel
es das anwendetView
. Der Konstruktor von myChangeValueViewModel
übernimmt die Interaktionslogik, die er zum Aktualisieren seines Status benötigtEditModel
(normalerweise wird nur ein a übergebenFunc<string>
), und die AktionAction
, die er ausführen muss, wenn der Benutzer den Wert bearbeitet (nur eine , die eine Logik in der ausführtEditModel
).Das übergeordnete Element
ViewModel
(für den Bildschirm) nimmt einEditModel
in seinen Konstruktor und instanziiert nur die entsprechenden elementaren ElementeViewModel
wie zChangeValueViewModel
. Da das übergeordneteViewModel
Element die auszuführende Aktion einfügt, wenn der Benutzer Änderungen vornimmt, kann es alle diese Aktionen abfangen und andere Aktionen ausführen. Daher könnte die injizierte Bearbeitungsaktion für aChangeValueViewModel
wie folgt aussehen:Natürlich kann die
foreach
Schleife an einer anderen Stelle umgestaltet werden, aber dies bewirkt, dass die Aktion ausgeführt und auf das Modell angewendet wird. Dann (vorausgesetzt, das Modell hat seinen Status auf unbekannte Weise aktualisiert) werden alle KinderViewModel
aufgefordert, ihren Status abzurufen das Modell wieder. Wenn sich der Zustand geändert hat, sind sie beiPropertyChanged
Bedarf für die Ausführung ihrer Ereignisse verantwortlich .Das regelt die Interaktion zwischen beispielsweise einem Listenfeld und einem Detailfenster recht gut. Wenn der Benutzer eine neue Auswahl auswählt, aktualisiert er die
EditModel
Auswahl mit der Auswahl undEditModel
ändert die Werte der Eigenschaften, die für den Detailbereich verfügbar gemacht werden. DieViewModel
Kinder, die für die Anzeige der Detailfensterinformationen verantwortlich sind, werden automatisch benachrichtigt, dass sie nach neuen Werten suchen müssen. Wenn sie sich geändert haben, lösen sie ihrePropertyChanged
Ereignisse aus.quelle
ViewModel
Ebene vorziehen . Nicht jeder stimmt mir zu, aber es hängt davon ab, wie Ihre Architektur funktioniert.CalendarViewModel
für einCalendarView
UserControl oder einDialogViewModel
für einDialogView
). Das ist nur meine Meinung :)ViewModel
s.Wenn die Konvertierung etwas mit der Ansicht zu tun hat, z. B. die Sichtbarkeit eines Objekts zu bestimmen, das anzuzeigende Bild zu bestimmen oder die zu verwendende Pinselfarbe zu ermitteln, lege ich meine Konverter immer in die Ansicht.
Wenn es geschäftsbezogen ist, z. B. wenn festgelegt wird, ob ein Feld maskiert werden soll, oder wenn ein Benutzer über die Berechtigung zum Ausführen einer Aktion verfügt, erfolgt die Konvertierung in meinem ViewModel.
Von Ihrem Beispiel, ich glaube , Sie ein großes Stück WPF sind vermisst:
DataTriggers
. Sie scheinen Konverter zum Bestimmen von Bedingungswerten zu verwenden, aber Konverter sollten wirklich zum Konvertieren eines Datentyps in einen anderen dienen.In deinem obigen Beispiel
Ich würde ein verwenden
DataTrigger
, um zu bestimmen, welches Bild angezeigt werden soll, nicht einConverter
. Ein Konverter dient zum Konvertieren eines Datentyps in einen anderen, während ein Trigger verwendet wird, um einige Eigenschaften basierend auf einem Wert zu bestimmen.Ich würde nur in Betracht ziehen, einen Konverter zu verwenden, wenn der gebundene Wert tatsächlich die Bilddaten enthält und ich ihn in einen Datentyp konvertieren muss, den die Benutzeroberfläche verstehen kann. Wenn die Datenquelle beispielsweise eine aufgerufene Eigenschaft enthält
ImageFilePath
, würde ich in Betracht ziehen, die Zeichenfolge mit dem Speicherort der Bilddatei mit einem Konverter in eine zu konvertieren, dieBitmapImage
als Quelle für mein Bild verwendet werden kannDas Endergebnis ist, dass ich einen Bibliotheksnamensraum voller generischer Konverter habe, die einen Datentyp in einen anderen konvertieren, und selten einen neuen Konverter codieren muss. Es gibt Fälle, in denen ich Konverter für bestimmte Konvertierungen haben möchte, aber sie sind selten genug, dass es mir nichts ausmacht, sie zu schreiben.
quelle
Grid
Elemente. Ich versuche auch, Pinsel für Vordergrund / Hintergrund / Kontur festzulegen, basierend auf den Daten in meinem Ansichtsmodell und einer bestimmten Farbpalette, die in der Konfigurationsdatei definiert ist. Ich bin mir nicht sicher, ob dies für einen Trigger oder einen Konverter geeignet ist. Das einzige Problem, das ich bisher habe, wenn ich die meiste Ansichtslogik in das Ansichtsmodell einbaue, ist die Verkabelung allerRaisePropertyChanged()
Anrufe.DataTrigger
Grid tun und sogar die Elemente des Grids austauschen . Normalerweise platziere ich einen,ContentControl
wo sich mein dynamischer Inhalt befinden soll, und tausche denContentTemplate
in einem Trigger aus. Ich habe ein Beispiel unter folgendem Link , wenn Sie daran interessiert sind (navigieren Sie zu dem Abschnitt nach unten mit dem HeaderUsing a DataTrigger
) rachel53461.wordpress.com/2011/05/28/...<TextBlock Text="I'm a Person" Visibility={Binding ConsumerType, Converter={vc:MatchToVisibility IfTrue=Visible, IfFalse=Hidden, Value1=Person}}"
und<TextBlock Text="I'm a Business" Visibility={Binding ConsumerType, Converter={vc:MatchToVisibility IfTrue=Visible, IfFalse=Hidden, Value1=Business}}"
Es hängt davon ab, was Sie testen , wenn überhaupt.
Keine Tests: Mischen Sie den Code mit ViewModel nach Belieben (Sie können ihn später jederzeit umgestalten).
Tests auf ViewModel und / oder niedriger: Konverter verwenden.
Tests auf Modellebenen und / oder niedriger: Code nach Belieben mit ViewModel mischen
ViewModel abstrahiert das Modell für die Ansicht . Persönlich würde ich ViewModel für Pinsel usw. verwenden und die Konverter überspringen. Testen Sie die Ebene (n), auf der sich die Daten in ihrer " reinsten " Form befinden (dh Modellebenen ).
quelle
Visibility
,SolidColorBrush
undThickness
.Dies wird wahrscheinlich nicht alle Probleme lösen, die Sie angesprochen haben, aber es gibt zwei Punkte zu beachten:
Zunächst müssen Sie den Konvertercode in Ihrer ersten Strategie platzieren. Betrachten Sie diesen Teil der Ansicht oder des Ansichtsmodells? Wenn es Teil der Ansicht ist, platzieren Sie die ansichtsspezifischen Eigenschaften in der Ansicht anstelle des Ansichtsmodells.
Zweitens scheint es, als würde Ihr Nicht-Konverter-Entwurf versuchen, die tatsächlichen Objekteigenschaften zu ändern, die bereits vorhanden sind. Es hört sich so an, als würden sie bereits INotifyPropertyChanged implementieren. Warum also nicht ein ansichtsspezifisches Wrapper-Objekt zum Binden verwenden? Hier ist ein einfaches Beispiel:
quelle
Manchmal ist es gut, einen Wertekonverter zu verwenden, um die Virtualisierung zu nutzen.
Ein Beispiel dafür, was in einem Projekt, in dem wir bitmaskierte Daten für Hunderttausende von Zellen in einem Raster anzeigen mussten. Als wir die Bitmasken im Ansichtsmodell für jede einzelne Zelle dekodierten, dauerte das Laden des Programms viel zu lange.
Als wir jedoch einen Wertekonverter erstellten, der eine einzelne Zelle dekodierte, wurde das Programm in einem Bruchteil der Zeit geladen und reagierte genauso, da der Konverter nur aufgerufen wird, wenn der Benutzer eine bestimmte Zelle ansieht (und dies nur aufgerufen werden müsste maximal dreißig Mal, wenn der Benutzer seinen Blick auf das Raster verschiebt).
Ich weiß nicht, wie MVVM diese Lösung beanstandet hat, aber sie hat die Ladezeit um 95% verkürzt.
quelle