BindableProperty未在ViewModel上更新

时间:2015-05-25 19:00:48

标签: xaml data-binding xamarin.forms

在Xamarin.Forms中,我实现了自定义PickerItemsSource已正确设置。但是,当我更改所选项目时,它不会更新我的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; }

2 个答案:

答案 0 :(得分:3)

创建BindableProperty时:

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

未指定defaultBindingModeBindingMode设置为OneWay,表示Binding已从源(您的视图模型)更新为目标(您的视图)。

可以通过更改defaultBindingMode修复此问题:

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

或者,如果它是您希望选择器的默认值,但只想在此视图中更新源,则可以仅为此Binding实例指定BindingMode:

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

答案 1 :(得分:0)

除了将response添加到我的绑定之外,还必须更改我的选择器中的一些内容,以便它可以与我绑定的实际对象一起使用。

Mode=TwoWay的{​​{1}}属性为Items 因为我的所有项目都以字符串形式添加到它中,所以它保持相同的索引值。

因此,ItemsSource更改为Xamarin Picker

IList<string>

我还修改了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