Laden...

Lost Binding/Command nach Deserialisierung

Letzter Beitrag vor einem Jahr 7 Posts 559 Views
Lost Binding/Command nach Deserialisierung

Hallo zusammen

Ich habe das Problem, dass ich bei der Deserialisierung mit Json sowohl die Bindings als auch die Commands verliere (vorher funktionieren diese einwandfrei). Das Objekt bekommt die richtigen Daten zwar wieder, diese werden in den einzelnen Controls die sich in einem UserControl befinden aber nicht mehr aktualisiert (Bild im Anhang: Mit "1" und "2" können die UserControls in grün und gelb ein-/ausgeschaltet werden. Die Daten in den Controls kommen von den "Underlying"-Objekten.).

MainWindow.xaml

<uc:UnderlyingsRowHidden Grid.Row="0" Visibility="{Binding Underlying1.RowIsVisible, Converter={StaticResource invertedBooleanToVisibilityConverter}}" />
<uc:UnderlyingsRow Grid.Row="0" 
                              Visibility="{Binding Underlying1.RowIsVisible, Converter={StaticResource booleanToVisibilityConverter}}"
                              Underlying="{Binding Underlying1}"
                              ButtonBuySellUnderlyingCommand="{Binding ButtonBuySellUnderlyingCommand}"
                              CalculateUnderlyingCommand="{Binding CalculateUnderlyingCommand}"
                              ComboBoxColorgroupUnderlyingCommand="{Binding ComboBoxColorgroupUnderlyingCommand}"
                              CalculateCommandParameter="{Binding Underlying1.RowNumber}"/>

MainViewModel.cs

public MainViewModel()
{
ShowUnderlyingsRowCommand = new RelayCommand(ShowUnderlyingsRowExecute, ShowUnderlyingsRowCanExecute);
...
}
private void ButtonLoadExecute(object obj)
{
   ObservableCollection<Underlying> loadedUnderlyingList = PersistenceInstance.Load();
   if (loadedUnderlyingList != null)
   {
       UnderlyingList.Clear();
       foreach (Underlying underlying in loadedUnderlyingList)
       {
           UnderlyingList.Add(underlying);
       }
   }
}

Persistence.cs

public ObservableCollection<Underlying>? Load()
{
   FileStream fs;
   StreamReader sr;
   OpenFileDialog ofd = new OpenFileDialog()
   {
       InitialDirectory = @"C:\Temp",
       Filter = "Json (*.json)|*.json",
       Title = "Datei zum Öffnen auswählen : "
   };
   if (ofd.ShowDialog() == true)
   {
       if (!File.Exists(ofd.FileName))
       {
           MessageBox.Show("Datei " + ofd.FileName + " existiert nicht");
           return null;
       }
       fs = new FileStream(ofd.FileName, FileMode.Open);
       sr = new StreamReader(fs);
       jsonUnderlyingList = sr.ReadLine();
       sr.Close();
   }
   //Liste muss noch auf null geprüft werden, sonst Absturz, wenn zwar geöffnet aber nichts ausgewählt wird.
   ObservableCollection<Underlying>? newUnderlyingList = JsonConvert.DeserializeObject<ObservableCollection<Underlying>>(jsonUnderlyingList);
   return newUnderlyingList;
}

RelayCommand.cs

public class RelayCommand : ICommand
{
   //Private Fields
   private readonly Action<object> _executedHandler;
   private readonly Predicate<object> _canExecuteHandler;
   private Action onButtonPressed;
   //Constructors
   public RelayCommand(Action<object> execute) : this(execute, null)
   {
   }
   public RelayCommand(Action<object> execute, Predicate<object> canExecute)
   {
       if (execute == null)
           throw new ArgumentNullException("Execute kann nicht null sein");
       _executedHandler = execute;
       _canExecuteHandler = canExecute;
   }
   public RelayCommand(Action onButtonPressed)
   {
       this.onButtonPressed = onButtonPressed;
   }              
   //Methods
   public void Execute(object parameter)
   {
       _executedHandler(parameter);
   }
   public bool CanExecute(object parameter)
   {
       if (_canExecuteHandler == null)
           return true;
       return _canExecuteHandler(parameter);
   }
   //Events
   public event EventHandler? CanExecuteChanged
   {
       add { CommandManager.RequerySuggested += value; }
       remove { CommandManager.RequerySuggested -= value; }
   }
}

Vielen Dank für eure Hilfe!

  • Wieso zeigst du uns nicht wie UnderlyingList deklariert ist?
  • Wieso deserialisierst du eine ObservableCollection obwohl du diese niemals als Observable einsetzt? Ein Array hätte hier gereicht.
  • Die Deklaration der Underlying Klasse wäre auch hilfreich, fehlt aber.
  • Du bindest an Underlying1 - was auch immer das sein soll und wie auch immer das gefüllt wird.

Und nur am Rand bemerkt:

