Xamarin表单自定义选择器SelectItem绑定不起作用

时间:2019-08-16 13:33:51

标签: xamarin xamarin.forms

我已经使用xaml创建了一个自定义选择器控件PCPicker(考虑到将来的兼容性,请注意以下内容):

<Label x:Name="ControlLabel"
               Style="{DynamicResource InputLabel}"
               Text="{Binding LabelText}"/>
        <Picker x:Name="ControlPicker"
                ItemsSource="{Binding Src}"
                Title="{Binding PlaceHolderText}"
                Style="{DynamicResource PCPickerStyle}"
                SelectedIndex="{Binding Index,Mode=TwoWay}"
                SelectedItem="{Binding SelectedOption,Mode=OneWayToSource}"
                />

后面的代码如下:

[XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class PCPicker : ContentView
    {
        public static readonly BindableProperty LabelTextProperty =
            BindableProperty.Create(
                propertyName: nameof(LabelText),
                returnType: typeof(string),
                declaringType: typeof(PCPicker),
                defaultValue: "",
                defaultBindingMode: BindingMode.TwoWay,
                propertyChanged: LabelTextPropertyChanged);

        public string LabelText
        {
            get { return GetValue(LabelTextProperty).ToString(); }
            set { SetValue(LabelTextProperty, value); }
        }

        private static void LabelTextPropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (PCPicker)bindable;
            control.ControlLabel.Text = newValue.ToString();
        }

        public static readonly BindableProperty PlaceHolderTextProperty =
            BindableProperty.Create(
                propertyName: nameof(PlaceHolderText),
                returnType: typeof(string),
                declaringType: typeof(PCPicker),
                defaultValue: "",
                defaultBindingMode: BindingMode.TwoWay,
                propertyChanged: PlaceHolderTextPropertyChanged);

        public string PlaceHolderText
        {
            get { return GetValue(PlaceHolderTextProperty).ToString(); }
            set { SetValue(PlaceHolderTextProperty, value); }
        }

        private static void PlaceHolderTextPropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (PCPicker)bindable;
            control.ControlPicker.Title = newValue.ToString();
        }

        public static readonly BindableProperty SelectedOptionProperty =
            BindableProperty.Create(
                propertyName: nameof(SelectedOption),
                returnType: typeof(object),
                declaringType: typeof(PCPicker),
                defaultValue: null,
                defaultBindingMode: BindingMode.TwoWay,
                propertyChanged: SelectedOptionChanged);

        public object SelectedOption
        {
            get { return GetValue(SelectedOptionProperty); }
            set { SetValue(SelectedOptionProperty, value); }
        }

        private static void SelectedOptionChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (PCPicker)bindable;
            control.ControlPicker.SelectedItem = newValue;
        }


        public static readonly BindableProperty SrcProperty =
            BindableProperty.Create(
                propertyName: nameof(Src),
                returnType: typeof(IList),
                declaringType: typeof(PCPicker),
                defaultValue: null,
                defaultBindingMode: BindingMode.TwoWay,
                propertyChanged: PickerSourceChanged);

        public IList Src
        {
            get { return (IList)GetValue(SrcProperty); }
            set { SetValue(SrcProperty, value); }
        }

        private static void PickerSourceChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (PCPicker)bindable;
            control.ControlPicker.ItemsSource = (IList)newValue;
        }

        public static readonly BindableProperty IndexProperty =
            BindableProperty.Create(
                propertyName: nameof(Index),
                returnType: typeof(int),
                declaringType: typeof(PCPicker),
                defaultValue: -1,
                defaultBindingMode: BindingMode.TwoWay,
                propertyChanged: SelectedIndexChanged);


        public int Index
        {
            get { return (int)GetValue(IndexProperty); }
            set { SetValue(IndexProperty, value); }
        }

        private static void SelectedIndexChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (PCPicker)bindable;
            control.ControlPicker.SelectedIndex = (int)newValue;
        }

        public BindingBase DisplayMember
        {
            get { return ControlPicker.ItemDisplayBinding; }
            set { ControlPicker.ItemDisplayBinding = value; }
        }

        public PCPicker()
        {
            InitializeComponent();
        }

    }

用法:

<cc:PCPicker BindingContext="{x:Binding M}" 
                             LabelText="* Location" 
                             PlaceHolderText="Select Cat"
                             Src="{Binding Cats}"
                             SelectedOption="{Binding SelectedCat, Mode=TwoWay}"
                             Index="{Binding Position, Mode=TwoWay}"
                             DisplayMember="{Binding Name}"/>

通过上面的内容,我可以使Display Binding和ItemSource绑定起作用。但是,SelectedItem值绑定始终为null。我输入了SelectedIndex绑定作为测试,但它始终始终为0。我确保绑定ModeTwoWay,但我仍然始终得到一个空的SelectedItem。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

您是否在ViewModel中实现了 INotifyPropertyChanged

ViewModels通常实现INotifyPropertyChanged接口,这意味着该类在其属性之一发生更改时会触发PropertyChanged事件。 Xamarin.Forms中的数据绑定机制将处理程序附加到此PropertyChanged事件,以便可以在属性更改时得到通知,并使目标保持新值。

因此您可以按照以下方式改进视频模型

public class MyViewModel: INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    ObservableCollection<Cat> Cats { get; set; }

    private Cat selectedCat;
    public Cat SelectedCat
    {
        get
        {
            return selectedCat;
        }
        set
        {
            if (selectedCat != value)
            {
                selectedCat = value;
                NotifyPropertyChanged();

                // do something you want 

            }
        }
    }

    private int position=0;
    public int Position
    {
        get
        {
            return position;
        }
        set
        {
            if (position != value)
            {
                position = value;
                NotifyPropertyChanged();
            }
        }
    }

    public MyViewModel()
    {
        //... 


    }

}