BindableProperty:类型不匹配

BindableProperty: Type Mismatch

我想扩展 Xamarin.Forms 选择器,以便我可以将集合绑定到它。快速搜索后,我找到了这个页面:Picker Example,其中有两个很好的例子。拒绝只是复制和粘贴代码(出于学习目的)我继续根据这两个示例制作自己的代码。

几乎完全一样,只是我的不行。

当我不向 ItemsSource 提供集合时,一切正常。每当我分配一个集合时,我都会收到以下错误:

Xamarin.Forms.Xaml.XamlParseException: Position 9:32. Cannot assign property "ItemsSource": type mismatch between "Xamarin.Forms.Binding" and "System.Collections.IEnumerable"

选择器:

public class BindablePicker : Picker
{
    private static readonly BindableProperty ItemsSourceProperty =
        BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(BindablePicker), null, propertyChanged: OnItemsSourceChanged);

    private static readonly BindableProperty SelectedItemProperty =
        BindableProperty.Create("SelectedItem", typeof(object), typeof(BindablePicker));

    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }
    public object SelectedItem
    {
        get { return GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
    }
    public string DisplayMember { get; set; }


    private static void OnItemsSourceChanged(BindableObject bindable, Object oldValue, Object newValue)
    {
        var newval = newValue as IEnumerable; //Had to implement this because of the non-generic .Create() method expects Object as param.
        var picker = bindable as BindablePicker;

        if (picker != null)
        {
            picker.Items.Clear();
            if (newval == null) return;

            foreach (var item in newval)
            {
                if (string.IsNullOrEmpty(picker.DisplayMember))
                {
                    picker.Items.Add(item.ToString());
                }
                else
                {
                    var prop = item.GetType()
                        .GetRuntimeProperties()
                        .FirstOrDefault(p => string.Equals(p.Name, picker.DisplayMember, StringComparison.OrdinalIgnoreCase));

                    picker.Items.Add(prop.GetValue(item).ToString());
                }
            }
        }
    }

    private void OnSelectedIndexChanged(object sender, EventArgs args)
    {
        if (SelectedIndex < 0 || SelectedIndex > Items.Count - 1)
        {
            SelectedItem = null;
        }
        else
        {
            SelectedItem = ItemsSource.ItemOf(SelectedIndex); //ItemOf is an extension method I made for IEnumerable (has to be tested).
        }
    }
}

ViewModel(部分):

public class HomePageViewModel : ViewModelBase
{
    //In the app this is populated with a List<Person>.
    public IEnumerable<Person> People { get; set; }
}

XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:controls="clr-namespace:TestApp.Controls;assembly=TestApp"
         x:Class="TestApp.Views.HomePage">
  <ContentPage.Content>
     <StackLayout>

         <controls:BindablePicker ItemsSource="{Binding People}"
                                  HorizontalOptions="Center" />
     </StackLayout>
  </ContentPage.Content>
</ContentPage>

请注意,链接页面中的第一个示例选择器适用于提供的 VM/View 设置。

我还没有完成选择器,我仍然想提供对 SelectedItem 的双向绑定 属性 和对 ObservableCollection 的支持。

你的,

起初我以为我要疯了。

然后我以为是什么东西严重坏了。

但我终于想通了...

private static readonly BindableProperty ItemsSourceProperty =
    BindableProperty.Create("ItemsSource", typeof(IEnumerable),  
    typeof(BindablePicker), null, propertyChanged: OnItemsSourceChanged);

为了让 Xaml 解析器看到 BindableProperty 本身,它必须是 public(和 static,但你说对了那部分) .

在你的例子中,Xaml 解析器没有看到 BindableProperty,所以它回退到 属性,但它没有任何方法来设置 Binding,由于类型不匹配,您会得到异常。

将您的代码更改为

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