Bei der Load Methode vermengst du UI mit Infrastruktur und Präsentation. Besser wäre im ViewModel ein LoadCommand der als CommandParameter die gewählte Datei übergeben bekommt. In der View rufst du den Dialog auf und wenn das erfolgreich war, dann führst du den LoadCommand aus. Und ja, das kommt in das Code-Behind der View und ist nicht schlimm.

Hat die Blume einen Knick, war der Schmetterling zu dick.

Deklaration der UnderlyingList

UnderlyingList = new ObservableCollection<Underlying>()
{
   Underlying1, Underlying2
};

Deklaration der 2 Underlying-Objekte

Underlying1 = new Underlying() 
{                
   DivDate = DivDate,
   DivAmount = DivAmount,
   VrfList = { new DateTime(2023, 01, 20), new DateTime(2025, 11, 28) },
   
   RowNumber = 1,
   RowIsVisible = true,
   BS = 'K',               
   Hdt = new DateTime(2022, 05, 21),
   Prjd = new DateTime(2022, 05, 21),
   Vrf = new DateTime(2025, 11, 28),
   KUl = 68.63f,                
   Ka = 1,
   BzvhO = 100.00f,               
   Vortrag = 0f,
   Colorgroup = IAsset.Group.B
};
Underlying2 = new Underlying() 
{
   DivDate = DivDate,
   DivAmount = DivAmount,
   VrfList = { new DateTime(2023, 01, 20), new DateTime(2025, 11, 28) },
   RowNumber = 2,
   RowIsVisible = true,
   BS = 'K',
   Hdt = new DateTime(2022, 05, 21),
   Prjd = new DateTime(2022, 05, 21),
   Vrf = new DateTime(2025, 11, 28),
   KUl = 68.63f,
   Ka = 1,
   BzvhO = 100.00f,
   Vortrag = 0f,
   Colorgroup = IAsset.Group.C
};

Hoffe das hilft für das Verständnis vom Gesamten weiter.

Besten Dank auch für deine Randbemerkung, die ich gerne noch studieren werden.

Du hast da eine Liste UnderlyingList die du leerst und wieder füllst, die aber in der View nicht verwendet wird (oder willst du das nicht zeigen?).

Du hast zwei Eigenschaften Underlying1 und Underlying2 wo es in der View eine Bindung mit der ersten gibt, diese werden aber in der ButtonLoadExecute Methode nicht aktualisiert.

Und nun erwartest du das die View darauf irgendwie reagiert. Warum?

Hat die Blume einen Knick, war der Schmetterling zu dick.

Die ListeUnderlyingListwird in der View tatsächlich nicht verwendet (diese benötige ich im ViewModel).

Underlying1 und Underlying2 haben in der View beide eine Bindung (im geposteten Code aber nur Underlying1 ersichtlich). Das diese beiden nicht aktualisiert werden ist genau mein Problem, dass ich nicht zu lösen weiss. Für Terminerinnerungen habe ich in einem anderen Teil des Programms nahezu denselben (nachfolgenden) Code, er funktioniert und die View aktualisiert sich nach dem Aufruf der "Load"-Methode. Der einzige Unterschied ist, dass die dort verwendeten Controls nicht in einem UserControl eingebettet sind.

ObservableCollection<Reminder> loadedReminderList = PersistenceInstance.Load();
if (loadedReminderList != null)
{
   ReminderList.Clear();
   foreach (Reminder reminder in loadedReminderList)
   {
       ReminderList.Add(reminder);
   }
}

Dir ist schon bewusst, dass wir keine Möglichkeit haben auf deinen Bildschirm oder deine Festplatte zu schauen?

Warum zeigst du uns nicht eine abgespeckte aber in sich lauffähige Version die (nur) dein Problem zeigt? Es ist sehr ermüdend jeden Popel einzeln aus der Nase heraus zu ziehen nur um festzustellen, dass da noch mehr ist was relevant aber für uns unbekannt ist.

In solch einer abgespeckten Version entfernt man z.B. dieses ganze Dialog und Datei Geraffel und liefert einfach eine statisches oder generiertes Ergebnis zurück.

Hat die Blume einen Knick, war der Schmetterling zu dick.

Hallo TreaxP,

dein Fehler ist, daß du direkt an Underlying1 bzw. Underlying2 bindest, anstatt nur an die UnderlyingList.

Sobald du diese Liste wieder neu erzeugst (per Deserialisierung), bleiben die Referenzen zu Underlying1 bzw. Underlying2bestehen (d.h. sie zeigen immer noch auf die ursprünglichen Daten).

Du mußt also konsequent an UnderlyingList binden:

Underlying="{Binding UnderlyingList[0]}"

Oder alternativ nach der Deserialisierung Underlying1 bzw. Underlying2neu zuweisen (bzw. diese als Eigenschaften erstellen und im Getter auf UnderlyingList[X] verweisen).