简体   繁体   中英

BindableProperty setter is never called

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.

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);
  }
}

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 use Content.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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM