2015-05-25 5 views
3

В Xamarin.Forms я внедрил обычай Picker. ItemsSource установлен правильно. Однако, когда я изменяю выбранный элемент, он не обновляет свойство на моей модели ViewModel.BindableProperty не обновлен на ViewModel

BindablePicker:

public class BindablePicker : Picker 
{ 
    public BindablePicker() 
    { 
     this.SelectedIndexChanged += OnSelectedIndexChanged; 
    } 

    public static BindableProperty ItemsSourceProperty = 
     BindableProperty.Create<BindablePicker, IEnumerable>(o => o.ItemsSource, default(IEnumerable), propertyChanged: OnItemsSourceChanged); 

    public static BindableProperty SelectedItemProperty = 
     BindableProperty.Create<BindablePicker, object>(o => o.SelectedItem, default(object), propertyChanged: OnSelectedItemChanged); 


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

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

    private static void OnItemsSourceChanged(BindableObject bindable, IEnumerable oldvalue, IEnumerable newvalue) 
    { 
     var picker = bindable as BindablePicker; 
     picker.Items.Clear(); 
     if (newvalue != null) 
     { 
      //now it works like "subscribe once" but you can improve 
      foreach (var item in newvalue) 
      { 
       picker.Items.Add(item.ToString()); 
      } 
     } 
    } 

    private void OnSelectedIndexChanged(object sender, EventArgs eventArgs) 
    { 
     if (SelectedIndex < 0 || SelectedIndex > Items.Count - 1) 
     { 
      SelectedItem = null; 
     } 
     else 
     { 
      SelectedItem = Items[SelectedIndex]; 
     } 
    } 
    private static void OnSelectedItemChanged(BindableObject bindable, object oldvalue, object newvalue) 
    { 
     var picker = bindable as BindablePicker; 
     if (newvalue != null) 
     { 
      picker.SelectedIndex = picker.Items.IndexOf(newvalue.ToString()); 
     } 
    } 
} 

Xaml страница:

<controls:BindablePicker Title="Category" 
     ItemsSource="{Binding Categories}" 
     SelectedItem="{Binding SelectedCategory}" 
     Grid.Row="2"/> 

В ViewModel свойства, не выполнил NotifyPropertyChanged на свойства, так как они только должны быть обновлены с'View to the ViewModel`:

public Category SelectedCategory { get; set; } 
public ObservableCollection<Category> Categories { get; set; } 

ответ

0

Помимо добавления Mode=TwoWay к моей привязке пришлось изменить некоторые вещи в моей палитре, так что может работать с реальными объектами я имел это неизбежно.

Items свойства Xamarin Picker является IList<string> , так как все мои элементы добавляются к нему в виде строки, она сохраняет то же индексное значение.

Therefor в ItemsSource изменяется на IList:

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

Я также изменил метод SelectedIndexChanged поэтому не извлекает элемент из Items, но из ItemsSource, которым в моем случае, если IList<Category>:

private void OnSelectedIndexChanged(object sender, EventArgs eventArgs) 
    { 
     if (SelectedIndex < 0 || SelectedIndex > Items.Count - 1) 
     { 
      SelectedItem = null; 
     } 
     else 
     { 
      SelectedItem = ItemsSource[SelectedIndex]; 
     } 
    } 

в моей ViewModel я больше не использовать ObservableCollection для моего Categories но добавить эти элементы в IList<Category>.

ObservableCollection не использовать, так, когда мой BindablePicker связывается с ItemsSource элементы добавляются к внутренней IList<string>. при добавлении элемента в коллекцию он не будет обновляться. Теперь я обновляю весь ItemSource, если элемент изменен.

3

При создании BindableProperty:

public static BindableProperty SelectedItemProperty = 
    BindableProperty.Create<BindablePicker, object>(o => o.SelectedItem, default(object), propertyChanged: OnSelectedItemChanged); 

без указания defaultBindingMode, то BindingMode установлен в OneWay, означая Binding обновляется из источника (модель вида) для целевой (просмотра).

Это может быть исправлено путем изменения defaultBindingMode:

public static BindableProperty SelectedItemProperty = 
    BindableProperty.Create<BindablePicker, object>(o => o.SelectedItem, default(object), BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged); 

или, если это по умолчанию вы хотите для своего сборщика, но хотите обновить источник только в этом режиме вы можете указать BindingMode для этого экземпляр только переплет:

<controls:BindablePicker Title="Category" 
    ItemsSource="{Binding Categories}" 
    SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" 
    Grid.Row="2"/> 
+0

Я пробовал это allready, не помогал все это действительно должен быть включен, так что upvote.Я заметил, что когда я изменяю свое свойство привязки из типа Category, чтобы объект был успешным, это просто строковое значение, которое отбрасывается, поэтому я буду работать над этим позже и обновить ответ. – JMan

Смежные вопросы