Binding Problem

  • WPF

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

    Binding Problem

    Hallo Ihr wissenden,

    ich habe ein Problem:
    Zustandsbeschreibung: Ich habe ein Listview die an eine observablecollection gebunden ist. In dieser Listview habe ich ein ein ItemTemplate welches ein UserControl beinhaltet. Dieses UserControl ist eine UI Hülle welches die Daten aus der observablecollection der Listview bezieht.

    XML-Quellcode

    1. <ListView ItemsSource="{Binding DataContext.DestinationCollection, NotifyOnSourceUpdated=True, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
    2. <ListView.ItemTemplate>
    3. <DataTemplate>
    4. <local:ctr_Destination DataContext="{Binding BindsDirectlyToSource=True}"/>
    5. </DataTemplate>
    6. </ListView.ItemTemplate>
    7. </ListView>


    Problem: Das ListView erhält die Daten das es erhalten soll. Das funktioniert! Aber der DataContext wird nicht an das "ctr_Destination" übertragen. Erst wenn ich das Binding neu anstoße indem ich im laufenden Betrieb im Xaml z.b. BindsDirectlyToSource=True auf BindsDirectlyToSource=False und zurücksetze, wird das UserControl neu gebunden und die Datenbindung funktioniert.
    Könnt Ihr erkennen was hier falsch läuft? Was muss ich im DataContext von "ctr_Destination" ändern, damit Datenänderungen gleich erkannt werden?

    Vielen Dank für eure Hilfe.

    Lieben Gruß,
    Chris

    *CodeTag korrigiert* ~NoFear23m

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Nofear23m“ ()

    Hallo

    Wenn das ListView die Daten enthält wie es soll stimmt das Binding. Was hier vermutlich das Problem ist, ist die zugrunde liegende Klasse.

    In wiefern werden die Daten denn geändert? Zeige mal den Code von "DestinationCollection" bzw. das besagte Property.

    Erstens muss das Property "DestinationCollection" das Event PropertyChanged werfen und zum anderen die Propertys der Items auch.

    Also wenn "DestinationCollection" eine Observable(Of Car) wäre und in der Klasse Car gibt es Properties wie Marke und Model müssen die Properties Marke und Model auch im Setter das Event PRopertyChanged werfen da die WPF sonst nicht weis was sich wann ändert und du es wie du ja richtig sagst manuell mitteilen musst.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    vielen Dank für deine Antwort und deine Anpassungs meines Codes. Ich weiß leider nicht wie ich das ganze farbig gestalte.

    Die DestinationColection sieht so aus:


    VB.NET-Quellcode

    1. Private _DestinationCollection As ObservableCollection(Of DestinationViewModel) = New ObservableCollection(Of DestinationViewModel)
    2. Public ReadOnly Property DestinationCollection As ObservableCollection(Of DestinationViewModel)
    3. Get
    4. Return _DestinationCollection
    5. End Get
    6. End Property



    Das UserControl "ctr_Destination" hat entsprechend das DestinationViewModel als DataContext. Die DestinationCollection wird richtig befüllt. Sind zum Beispiel drei Destinationen vorhanden, wird das UserControl 'ctr_Destination' entsprechend dreimal angezeigt aber entsprechend ohne Inhalt. Erst wenn ich das Bindung im laufenden Betrieb durch Manipulation des XAML Codes erneuer, werden die Daten entsprechend richtig angezeigt. Ich weiß aber das die Daten von anfang an vorhanden sind. Den wenn ich z.B. anstelle des UserControls einfach eine Textbox nehme und dessen Content an eine Property des DestinationsViewModel binde, dann werden die Daten von Anfang an angezeigt.

    Es scheint einfach, dass die Bindung von 'ctr_Destination' stattfindet bevor Daten vorhanden sind. Wenn dann Daten hinzugefügt wurden bekommt das UserControl dies nicht mit. Innerhalb des ViewModel ist jede Property mit INotifyPropertyChanged verbunden. Wie gesagt, dass UserControl an sich funtioniert wie es soll, nur der DataContext bezieht sich anfangs eben nicht auf das DestinationViewModel des ObservableCollection sondern auf ihren eigenen DataContext. Erst durch erneutes manuelles Anstoßen wechelt der DataContext und der Inhalt wird richtig angzeigt.

    *CodeTag korrigiert* ~NoFeart23m

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Nofear23m“ ()

    Hallo

    Gut, dann können wir das ganze schonmal eingrenzen.

    Aber zeig doch ein wenig mehr. OK, was die Klasse betrifft gleube ich dir jetzt mal das INotifyPropertyChanged richtig implementiert ist und korrekt angewandt wird.
    Dann zeig mal bitte den XAML des UserControl.

    BTW: Bitte verwende die richtigen CodeTag. für XAML verwende bitte XML und für VB.Net Code bitte das Tag für VB.Net. Danke.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    der XAML Code des UserControls ist über 300 Zeilen lang und wird dir nicht helfen. Es bindet sich an die ganzen Properties des ViewModels. Wie gesagt das Control an sich funktioniert. Es bindet sich an das DestinationViewModel mittels folgenden XAML Code.

    XML-Quellcode

    1. <UserControl.DataContext>
    2. <local:DestinationViewModel/>
    3. </UserControl.DataContext>


    Wenn ich das Control mit einer definierten Instanz des ViewModels verwenden möchte, dann binde ich dessen DataContext an die Instanz auf das sich das Control beziehen soll. Das funktioniert, wenn ich das Usercontrol einzeln verwende und ich den DataContext entsprechend definiere. Jetzt soll es sich aber dynamisch an eine ObservableCollection gebunden werden. Und ich glaube er bezieht sich eben auf ein leeres ViewModel oder sein eigenes und bekommt die Daten aus dem der Collection erst nach manuellen Hinweis mit.
    OK, dann machen wir folgendes.

    Du machst ein kleines Beispielprojekt welches das Problem reproduziert. Kann ja was einfacher sein wie eine Collection von Autos oder so.
    Das ladest bereinigt (ohne BIN Ordner) hier als ZIP hoch. Ich schau mir das dann gerne an.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo,

    also ich habe mal ein kleines Beispiel gemacht.
    In dem Fall gibt es das Usercontrol 'ctr_Car' in dem man nach Automarken suchen kann. In dem Beispiel habe ich nur Marken mit A hinterlegt. Wird im Suchfeld soviel eingegeben, dass eine eindeutige Zuweisung möglich ist, wird die Automarke im Control automatisch ausgewählt.

    Darüber hinaus gibt es das Usercontol 'ctr_Cars' in dem man nach mehreren Marken suchen kann. Wenn man im Suchfeld mehrere Marken eingibt und diese mit '-' trennt. Dann wird eine Listview mit dem 'ctr_Car' gefüllt. Die Bindung funktioniert leider wie im Original nicht. Erst wenn ich den Xaml Code im laufenden Betrieb manpuliere z.b. BindsDirectlyToSource=True auf BindsDirectlyToSource=False wird die Bindung erneuert und der Code funktioniert wie er soll.

    Vielleicht hat ja jemand eine Idee wie ich die Bildung vorher schon richtig setzen kann.

    Vielen Dank im Voraus.

    Lieben Gruß,
    Chris
    Dateien
    Hallo

    OK, nur mal kurz. Sorry, ich blick da nicht ganz durch was "erreicht" werden soll.

    Du hast ein Objekt "Car". Und in Car gibt es die Eigenschaft "Brand". Und die Suche soll dazu dienen dem aktuellen CarViewModel eine Brand zuzuweisen oder? Wenn dem so ist ist das ganze etwas sehr wirr gelöst.
    Oder soll es eine reine Suche werden. Also wenn wir annehmen es gibt eine Liste von Autos und man will per Marke Filtern.

    Ich würde es dir gerne so "umbauen" das es für dich auch verständlicher wird was der Fehler ist/war, es wäre allerdings nützlich wenn ich weis was am Ende rauskommen soll.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    erstmal vielen Dank nochmal. Es ist nur ein Beispiel. Es soll zeigen, wie ich das eine Usercontrol mit dem anderen eingebudnen habe. Die EIgenschaften bzw. Cars oder Car sind komplett egal. Im Original hat das Model ca. 30 Eigenschaften und die Suche ist deutlich komplexer. Aber im Grunde funktioniert die Suche wie im Beispiel. Der zu suchende String wird in die einzelnen Segmente getrennt, welches jeweils ein ViewModel darstellt. Ist die Suche auf dem Server erfolgreich wird das eindeutige Ergebnis ausgewählt. Ist die Suche nicht eindeutig, so wird das Ergebnis in einer Listview innerhalb des Usercontros ausgeworfen, welches man dann auswählen muss.

    Aber wie gesagt, das Problem ist die Bindung zwischen dem einen Usercontrol mit dem anderen. Also in dem Beispiel die Bindung der Listview im 'ctrCars' mit 'ctrCar'.

    Lieben GRuß,

    #Also nochmal als Ergänzung: In dem Beispiel gebe ich z.B. in ctr_Cars folgenden suchstring ein 'Audi-As-Alpina'. Die Eingabe repräsentiert also drei Autos. 'Audi' und 'Alpina' sind eindeutig und werden sofort gewählt. Das zweite Auto 'AS' ist nicht eindeutig und muss nochmal nachbearbeitet werden. Hierzu wird die ListView im 'ctr_Cars' angezeigt, damit ich die richtige Marke wählen kann. Ist nach der Auswahl 'AS' = 'Aston Martin' ebenfalls eindeutig so sind alle drei Autos eindeutig zugewiesen.
    Chris

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Hotdogxxxx“ ()

    Hallo

    OK, ich denke ich weis um was es dir Grundlegend geht.
    Das Hauptproblem ist das du innerhalb des XAML des UserControls (deshalb wollte ich den ja sehen) den DatenContext erstellt hast.
    Dadurch erstellt erstmal jedes UserControl seinen eigenen DatenContext und das Binding "verliert" sich. Das UserControl erstellt also somit seine eigene Instanz der Klasse. Das willst du ja nicht, du willst die Instanz der Auflist als DatenKontekt übergeben.

    Weiters ist/war in der Klasse CarViewModel Dinge enthalten die da so nicht hingehören. Klar du hast aus deinem Model "CarModel" kurzerhand ein ViewModel gemacht indem du INotifyPropertyChanged implementiert hast, oder eigendlich nocht schlimmer - gleich die ViewModel-Basisklasse geärbt. Somit gibst du die Trennung zwischen Model und ViewModel in dem Moment völlig auf. Aber gut, das wäre jetzt nicht weiter schlimm.

    Ich habe ein "Ober-ViewModel" SearchCarViewModel erstellt. Dieses hat einfach zwei Eigenschaften NormalSearchViewModel und MultiSearchViewModel.
    Im Konstruktor instanziiere ich beide Eigenschaften. Und diese Klassen wiederum kümmern sich um den Teil um den sie sich kümmern sollen.
    Die Klasse CarViewModel macht nun das was sie soll. Nämlich nur ein Car-Model Wrappen. In diesem Fall ist es simple, es werden vom Model-Objekt einfach die Eigenschaften im jeweiligen Getter zurückgegeben und im Setter in die Model-Instanz reinregeicht. Bei komplexeren Dingen hilft dir solch ein Wrapper aber ungemein da man ja nicht immer so speichern möchte wie man die Daten auch gerade anzeigt und umgekehrt.

    Grüße
    Sascha
    Dateien
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    vielen Dank erstmal. Ich glaube zu verstehen was du meinst und werde es mir morgen im Detail anschauen. Ich war mir schon fast sicher, dass ich das mit dem Zusammenspiel zwischen Model und ViewModel nicht ganz (überhauptnicht) korrekt mache. Ich habe mein Wissen hauptsächlich durch Tutorials (z.B. auch dein Youtube Kanal) versucht selber beizubringen. Daher bin ich dir auch sehr Dankbar, dass du dir die Zeit genommen hast. Ich bin aber auch Dankbar, dass ich mein Geld mit anderen Sachen verdiene und es eher als Hobby betrachte. :)

    Wie gesagt ich schaue es mir morgen an und gebe dann nochmal Feedback.

    Dir einen schönen Abend.

    Lieben Gruß, Chris.
    Kein Problem.

    Nagut, aber MVVM ist auch nicht leicht zu verstehen. Aber hat man den Bogen erstmal raus ist es super.
    Achja, durch die umstrukturierung konnte auch der CodeBehind des Usercontrols in die ViewModel Klasse hinein. Somit gibt es nun keinerlei CodeBehind. Wie es sich gehört.

    Wenn du Fragen zu MVVM hast frag einfach hier. Irgendwer wird dir immer Helfen können.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    Ich beiß mir gerade noch etwas die Zähne aus, um deine Änderung in meinen bestehenden Code zu implementieren.
    EIne generelle Frage zu MVVM. Du meintest das meine Umsetztung so falsch ist, da ich bereits im Model IPropertyChange verwende. Das verstehe ich.
    Ich habe gesehen, dass dein Model kein IPropertyChange beinhaltet. Dafür erstellst du im ViewModel eine Property die das Model als Basis hat.
    Ist es dann richtig, dass ich im ViewModel für jede Property die in der UI angezeigt werden soll die Property des Models nochmal mit IPropertyChangeEvent erstellen muss.
    Bedeutet also, angenommen das Model hat 30 Properties von denen 15 in der UI verwendet werden, dann muss ich im ViewModel nochmal die 15 Properties anlegen? Ist das nicht alles irgendwie doppeltgemoppelt und fehleranfällig im Sinne von Namensänderung etc.?

    Ich finde überall nur Beispiele für MVVM aber nicht kurz und bündig wie man MVVM wirklich Sinnvoll implementiert.

    Lieben GRuß,
    Chris
    Hallo

    Ich verstehe die verwirrung und deine überlegung bez. des "Doppelt gemoppelt".
    Dazu gibt es aber zwei Dinge auf die ich eingehen will.

    Wenn das Model kein INotifyPropertyChanged benötigt erspare ich mir hier schon mal die "FullProperties". Kann also im Model z.b. Public Property Xyz As String schreiben und benötige keinen Getter und keinen Setter.
    Doppelt gemoppelt ist es in dem Sinne nur wenn du die Eigenschaften 1:1 übernimmst. Naja, auch nicht ganz weil du ja noch das Propertychanged Event im Setter wirfst aber ich verstehe was du meinst.

    Bedenke aber folgendes. Oft ist es ja so das man auf das Model bzw. wie dieses aufgebaut ist keinen einfluss hat weil es von einer anderen Anwendung kommt oder man möchte die Daten gar nicht so im UI anzeigen wie diese im Model enthalten sind.

    Beispiel: Ich habe im Model "Person" das Geburtsdatum. Im UI möchte ich nun in einem Feld das Alter angezeigt haben. so habe ich das Property Birthday erst garnicht im ViewModel, sondern die Eigenschaft Age und diese gibt das Alter als Interger zurück. Ist nur ein kleines Beispiel aber ich danke es kommt rüber was ich meine.

    Das Model representiert genau das was gespeichert wird/werden soll und das ViewModel representiert ganz genau das was im UI angezeigt wird. Deshalb View-Model.
    Wenn du noch Fragen hast frag einfach.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo,

    gut, dann habe ich es verstanden sehe aber schon einen gewissen Mehraufwand, wenn man sich Stur an MVVM hält.
    Aber... leider musste ich gerade mit absoluter Verzweifung feststellen, dass der Fehler nichts mit der Struktur oder einer falschen Instanz zu tun hat.
    Im Zuge des kompletten Umbau's, um deine Struktur zu implementieren, habe ich festgestellt, dass ich bei einer Property das RaisePropertsEvent schlicht vergessen habe. Das hatte zur Folge, dass die Server_IP nicht geladen wurde und somit der ganze Ablauf unterbrochen war.

    EIne Zeile Code = 4 Tage arbeit. Es hat sich also erledigt und funktioniert wie es soll. Wow...
    Dennoch Danke ich dir nochmal, da mir durch deinen Code doch eines bewusster geworden ist.
    Jo, ich find dieses doppelt moppeln auch kein guten Stil.
    Und nehme mir daher heraus, MVVM anders zu verstehen.
    Bei mir werden die Schichten Model und Viewmodel nur dann getrennt, wenn es wirklich nötig ist, ein vom Model unterschiedenes Viewmodel zu haben. Solange das Viewmodel nix anneres zu tun hat, als das Model noch einmal zu kapseln, verzichte dich drauf.
    gugge Grundlagen - MVVM-Anwendungs-Struktur

    Schlechten Stil finde ich Doppelmoppelungen deshalb, weil es gegen das "Dont repeat yourself"-Prinzip verstösst.
    Und wenn man solchen Code durchguckt, befällt einen schnell eine massive Ratlosigkeit, wenn man verstehen will, was diese und jene Klassen bezwecken.
    Willkommen in der Welt der Pattern.......
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##