绑定表达式在Xamarin中执行的位置是什么?

时间:2017-12-10 08:02:16

标签: c# xamarin mvvm data-binding xamarin.forms

我正在创建一个具有ItemsSource属性的自定义控件:

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

我在属性设置器中调用OnItemsAdded方法来初始化控件, 只有当我像这样设置属性时才会调用它:

myCustomControl.ItemsSource = vm.MyList;

但是当我通过数据绑定设置它时,它不会被调用:

<Controls:RadioButtonsGroup ItemsSource="{Binding MyList}" x:Name="myCustomControl"/>

因此控件无法获取列表并且根本没有初始化!

我不想使用propertyChanged委托,因为它是静态的,我需要在其中使用实例成员。

2 个答案:

答案 0 :(得分:2)

这是一个如何实现可绑定属性的示例,即集合

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

答案 1 :(得分:0)

您需要通知绑定MyList属性已更改。如果您在页面代码隐藏(MyList)中有xaml.cs属性,它将如下所示:

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

正如您所看到的,您不会在setter中订阅PropertyChanged事件,而是将其激活。在幕后,Binding订阅此事件,当它被执行时,它会更新自定义控件上的属性值。

要对属性更改做出反应,您需要在BindableProperty定义中添加另一个参数:

public static readonly BindableProperty ItemsSourceProperty = 
BindableProperty.Create("ItemsSource", ..., propertyChanged: OnItemsSourceChanged);

static void OnEventNameChanged (BindableObject bindable, object oldValue, object newValue)
{
    // Property changed implementation goes here
}

有一个很好的教程,用于构建具有可绑定属性的自定义控件:https://mindofai.github.io/Creating-Custom-Controls-with-Bindable-Properties-in-Xamarin.Forms/