Xamarin Forms - 选择器 selectedItem 未触发

Xamarin Forms - picker selectedItem not firing

以下示例工作正常 (https://developer.xamarin.com/samples/xamarin-forms/UserInterface/BindablePicker/)

当我尝试在我的代码中实现它时,未设置为 selectedItem 引用的对象。选择器正在加载和选择数据,只是没有更新对象。

这是我正在使用的一些代码: XAML页数

 <Picker x:Name="testpicker" Title="Select a Service" ItemsSource="{Binding Services}, Mode=TwoWay}" ItemDisplayBinding="{Binding ServiceDescription}" SelectedItem="{Binding SelectedServiceName, Mode=TwoWay}" />

我在视图模型中有对象,但在选择选取器项时从未调用它。:

string selectedServiceName;
    public string SelectedServiceName
    {
        get { return selectedServiceName; }
        set
        {
            if (selectedServiceName != value)
            {
                selectedServiceName = value;
                PickerOnPropertyChanged();
                PickerOnPropertyChanged("SelectedService");
            }
        }
    }

顺便说一下,绑定是在视图加载时从控制器完成的....

  protected async override void OnAppearing()
    {

        base.OnAppearing();
        await viewModel.LoadPreferenceData();
        await viewModel.LoadServiceData();

        testpicker.SelectedIndex = 5;

    }

我还更新了基础 class 以反映教程,我更改了名称。

你能看出为什么这不起作用吗?如果需要,我很乐意提供更多代码。

创建自定义选择器并在您的代码中实现它对我有用请尝试以下代码:

public class CustomPicker : Picker
    {
        public CustomPicker()
        {
            SelectedIndexChanged += OnSelectedIndexChanged;
        }

        public static readonly BindableProperty SelectedItemProperty =
            BindableProperty.Create("SelectedItem", typeof(object), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnSelectedItemChanged);

        public object SelectedItem
        {
            get { return GetValue(SelectedItemProperty); }
            set
            {
                SetValue(SelectedItemProperty, value);

                if (value != null &&  ItemsSource!=null && ItemsSource.Contains(value))
                    SelectedIndex = ItemsSource.IndexOf(value);
                else
                    SelectedIndex = -1;
            }
        }

        public static readonly BindableProperty ItemsSourceProperty =
            BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnItemsSourceChanged);

        public IList ItemsSource
        {
            get { return (IList)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly BindableProperty DisplayPropertyProperty =
            BindableProperty.Create("DisplayProperty", typeof(string), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnDisplayPropertyChanged);


        public string DisplayProperty
        {
            get { return (string)GetValue(DisplayPropertyProperty); }
            set { SetValue(DisplayPropertyProperty, value); }
        }
        private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var picker = (CustomPicker)bindable;
            picker.SelectedItem = newValue;
            if (picker.ItemsSource != null && picker.SelectedItem != null)
            {
                var count = 0;
                foreach (var obj in picker.ItemsSource)
                {
                    if (obj == picker.SelectedItem)
                    {
                        picker.SelectedIndex = count;
                        break;
                    }
                    count++;
                }
            }
        }

        private static void OnDisplayPropertyChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var picker = (CustomPicker)bindable;
            picker.DisplayProperty = (string)newValue;
            LoadItemsAndSetSelected(bindable);
        }

        private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var picker = (CustomPicker)bindable;
            picker.ItemsSource = (IList)newValue;

            var oc = newValue as INotifyCollectionChanged;

            if (oc != null)
            {
                oc.CollectionChanged += (a, b) =>
                {
                    LoadItemsAndSetSelected(bindable);
                };
            }

            LoadItemsAndSetSelected(bindable);
        }

        private static void LoadItemsAndSetSelected(BindableObject bindable)
        {
            var picker = (CustomPicker)bindable;

            if (picker.ItemsSource == null)
                return;

            var count = 0;

            foreach (var obj in picker.ItemsSource)
            {
                var value = string.Empty;
                if (picker.DisplayProperty != null)
                {
                    var prop = obj.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, picker.DisplayProperty, StringComparison.OrdinalIgnoreCase));

                    if (prop != null)
                        value = prop.GetValue(obj).ToString();
                }
                else
                {
                    value = obj.ToString();
                }

                if (!picker.Items.Contains(value))
                {
                    picker.Items.Add(value);
                }

                if (picker.SelectedItem != null && picker.SelectedItem == obj)
                    picker.SelectedIndex = count;

                count++;
            }

            if (picker.ItemsSource.Count == picker.Items.Count - 1)
                picker.SelectedIndex++;
        }
        private void OnSelectedIndexChanged(object sender, EventArgs e)
        {
            if (SelectedIndex > -1)
            {
                SelectedItem = ItemsSource[SelectedIndex];
            }
        }
    }

Xaml代码

 <userControls:CustomPicker BackgroundColor="Transparent"  x:Name="testpicker" HorizontalOptions="FillAndExpand" ItemsSource="{Binding Services}" SelectedItem="{Binding SelectedServiceName}" DisplayProperty="{Binding ServiceDescription}" />

别忘了输入 Xaml header

xmlns:userControls="clr-namespace:MyNameSpace"

错误是由于将选择器绑定到源的自定义类型。

ItemsSource="{Binding Services}

我没有使用字符串作为绑定对象,而是将类型更改为:

public String SelectedServiceName 

为此:

public Service SelectedServiceName