2016-09-11 4 views
1

Я хочу расширить Xamarin.Forms Picker, чтобы я мог привязать к нему коллекцию. После быстрого поиска я нашел эту страницу: Picker Example с двумя замечательными примерами. Отказавшись просто скопировать & вставьте код (для учебных целей). Я продолжал и делал свое, основываясь на двух примерах.BindableProperty: несоответствие типов

Это почти идентично, кроме моего не работает.

Когда я не предоставляю коллекцию ItemsSource, все работает нормально. Всякий раз, когда я назначить коллекцию, я получаю следующее сообщение об ошибке:

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

Picker:

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> 

Примечание что первый примерщик из строки Страница ked работает с предоставленной установкой VM/View.

Я также не закончил сборщик, я все еще хочу предоставить привязку TwoWay к свойству SelectedItem и поддержку ObservableCollection.

Ваш,

ответ

1

Сначала мне показалось, что я злюсь.

Тогда я думал, что что-то серьезно нарушено.

Но в конце концов я понял это ...

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

Для того, чтобы синтаксический анализатор Xaml чтобы увидеть BindableProperty как таковой, он должен быть publicstatic, но вы получили ту часть справа).

В вашем случае синтаксический анализатор Xaml не видит BindableProperty, поэтому он возвращается к свойству, но у него нет способа установить Binding, и по мере того, как типы не совпадают, вы получаете исключение.

Изменить код

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