Reputation: 7449
I'm creating a custom control which has an ItemsSource
property:
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable<object>), typeof(RadioButtonsGroup), defaultBindingMode: BindingMode.TwoWay);
public IEnumerable<object> ItemsSource
{
get { return (IEnumerable<object>)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
OnItemsAdded(this, new ItemsAddedEventArgs(value));
}
}
I call the OnItemsAdded
method in the property setter, to initialize the control,
it get called only when I set the property like this:
myCustomControl.ItemsSource = vm.MyList;
but doesn't get called when I set it through data-binding:
<Controls:RadioButtonsGroup ItemsSource="{Binding MyList}" x:Name="myCustomControl"/>
so the control doesn't get the list and isn't initialized at all!
I don't want to use the propertyChanged
delegate, because it's static and I need to use instance members in it.
Upvotes: 1
Views: 573
Reputation: 39082
You need to notify the binding that the MyList
property has changed. If you have the MyList
property in the code-behind of the page (xaml.cs
), it would look like this:
public class Detail : Page, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private List<int> _myList;
public List<int> MyList
{
get => _myList;
set
{
_myList = value;
NotifyPropertyChanged();
}
}
}
As you can see, you don't subscribe to the PropertyChanged
event in the setter, but rather fire it. Behind the scenes the Binding
subscribes to this event and when it is executed it updates the value of the property on your custom control.
To react to property changes, you need to add another parameter to the BindableProperty
definition:
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", ..., propertyChanged: OnItemsSourceChanged);
static void OnEventNameChanged (BindableObject bindable, object oldValue, object newValue)
{
// Property changed implementation goes here
}
There is a nice tutorial on building Custom controls with bindable properties: https://mindofai.github.io/Creating-Custom-Controls-with-Bindable-Properties-in-Xamarin.Forms/
Upvotes: 0
Reputation: 19106
This is an example how you should implement a bindable property, that is a collection
public class RadioButtonsGroup : View
{
public static BindableProperty ItemsSourceProperty = BindableProperty.Create(
propertyName: nameof(ItemsSource),
returnType: typeof(IEnumerable),
declaringType: typeof(RadioButtonsGroup),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnItemsSourceChanged
);
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty,value);
}
// gets called from BindableProperty
// whenever you assign a new value to ItemsSource property
private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
var @this = bindable as RadioButtonsGroup;
// unsubscribe from the old value
var oldNPC = oldValue as INotifyPropertyChanged;
if (oldNPC != null)
{
oldNPC.PropertyChanged -= @this.OnItemsSourcePropertyChanged;
}
var oldNCC = oldValue as INotifyCollectionChanged;
if (oldNCC != null)
{
oldNCC.CollectionChanged -= @this.OnItemsSourceCollectionChanged;
}
// subscribe to the new value
var newNPC = newValue as INotifyPropertyChanged;
if (newNPC != null)
{
newNPC.PropertyChanged += @this.OnItemsSourcePropertyChanged;
}
var newNCC = newValue as INotifyCollectionChanged;
if (newNCC != null)
{
newNCC.CollectionChanged += @this.OnItemsSourceCollectionChanged;
}
// inform the instance to do something
@this.RebuildOnItemsSource();
}
private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// handle the collection changes
throw new NotImplementedException();
}
private void OnItemsSourcePropertyChanged(object sender, PropertyChangedEventArgs e)
{
// handle the property changes
throw new NotImplementedException();
}
private void RebuildOnItemsSource()
{
if (ItemsSource == null)
{
// clear out all
}
else
{
// complete creation of all subviews
}
}
}
Upvotes: 2