MvvmBlazor
MvvmBlazor copied to clipboard
Cascading BindingContext
Is there a way to have cascading BindingContext? Say we have two components:
class ParentComponent: MvvmComponentBase<ParentViewModel> {
ChildComponent Child;
}
class ChildComponent: MvvmComponentBase<ChildViewModel> { }
class ParentViewModel: ViewModelBase {
ChildViewModel Child { get; }
}
class ChildViewModel: ViewModelBase {}
Now I would like to bind the BindingContext of the Child
component in the ParentComponent to the Child
property of the ParentViewModel instance, which is automatically resolved for the ParentComponent. However it seems the view model is always resolved in the component's constructor via DI, and we don't have a public BindingContext
property to override.
One way is to register the view models as Scoped, which is generally not a good idea because it forces all the component instances of the same type to share a single view model instance. I also can always create a new property on the ChildViewModel and bind to that property instead of the BindingContext, but this kind of use case is very common and I think it should be supported by any MVVM framework.
One possible approach is make the BindingContext
property public and [Parameter]
, and make its auto-resolve lazy, so the parent component have a chance to specify the child component's BindingContext as a parameter, before it's being used for the first time.
One possible approach is make the BindingContext property public and [Parameter], and make its auto-resolve lazy, so the parent component have a chance to specify the child component's BindingContext as a parameter, before it's being used for the first time.
Sounds good to me, would love to see a PR with this. Otherwise, I'm gonna implement this.
Right now I'm playing with this idea, but it raises some questions:
- Should the auto-resolve be lazy or should we keep the
SetBindingContext
call in theOnInitialized
method (i.e. the BindingContext can only be set externally before the component is initialized)? - If we set the BindingContext after the component is initialized, should the
OnInitialized
andOnInitializedAsync
be called on the new BindingContext? Same goes to all other lifecycle methods. - Is the BindingContext bindable? If it's changed, should we update all the bindings in the component immediately?
Should the auto-resolve be lazy or should we keep the SetBindingContext call in the OnInitialized method (i.e. the BindingContext can only be set externally before the component is initialized)?
As of now, the BindingContext
is only resolved via DI if there is no binding context present. That would mean that making the property public should be enough to resolve this problem. This way, the lifecycle methods also get called on the right context right away.
Is the BindingContext bindable? If it's changed, should we update all the bindings in the component immediately?
I would argue against the possibility to change the binding context since it would open some potential loop holes. The binding context should be read only once set.
As of now, the
BindingContext
is only resolved via DI if there is no binding context present. That would mean that making the property public should be enough to resolve this problem. This way, the lifecycle methods also get called on the right context right away.
If I'm not mistaken, the view model is set right in the constructor, so it's always present.
I would argue against the possibility to change the binding context since it would open some potential loop holes. The binding context should be read only once set.
For example WPF allows you to change DataContext, you can even bind something to it. But I agree it's not a must-have and for simplicity it's a reasonable design choice to not allow changing the view model.
If I'm not mistaken, the view model is set right in the constructor, so it's always present.
This only applies for the internal constructor that is used for testing. This constructor serves no purpose besides that. When inheriting from MvvmComponentBase<T>
the public constructor will be used. And then the BindingContext
will be resolved on init, if not present.
For example WPF allows you to change DataContext, you can even bind something to it. But I agree it's not a must-have and for simplicity it's a reasonable design choice to not allow changing the view model.
It would be a nice to have thingie, however upon changing the BindingContext
all bindings would need to be redone which could be a bit messy (but doable IMO).
This only applies for the internal constructor that is used for testing. This constructor serves no purpose besides that. When inheriting from
MvvmComponentBase<T>
the public constructor will be used. And then theBindingContext
will be resolved on init, if not present.
Right, I misread the code. So yeah, I agree for now making BindingContext
public could have the job done (and maybe a little protection mechanism to prevent it from changing after OnInitialized
).