BindableProperty:类型不匹配

时间:2016-09-11 14:21:15

标签: c# xamarin.forms bindable

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

除了雷不起作用之外几乎完全相同。

当我没有向ItemsSource提供集合时,一切正常。每当我指定一个集合时,我都会收到以下错误:

  

Xamarin.Forms.Xaml.XamlParseException:位置9:32。无法分配属性“ItemsSource”:“Xamarin.Forms.Binding”和“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属性提供TwoWay绑定并支持ObservableCollection。

此致,

1 个答案:

答案 0 :(得分:1)

起初我以为我疯了。

然后我觉得有些东西被严重破坏了。

但最后我发现了......

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