| 

.NET C# Java Javascript Exception

1
Hi Leute,

ViewModel wird ja in der View (entweder XAML oder Codebehind)instanzieert. Somnit kann ich die Observable zur ListBox binden. Wenn ich nun aber von einer ganz anderen Klasse auf diese Observable zugreifen möchte, dann weiss ich nicht so recht wie ich das machen soll. Ich habe echt ne Weilge recherchiert aber genau dieses Thema nicht wirklich gefunden. Das ViewModel als singleton zu verwenden???....hmmmmm???? FindResource ist bestimmt auch nicht die ideale Lösung, dann müsste ich ja das ViewModel im App.Xaml instanziieren. Wie wird sowas gemacht? Ich blicke überhaupt nicht durch......
News:
10.08.2016
mradic 3 3
9 Antworten
1
so wie ich dich verstehe, hast du nur die XAML-View und ein passendes ViewModel implementiert. Das ViewModel ist aber nur dazu da, die Daten aus der Anwendungslogik für die Präsentation am Bildschirm aufzubereiten. Du müsstest also zunächst mal Datenmodell und Anwendungslogik implementieren. Das Datenmodell könnte z.B. aus einer Klasse mit den Daten für Transkationen (sprich Geld-Ein- und ausgänge) und einer Klasse Konto, welche eine Liste von Transaktionen verwaltet bestehen. Die Anwendungslogik einthält dann Funktionen zur Verwaltung des Kontos (wie z.B. Einzahlung, Auszahlung usw.). Die Anwendungslogik ist dann unter anderem auch dafür zuständig, die einzelnen Views anzuzeigen. Du kannst auf diese Weise von der Anwendungslogik aus dieselbe Liste von Transaktionen in verschiedene ViewModels injizieren. Wenn dein Datenmodell die INotifyPropertyChanged bzw. ICollectionChanged Interfaces implementiert, werden Änderungen in einer View automatisch in die andere View übernommen.

Ich habe noch ein paar Links zum Thema MVVM herausgesucht. Mit Hilfe dieser Artikel habe ich mich selber in das Thema eingearbeitet:


Step by Step guide to MVVM
WPF MVVM Quickstart Tutorial
The MVVM Design Pattern
Von der Datenbank bis zur Oberfläche
Ein etwas komplexeres Beispiel
12.08.2016
luedi 2,0k 1 9
Die Artikel sind sehr hilfreich. Vielen Dank.
mradic 12.08.2016
1
Nach deiner Beschrebung entspricht deine Controller-Klasse eher einem Service. Somit bist du schon auf dem richtigen Weg. Ich implementiere die Anwendungslogik in der Regel in separaten Klassen, die per Konvention "Service" genannt werden. Diese Service-Klassen instantiiere ich dann im ViewModel um die Funktionen zu nutzen. Dein Beispiel könnte z.B. so aussehen:

public class TransaktionsService {
...
public void SpeicherGeldEingaenge(ObservableCollection<GeldEingang> liste) {
...
}
// und zum Anbinden an die View (über das ViewModel)
public ObservableCollection<GeldEingang> LeseGeldeingaenge() {
...
}
}

public class MyViewModel {
private TransaktionsService myService;

public MyViewModel() {
myService = new TransaktionsService();
}
...
}


Das ist aus meiner Sicht aber nicht die beste Lösung, da die ObservableCollection GUI-bezogen ist und deshalb in einer Service-Schicht nicht verwendet werden sollte (weil z.B. andere GUI-Frameworks nicht mit ObservableCollections umgehen können). Deshalb würde ich in den Serviceklassen die Standard-Collections von .NET (wie z.B. List<T>) verwenden und diese im ViewModel in eine ObservableCollection umkopieren. Du musst dir immer vor Augen halten, dass das ViewModel nur für die Anbindung der Daten an die View und die Reaktion auf Benutzereingaben zuständig ist. Je nach Benutzereingabe delegiert das ViewModel die Verarbeitung dann an die Anwendungslogik. Diese sollte keine Kenntnis darüber haben, wie die Daten dargestellt werden. Aus diesem Grund ist unter Anderem das MVVM-Pattern entstanden. Das ViewModel nimmt die Daten aus der Anwendungslogik entgegen und bereitet sie für die Anzeige auf. Dabei ist es durchaus legitim, dass verschiedene ViewModels identische Daten unterschiedlich anzeigen (z.B. als Liste von Werten oder als Grafik).
13.08.2016
luedi 2,0k 1 9
0
Ich verstehe Ihr Problem leider nicht ganz.
Auf eine Observable muss man eigentlich nie direkt zugreifen, da man ja Komponenten, die an Ereignissen interessiert sind, bei der Observablen registriert.

