Laden...

Data Binding eines Arrays im MVVM ohne Arrayindize

Erstellt von Daimonion1980 vor 5 Jahren Letzter Beitrag vor 5 Jahren 2.093 Views
D
Daimonion1980 Themenstarter:in
6 Beiträge seit 2019
vor 5 Jahren
Data Binding eines Arrays im MVVM ohne Arrayindize

Hallo Leute.

Ich muss mich mal an euch wenden, da ich an einer Stelle in einem C# Projekt nicht weiterkomme.

Zuvor, ich bin gerade dabei mich in C# neu einzulernen, da meine letzten Kontakte damit 13 Jahre zurück liegen. Daher vermute ich auch dass ich schlichtweg irgendeinen Ansatz übersehen habe, was mein Problem verursacht.

Ausgangslage ist ein Stück Code mit dem ich versuche Werte aus einer Collection von Parametern zu laden. dieser Code wurde vom ExKollegen implementiert und hat die Besonderheit, dass ich pro anzuzeigenden Parameter, die im Code als ObserveableCollection gespeichert sind, 8 Zugriffe auf diesen Wert habe. Das XAML, welches die Collection nutzt bekommt sie via DataBinding zur Verfügung gestellt.

Implementiert wurde es wie in diesem StackOverflowArtikel beschrieben:

https://stackoverflow.com/a/5415971/1425795

private ObservableCollection<Parameters> arr = new ObservableCollection<Parameters>();

The elements in Arr would need to implement INotifyPropertyChanged though in order to dynamically update.

Update: To elaborate a bit more:

public class MyDouble : INotifyPropertyChanged  
{  
    public event PropertyChangedEventHandler PropertyChanged;  
  
    private double _Value;  
    public double Value   
    {   
        get { return _Value; }   
        set { _Value = value; OnPropertyChanged("Value"); }  
    }  
  
    void OnPropertyChanged(string propertyName)  
    {  
       var handler = PropertyChanged;  
       if (handler != null)  
       {  
          handler(this, new PropertyChangedEventArgs(propertyName));  
       }  
    }  
}   

and then

 ObservableCollection<MyDouble> Arr { get; set; }   

and bind to

 <TextBlock Name="testBox" Text="{Binding Path=Arr[0].Value}"/>   

Nun stand ich vor der Herausforderung, dass ich die Parameter neu strukturieren und teilweise neue Parameter hinzufügen soll.
Neben dem ersten Gedanken, warum hat der Kerle die Parameterstruktur im UserControl nicht grundsätzlich dynamisch erzeugt, habe ich keinen Bock gehabt für alle Parameter mehrmals die Arrayindizes zu ändern.
Nun gut, also habe ich versucht das ganze logisch zu vereinfachen.

Ich habe den DataContext um eine neue Variable erweitert


this.DataContext = new
            {
                This = this,
                .....
                
            };

Weiterhin habe ich ein neues Property in das UserControl eingefügt:

        public Parameter Arrayindize1
        {
            get { return Arr[10]; }
        }

Und Im Xaml habe ich dann den Code an den Zugriffstellen so abgeändert.

<TextBlock Name="testBox" Text="{Binding This.Arrayindize1.Value}"/>

Dadurch hatte ich nun initial ein wenig Aufwand alle direkten Arrayzugriffe abzuändern, aber zukünftig muss ich nur noch für jeden zu ändernden Parameter einen Indexzugriff ändern und brauche nicht mehr aufwendig suchen. Später soll das dann auch mal komplett dynamisch werden.

Nun zu meinem eigentlichen Problem.

Diese Art des Zugriffes funktioniert komischerweise nicht zuverlässig. Ich habe mehrere UserControls und Collections mit diesem Set. Bei einigen habe ich allerdings das Problem dass mir die TextBox den Wert nicht aktualisiert wenn er im Code aktualisiert wird. Es scheint als greift das System dann einfach nicht auf den Wert zu.

Ändere ich das UserControl wieder auf die alte Schreibeweise, also

<TextBlock Name="testBox" Text="{Binding Arr[10].Value}"/>

so wird mir Value sofort wieder korrekt in die Textbox reingeschrieben.

Es kann sehr wohl sein, dass ich bei meiner ganzen Kopieraktion und Neustrukturierung einen Fehler gemacht habe, aber mich würde mal Interessieren ob das Prinzip, grundsätzlich so funktioniert oder ob es vielleicht auch noch eleganter gelöst werden kann?

Danke schon mal für euer offenes Ohr und vielleicht fällt jemandem was dazu ein.

Grüße
Daimonion

5.658 Beiträge seit 2006
vor 5 Jahren

Hi Daimonion1980,

leider verstehe ich deine Frage nicht, weil du auch keinen Kontext gibst. Interessant sind eigentlich nicht deine Umsetzungsversuche, sondern deine Anforderungen, die du damit umsetzen möchtest.

Was der SO-Beitrag mit der Frage zu tun hat, erschließt sich mir auch nicht ganz.

Du hast eine ObservableCollection im ViewModel und du hast in der View irgendein ItemsControl, an das du die Collection bindest. Mehr braucht man eigentlich nicht.

Hier gibt es mehr Details: [Artikel] MVVM und DataBinding

Weeks of programming can save you hours of planning

D
Daimonion1980 Themenstarter:in
6 Beiträge seit 2019
vor 5 Jahren

Hallo

Ja ich gebe zu das ist alles ein wenig wirr. Ich hab gehofft dass es nicht notwendig ist den ganzen Kontext hier darzulegen. Aber ja, es sind komplexe Themen und so ist die Information schon wichtig.

