I have a WPF view which contains 2 mutually dependent properties; a change in one might trigger a change in the other. How do I write code that cleanly updates both?
More specifically: I have WPF view which makes it possible to export data. That view contains a list of "channels" (that's how I call my data), and for each channel the user can select different file formats for the export. So it is possible to export channel1 to .dat
and .csv
, while channel2 is being exported to .xls
and .csv
, whatever the user selects.
The view also contains a checkbox which indicates whether the channel should be exported at all.
My desired behaviour is:
- If all file formats are unselected, the main checkbox should be unset.
- If any file format is selected, the main checkbox is set.
- If the main checkbox is unset, the list of file formats is unchanged.
- If the main checkbox is set and there is a list of selected formats, it is unchanged.
- if the main checkbox is set and the selected formats list is empty, some default file formats are set.
I don't want to throw RaisePropertyChanged
everywhere, and would like to have somewhat centralized place to deal with the update.
Naive solution:
public bool? IsSelected {
get { return this.isSelected; }
set {
if (this.isSelected != value) {
this.isSelected = value;
if (value == true && this.SelectedFileFormats.Count == 0) {
ApplyDefaultFileFormats();
}
this.RaisePropertyChanged("IsSelected");
}
}
}
public void ApplyDefaultFileFormats() {
this.SelectedFileFormats = // Some logic.
}
public IList<VariableCommandHandler> SelectedFileFormats {
get { return this.selectedFileFormats; }
set {
this.selectedFileFormats = value;
this.UpdatePropertiesRelatedToSelectedHandlers();
this.RaisePropertyChanged("SelectedFileFormats");
this.RaisePropertyChanged("FileName");
}
}
private void UpdatePropertiesRelatedToSelectedHandlers() {
this.IsSelected = (this.selectedFileFormats.Count > 0);
// Do a bunch of other updates, which are derived only from the SelectedHandlers.
}
This works, but I don't like the fact that it is going twice to the IsSelected
setter and just misses on going into an infinite loop. Basically, if IsSelected
is set to true
(while there are no selected file formats), all of the methods above will be invoked. Once in UpdatePropertiesRelatedToSelectedHandlers
the execution will go back to IsSelected
with true
while it is already true
, so the if-statement right in the beginning will be true != true
and the execution will start to return.
I would like a way that is more straightforward, without calling a setter while being in another execution of that same setter.
I have thought of setting the backing fields in the two setters, and then calling RaisePropertyChanged
for both properties from an update method. But this is not the cleanest coding as the setter should be the only place where property changes are being raised.
Any suggestions on a cleaner way to achieve this?