Das sollte auch mit fremden Klassen funktionieren, wenn diese sich bei der Observablen registrieren können.
10.08.2016
edvservice 1,3k 1 6
0
vielen Dank für die Antwort.
Bisher habe ich immer nur eben mit der Add Methode der ObSColl. Objekte hinzugefügt. Eine andere Vorgehensweise kenne ich nicht. Mein Problem liegt darin, dass das View eine instanz vom ViewModel hat, wo die OBS drin ist. Wenn ich von einer anderen Klasse aus ebenfallst auf die OBS zugreifen will, dann ist ja das mit mit einer neuen Instanz ja überflüssig, da ja dieses neue Objekt dem View nicht bekannt ist. Da ich mich nicht so gut auskenne, ist es für mich da ein wenig unübersichtlich. Ist das kompliziert mit dem Registrieren? Gibt es da einen Artikel? Vielen Dank noch mal......

Vielleicht ist das noch erwähnenswert ??: Struktur ist View1 <=> ViewModel1 <=> Logik <=> Daten. Und der Zugriff auf die ObsCollection soll aus einer Klasse ausserhalb dieser Struktur erfolgen.....
10.08.2016
mradic 3 3
0
Ich habe dein Problem zwar auch nicht ganu verstanden, aber das ganze klingt für mich etwas obskur. Welchen Grund hast du, von außerhalb auf die Internas einer View zuzugreifen? Du scheinst dich ja mit deiner Architektur an das MVVM-Pattern anzulehen. Ein Prinzip hierbei ist, dass ein ViewModel genau für eine View zuständig ist. Das ViewModel wird von der Logik mit Daten versorgt (in einfachen Fällen können die Daten auch direkt gelesen werden). Wenn du den Inhalt der ObservableCollection modifizieren oder abfragen musst, kannst du dies doch auch in deiner Logik tun. D. h. du baust deine Collection in der Logik auf und übergibst sie an das Viewmodel, welches sie dann der View zur Verfügung stellt. Wenn du in deiner Logik die Collection änderst werden die Änderungen in der View sichtbar, vorausgesetzt die CollectionChenged-Events sind korrekt implementiert.

Wenn du allerdings möchtest, dass in Abhängigkeit von der Auswahl in der Combobox oder ListView irgendetwas passieren soll (sei des ein Aufruf in die Logik oder die Änderung der Darstellung in einer anderen View) solltest du das Command-Pattern verwenden. Damit kannst du in XAML ein Event an eine Funktion in deinem ViewModel binden und von dort aus die gewünschte Logik aufrufen.

Vielleich hilft dir ja der folgende CodeProject-Artikel weiter.

Gruß
Klaus
11.08.2016
luedi 2,0k 1 9
0
Hi Klaus.....vielen Dank für deine Antwort,

gut, dann erklär ich das mal ausführlicher. Ich entwickle ein Programm zum festhalten der Geldeinnahmen und Geldausgaben. Da ich am lernen bin, will ich auch keine fertigen Sachen runterladen. Als Beispiel nehme ich den Geldeingang. Ich habe eine MainView mit einem Tab - Control. Eine Tab für Geldeingänge, eine für Geldausgänge....usw. Dann habe ich für den Geldeingang ein UserControl (RevenueView) erstellt und das dann im TabItem reingezogen. In der RevenueView ist eine ListBox vorhanden. Im Xaml der RevenueView instanziiere ich das RevenueViewModel, denn da ist ja die ObservableCollection. Im Knoten ListBox binde ich dann ja mit ItemSource die ListBox mit der ObservableCollection. Das ist alles ok und funktioniert. Meine Frage lautet nun: Da die ReveneueView bereits das RevenueViewModel instanziiert, exisitert bereits ein Objekt und demnach auch eine ObservableCollection. Wenn ich aber nun in einer anderen Klasse auf diese ObservableCollection zugreifen möchte, dann müsste ich doch in dieser andren Klasse das ReveneueVieModel noch mal instanziieren. Aber dann hätte ich doch eine ObservableColleciotn, die nicht mehr an die ListBox gebunden wäre.....sehe ich das falsch??? Vorher habe ich das so gemacht: Anstatt in der RevennueView das ReveneueViewModel zu zunstanziieren, habe ich das in der App.Xaml gemacht. Ich kann dann in jeder klasse mit FindResource() mir die Instanz holen. Oder die ObservableCollection wird als static deklariert......oder das ReveneueViewModsel als singleton.......gibt es denn nicht eine andere Möglichkeit? Kann ich mit Interfaces arbeiten? oder mit irgendwelchen delegates? Ich habe mir das inzischen so umgebaut, dass auch die andere Klasse die Instanz vom RevennueViewModel bekommt aber ich habe mir halt erhofft, dass es elegantere Möglichkeiten gibt. Will ja lernen......Hoffe, dass ich diesmal verständlich bin. Vielen Dank für eure Mühen.
11.08.2016
mradic 3 3
0
Hi....Leute vielen Dank für eure Mühen und eure Bereitschaft mir zu helfen. Ich werde mir alles noch mal durchschauen und ich denke, dass meine Denkweise über Objekte das eigentliche Problemt ist. Es geht um Geldeingänge (Lohn / Gehalt, Kindergeld...etc) und um Geldausgänge ( MIete, Strom....etc. ) und um Einkäufe sowie eine Übersicht. Dementsprechd auch vier klassen.