Ich versuche es nochmal schnell auf Basis des SO Beitrags zusammenzufassen und meine Frage zu stellen.

Wenn ich eine ObserveableCollection mittels DataContext so in das UserControl einbinde, das folgender Code den Wert in einem Textfeld aktualisiert, wenn er z.B. über einen anderen Thread (serielle Kommunikation liest einen Wert aus und schreibt ihn in Value) geändert wird:

<TextBlock Name="testBox" Text="{Binding Arr[10].Value}"/>

funktioniert eine Aktualisierung des Wertes Value in die Textbox rein auch wenn der Code so implementiert wird

<TextBlock Name="testBox" Text="{Binding This.Para1.Value}"/>

Wenn im ViewModel dafür sorge getragen wird das This aufgelöst wird und das ein Property Para1 existiert?


        public Constructor()
        {
            InitializeComponent();

            this.DataContext = new
            {
                This = this
            };

        }

        public Parameter Para1
        {
            get { return Arr[10]; }
        }
      

Bei mir im Code funktioniert eine Werteaktualisierung (weil meine ObserveableCollection INotifyPropertyChanged implementiert) für den 1. angegebenen Fall. Ich möchte aber den zweiten Fall implementieren.

Ich hoffe das Problem wird ein wenig klarer.

Deinen Link zu Databindings werde ich mir auf jeden Fall mal durchlesen. Ganz so 100%ig bin ich noch nicht durchgestiegen.

5.658 Beiträge seit 2006
vor 5 Jahren

Ich verstehe immernoch nicht, warum du überhaupt auf das Array-Element per Index zugreifen willst. Und wozu du eine Referenz namens This mitgeben willst. Wenn so etwas erforderlich ist, stimmt etwas Grundsätzliches nicht an deiner Architektur.

Wie gesagt:

Du hast eine ObservableCollection im ViewModel und du hast in der View irgendein ItemsControl, an das du die Collection bindest. Mehr braucht man eigentlich nicht.

Man muß da nicht unbedingt das Rad neu erfinden.

Weeks of programming can save you hours of planning

D
Daimonion1980 Themenstarter:in
6 Beiträge seit 2019
vor 5 Jahren

Hmm, okay.

Ich arbeite mich gerade in die SW ein, die der, Kollege hinterlassen hat.

Daher ist die Architektur und die Typen erst mal so vorgegeben. Das wird sich in Zukunft sicherlich ändern.

Das Projekt ist eine Parametriersoftware für Antriebe. Die haben gewöhnlicherweise mehrere Parameter (über 100 in unserem Fall)

Diese Parameter werden über die serielle Schnittstelle ausgelesen und mittels der ObserveableCollection verwaltet.

Die Parameter werden dann im UserControl angezeigt, können verändert werden und werden irgendwann wieder per serielle Schnittstelle auf den Antrieb gespielt und dort dann auch gespeichert.

Die Visualisierung ins View hinein funktioniert, wie gesagt, aktuell so wie in dem SO Beitrag.

Ich kann verstehen dass du mein Geschwaffel in der Gänze nicht verstehst. 😉

Danke dir auf jeden Fall für deine Unterstützung

Grüße
Daimonion

W
955 Beiträge seit 2010
vor 5 Jahren

Bei einigen habe ich allerdings das Problem dass mir die TextBox den Wert nicht aktualisiert wenn er im Code aktualisiert wird. Du musst sicherstellen das NotifyPropertyChanged bis zum View durchkommt. Wenn du beispielsweise die Kette Model -> ViewModel -> View hast und im Model was änderst wird die View erst aktualisiert wenn das ViewModel das Event weiter zur View schmeißt. Mit deinem Konstrukt baust du eine solche dritte Schicht ein.
Wäre es nicht besser das richtig mit Properties abzubilden?
* ein Objekt liest den Byte-Stream auf, parst diesen und bildet ein Modellobjekt mit fest definierten Properties wie XOffset, YPosition oder was du da brauchst. Diese können dann über ein ViewModel an die View gebunden werden. Dann ist es auch einfacher das Ding zu erweitern.

D
Daimonion1980 Themenstarter:in
6 Beiträge seit 2019
vor 5 Jahren

Du musst sicherstellen das NotifyPropertyChanged bis zum View durchkommt. Wenn du beispielsweise die Kette Model -> ViewModel -> View hast und im Model was änderst wird die View erst aktualisiert wenn das ViewModel das Event weiter zur View schmeißt. Mit deinem Konstrukt baust du eine solche dritte Schicht ein.

Hallo witte

Genau so was hab ich mir schon gedacht. Danke für die Bestätigung.

Wäre es nicht besser das richtig mit Properties abzubilden?
* ein Objekt liest den Byte-Stream auf, parst diesen und bildet ein Modellobjekt mit fest definierten Properties wie XOffset, YPosition oder was du da brauchst. Diese können dann über ein ViewModel an die View gebunden werden. Dann ist es auch einfacher das Ding zu erweitern.

Ich verstehe grob was du sagst, und ich gebe dir recht. Es wäre eh schon mein nächster Punkt gewesen zu Fragen wie man so was korrekterweise löst.

Gibt es dazu evtl. noch ein wenig Literatur wo ich mir das nochmal erarbeiten kann? Mein WPF Buch kommt erst kommende Woche...

Danke auf jeden Fall mal für eure Mühen.

Grüße
Daimonion