【问题标题】:Xamarin Forms Custom Picker SelectItem Binding not workingXamarin 表单自定义选择器 SelectItem 绑定不起作用
【发布时间】:2019-08-16 13:33:51
【问题描述】:

我已经使用 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 值绑定始终为空。我输入了 SelectedIndex 绑定作为测试,但它也始终为 0。我确保绑定 ModeTwoWay,但我仍然总是得到一个空的 SelectedItem。任何帮助将不胜感激。

【问题讨论】:

  • 在您的视图模型中提供代码。

标签: xamarin xamarin.forms


【解决方案1】:

您是否在 ViewModel 中实现了 INotifyPropertyChanged

ViewModel 通常实现 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()
    {
        //... 


    }

}

【讨论】:

  • 我的视图模型实现了 INotifyPropertyChanged 接口。如果我直接绑定到选择器,则同样有效,但绑定到自定义选择器中的属性时则无效
  • 您可以提供一个样本,以便我可以在我身边进行测试。
猜你喜欢
  • 2018-02-01
  • 2014-08-22
  • 2021-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-22
  • 1970-01-01
  • 2018-12-25
相关资源
最近更新 更多