Correct Way to Define a Custom Bindable Property of Type ObservableCollection in Xamarin

422 Views Asked by At

I need to react to the content of an ObservableCollection's property changing. I define the property like this:

public static readonly BindableProperty MyCollectionProperty = BindableProperty.Create(
    nameof(MyContentView.MyCollection),
    typeof(ObservableCollection<object>),
    typeof(MyContentView),
    propertyChanged: OnMyCollectionPropertyChanged);

public ObservableCollection<object> MyCollection
{
    get => (ObservableCollection<object>)GetValue(MyContentView.MyCollectionProperty);
    set => SetValue(MyContentView.MyCollectionProperty, value);
}

private static void OnMyCollectionPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
{
    // Do Something
}

The method OnMyCollectionPropertyChanged is called when the whole bound collection object changes (i.e. a completely new collection) but of course not when the collection's content changes.

What is the correct way to react to the events of the INotifyCollectionChanged interface implemented by ObservableCollection? Do I need to manually sign up for them when the collection object is assigned or is there a syntax of BindableProperty.Create() which allows to do so directly, something similar to the propertyChanged method?

1

There are 1 best solutions below

1
On

I make a code sample of Custom BindableProperty for Type ObservableCollection for your reference.

ContentView:

 <ContentView.Content>
    <StackLayout>
        <ListView x:Name="listview1" ItemsSource="{Binding Items}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label Text="{Binding Name}" />

                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentView.Content>

public partial class View1 : ContentView
{
    public ObservableCollection<object> Items
    {
        get { return (ObservableCollection<object>)GetValue(ItemsProperty); }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }
    public static BindableProperty ItemsProperty = BindableProperty.Create("ItemsSource", 
                                                                            typeof(ObservableCollection<object>), 
                                                                            typeof(View1), 
                                                                            null, 
                                                                            BindingMode.TwoWay, 
                                                                            propertyChanged: (bindable, oldValue, newValue) => OnItemsSourceChanged(bindable, oldValue, newValue));

    private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (View1)bindable;
        control.listview1.ItemsSource = (ObservableCollection<object>)newValue;
    }

    public View1()
    {
        InitializeComponent();
    }
}

Useage:

Xaml:

<ContentPage.Content>
    <local:View1 Items="{Binding models}" />
</ContentPage.Content>

Code behind:

public partial class Page17 : ContentPage
{
    public ObservableCollection<object> models { get; set; }

    public Page17()
    {
        InitializeComponent();
        models = new ObservableCollection<object>()
        { 
            new modela(){Name="A" },
            new modela(){Name="B" }
        };
        this.BindingContext = this;
    }
}
public class modela
{
    public string Name { get; set; }
   
}