Also 4 Views, 4 ViewModels und 4 Models. Geldeingänge, Geldausgänge und Einkäufe haben immer die gleichen variablen: Datum, Sender/Empfänger und Betrag. Daher habe ich das in eine Abstrakte Klasse gepackt, damit die drei Klassen das erben....aus allen drei Klassen würden sich auch die gleichen Methoden: LadeGeldeingänge, LadeGeldausgänge, SpeicherGeldeingänge, SpeicherGeldausgänge ergebn.

Anstatt also jetzt in den drei Models diese Methoden zu implementieren, habe ich eine Controler-Klasse dazwischen. Da gibt es dann nur eine einzige Methode und erwartet ein object. Mit typeof wird der Sender bestimmt und dann gehts weiter zu einer einzigen Methode in nur einem Model. Also keine 4 Models mehr. Wenn ich nun die ObservableCollection im Controler deklariere und von dort aus der View zur Verfügung stelle??

(Müsste ich erst noch ausprobieren). Derzeit befindet sie sich ViewModel. Vielleicht gehe ich das alles falsch an aber ich habe das aus einem LehrVideo.....im View.Xaml (nicht Codebehind) wird das ViewModel instanziiert. Und hier mein Gedankenkang: View1 hat Instanz von ViewModel1. Dann darf ich in der Controler - Klasse das ViewModel doch nicht erneut instanziieren??? Beispiel:

Methode im Controler......
SpeicherGeldeingänge(object sender)
{
if sender.getType() == typeof(Geldeingang)
{ wie hole ich jetz die Daten aus der ObservableCollection?;}
}
Ich darf doch hier nicht das VievModel nochnal inszanziieren ?!!!. Dann bekomme ich doch ein neues Objekt, also auch eine leere ObservableCollection. Ich gehe wahrscheinlich das ganze komplett falsch an. In anderen Projekten habe ich die Collection einfach weiter gereicht.

Ich denke, dass der Thread geschlossen werden kann. Ich will euch das gar nicht mehr zumuten und entschuldige mich an dieser Stelle für die vielen Wiederholungen.......

Ich werde trotzden bis Morgen Mittag nochmal reinschauen. Vielleicht hat ja auch einer eine Idee, wie ich das anders umsetzen soll? Es muss ja nun wirklich nicht das MVVM sein. Ist aber einfacher mit den Bindungen.......Ok Leute. Ich scheiß mich mal dann gleich nochnal an VS2015 ran und refactorisiere das ding, bis es läuft.....he he he.

Grüße aus dem wunderschönen, abenteurlichen Berlin
12.08.2016
mradic 3 3
0
joaaahhh. Vielen Dank. Das werde ich sofort ausprobieren. Aber nur mal so ein Gedanke. Egal, ob das vernünftig ist oder nicht. Wenn du nun in dem ViewModel den TransAktionsService nicht instanziiertst dann kannst du die OBS nicht mitgeben, richtig? Luedi, hast mit diesem Beispiel eigentlich genau mein Porblem wiedergegeben.

"WPF eine im ViewModel, an eine ListBox im View, gebundene ObservableCollection aus einer anderen Klasse(TransaktionsService) ansprechen. Ja, ist vielleicht sehr unglücklich fromuliert. Und dann hätte ich wohl noch schreiben müssen, "wenn TranaktionsService nicht im VIeModel instanziiert wird".

luedi, soll ich dir das Projekt schicken? Wären drei oder vier Klassen, die man sich angucken müsste. Ich muss noch aufräumen, weil ich da ziemlich viel rumgeschlampt habe. Ich werde das auch gut kommentieren, sodass man sich gut zurechtfinden könnte. Ich denke, dass man ca. max. 20 Minuten zum drüberschauen bräuchte.....na ja, nur so ein Gedanke. Falls nicht, ist es auch ok. Ansonsten vielen Dank Leute....echt coole Sache hier.
13.08.2016
mradic 3 3
wenn du den Source irgendwo im Netz ablegst (z.B. OneDrive), kann ich ihn mir holen und ansehen. Meine E-Mail-Adresse werde ich hier nicht veröffentlichen.
luedi 14.08.2016
0
soll ich mir jetzt ein Hotmail-Konto anlegen oder was meinst du mit den Links?
Ich habe ein Verzeichnis auf meinem OneDrive freigegeben (da hätte ich auch gleich draufkommen können :-( ). Lade den Sourcecode auf folgende Adresse hoch (am besten als gepackte ZIP-Datei):

https://1drv.ms/f/s!AtF1S9tfXT7ObjaadPDHfeuLaAE
luedi 16.08.2016
geradeben habe ich festgestellt, dass du auf jeden Fall einen Microsoft-Account brauchst, um auf das Verzeichnis zugreifen zu können. Im Zweifel musst du dir einen anlegen.
luedi 16.08.2016

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH