I have a binding in my ListView
's ItemTemplate,
<ListView ItemsSource="{Binding Capsules}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<views:CapsuleWidgetView Model="{Binding}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And in my CapsuleWidgetView component, I have
public CapsuleWidgetViewModel ViewModel => (CapsuleWidgetViewModel)BindingContext;
public CapsuleModel Model
{
get => (CapsuleModel)GetValue(ModelProperty);
set => SetValue(ModelProperty, value);
}
public static readonly BindableProperty ModelProperty = BindableProperty.Create(
nameof(Model),
typeof(CapsuleModel),
typeof(CapsuleWidgetView),
propertyChanged: (bindable, value, newValue) =>
{
var view = (CapsuleWidgetView)bindable;
var modelValue = (CapsuleModel)newValue;
view.ViewModel.Capsule = modelValue;
});
Whenever the bound collection for my ListView
changes, the items are regenerated as expected. However, each Model
is always null, and the property setter is never called. Not from the ModelProperty
propertyChanged, nor my defined setter method. I've confirmed this with the debugger and attempted logging.
I originally thought my problem was from the binding being null, but this doesn't seem to be the case. Another test where I access the bound object's properties succeeds. Even then, the source collection will never have a null object added to it.
However, a CapsuleModel
directly defined in Xaml works A-OK.
<views:CapsuleWidgetView>
<views:CapsuleWidgetView.Model>
<models:CapsuleModel Name="Hello?"/>
</views:CapsuleWidgetView.Model>
</views:CapsuleWidgetView>
Referencing the properties of the model and binding them to something like Label.Text
works, I'm sure the problem stems from my BindableProperty
and/or BindingContext
. Nothing seems wrong with either, though.
CodePudding user response:
Why doesn't the <views:CapsuleWidgetView Model="{Binding}"/>
have a binding property name such as <views:CapsuleWidgetView Model="{Binding Model}"/>
?
In the viewmodel:
[ObservableProperty]
private ObservableCollection<Capsule> Capsules;
And in the model:
public class Capsule : ObservableObject
{
private CapsuleModel model;
public CapsuleModel Model
{
get => model;
set => SetProperty(ref model, value);
}
}
CodePudding user response:
To quote this answer,
Never do
BindingContext = this;
in your ContentView, as it hijacks the context from the Page trying to databind to it. Instead useContent.BindingContext = this;
In my case, the BindingContext
was being set in Xaml, which would be equivalent to BindingContext = this;
. I simply removed it and added it to my constructor like so,
public CapsuleWidgetView()
{
InitializeComponent();
Content.BindingContext = new CapsuleWidgetViewModel();
}
Note that it can't be placed above InitializeComponent
because the Content
hasn't actually been created yet.