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!
UnderlyingList
deklariert ist?ObservableCollection
obwohl du diese niemals als Observable einsetzt? Ein Array hätte hier gereicht.Underlying
Klasse wäre auch hilfreich, fehlt aber.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. Underlying2
bestehen (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. Underlying2
neu zuweisen (bzw. diese als Eigenschaften erstellen und im Getter auf UnderlyingList[X]
verweisen).