Reputation: 379
As we know, RelayCommand
and getter-only properties need to be notified when their dependencies change. That is usually done with NotifyCanExecuteChangedForAttribute
and NotifyPropertyChangedForAttribute
.
But what needs to be done in cases when we access nested object fields, and not primitive types? I know that those classes also need to implement INotifyPropertyChanged
. But that is not enough here, because that event isn't propagated to cause reevaluation of CanExecute
method.
Here is an example:
There is an object of Bill.Item
class that implements INotifyPropertyChanged
(I have tried to use both ObservableObject
and Fody.PropertyChange, but there is no difference).
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
[NotifyPropertyChangedFor(nameof(NotEnoughDrinks))]
private Bill.Item billItem;
Its properties are updated through UI with XAML two-way bindings:
<Entry Placeholder="Title" Text="{Binding BillItem.Title}" />
...
<HorizontalStackLayout>
<Entry Placeholder="Quantity" Text="{Binding BillItem.Quantity}" IsReadOnly="True" />
<Stepper Value="{Binding BillItem.Quantity}" Minimum="1" Increment="1" />
</HorizontalStackLayout>
SaveCommand
and NotEnoughDrinks
property depend on fields inside BillItem
.
public bool NotEnoughDrinks => ChosenDrink?.Quantity < BillItem.Quantity;
[RelayCommand(CanExecute = nameof(IsSaveable))]
private void Save() {
OnClose?.Invoke(BillItem);
}
private bool IsSaveable() {
if (string.IsNullOrWhiteSpace(BillItem.Title)) return false;
return true;
}
I have found a workaround, by subscribing to PropertyChanged
event and manually invoking OnPropertyChanged
and NotifyCanExecuteChanged
. Unfortunately that solution produces COMException
and TargetInvocationException
from time to time, and I am unable to find the root cause, or any message related to those exceptions. And except from that issue, I assume that this solution is not idiomatic enough because it makes code more complex.
partial void OnBillItemChanged(Bill.Item? oldValue, Bill.Item newValue)
{
void OnBillItemPropertyChanged(object? sender, PropertyChangedEventArgs args)
{
try
{
OnPropertyChanged(nameof(NotEnoughDrinks));
SaveCommand.NotifyCanExecuteChanged();
}
catch (Exception) {}
}
if (oldValue is not null)
oldValue.PropertyChanged -= OnBillItemPropertyChanged;
if (newValue is not null)
newValue.PropertyChanged += OnBillItemPropertyChanged;
}
Is there anything that I am missing, for example an attribute, that is useful for these cases when I need to handle updates of nested ObservableObject
fields? Or I really need to stick to workarounds like the one shown above?
Upvotes: 0
Views: 115