Xamarin Forms - 选择器 selectedItem 未触发
Xamarin Forms - picker selectedItem not firing
以下示例工作正常 (https://developer.xamarin.com/samples/xamarin-forms/UserInterface/BindablePicker/)
当我尝试在我的代码中实现它时,未设置为 selectedItem 引用的对象。选择器正在加载和选择数据,只是没有更新对象。
这是我正在使用的一些代码:
XAML页数
<Picker x:Name="testpicker" Title="Select a Service" ItemsSource="{Binding Services}, Mode=TwoWay}" ItemDisplayBinding="{Binding ServiceDescription}" SelectedItem="{Binding SelectedServiceName, Mode=TwoWay}" />
我在视图模型中有对象,但在选择选取器项时从未调用它。:
string selectedServiceName;
public string SelectedServiceName
{
get { return selectedServiceName; }
set
{
if (selectedServiceName != value)
{
selectedServiceName = value;
PickerOnPropertyChanged();
PickerOnPropertyChanged("SelectedService");
}
}
}
顺便说一下,绑定是在视图加载时从控制器完成的....
protected async override void OnAppearing()
{
base.OnAppearing();
await viewModel.LoadPreferenceData();
await viewModel.LoadServiceData();
testpicker.SelectedIndex = 5;
}
我还更新了基础 class 以反映教程,我更改了名称。
你能看出为什么这不起作用吗?如果需要,我很乐意提供更多代码。
创建自定义选择器并在您的代码中实现它对我有用请尝试以下代码:
public class CustomPicker : Picker
{
public CustomPicker()
{
SelectedIndexChanged += OnSelectedIndexChanged;
}
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create("SelectedItem", typeof(object), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnSelectedItemChanged);
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set
{
SetValue(SelectedItemProperty, value);
if (value != null && ItemsSource!=null && ItemsSource.Contains(value))
SelectedIndex = ItemsSource.IndexOf(value);
else
SelectedIndex = -1;
}
}
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnItemsSourceChanged);
public IList ItemsSource
{
get { return (IList)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly BindableProperty DisplayPropertyProperty =
BindableProperty.Create("DisplayProperty", typeof(string), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnDisplayPropertyChanged);
public string DisplayProperty
{
get { return (string)GetValue(DisplayPropertyProperty); }
set { SetValue(DisplayPropertyProperty, value); }
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
var picker = (CustomPicker)bindable;
picker.SelectedItem = newValue;
if (picker.ItemsSource != null && picker.SelectedItem != null)
{
var count = 0;
foreach (var obj in picker.ItemsSource)
{
if (obj == picker.SelectedItem)
{
picker.SelectedIndex = count;
break;
}
count++;
}
}
}
private static void OnDisplayPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var picker = (CustomPicker)bindable;
picker.DisplayProperty = (string)newValue;
LoadItemsAndSetSelected(bindable);
}
private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
var picker = (CustomPicker)bindable;
picker.ItemsSource = (IList)newValue;
var oc = newValue as INotifyCollectionChanged;
if (oc != null)
{
oc.CollectionChanged += (a, b) =>
{
LoadItemsAndSetSelected(bindable);
};
}
LoadItemsAndSetSelected(bindable);
}
private static void LoadItemsAndSetSelected(BindableObject bindable)
{
var picker = (CustomPicker)bindable;
if (picker.ItemsSource == null)
return;
var count = 0;
foreach (var obj in picker.ItemsSource)
{
var value = string.Empty;
if (picker.DisplayProperty != null)
{
var prop = obj.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, picker.DisplayProperty, StringComparison.OrdinalIgnoreCase));
if (prop != null)
value = prop.GetValue(obj).ToString();
}
else
{
value = obj.ToString();
}
if (!picker.Items.Contains(value))
{
picker.Items.Add(value);
}
if (picker.SelectedItem != null && picker.SelectedItem == obj)
picker.SelectedIndex = count;
count++;
}
if (picker.ItemsSource.Count == picker.Items.Count - 1)
picker.SelectedIndex++;
}
private void OnSelectedIndexChanged(object sender, EventArgs e)
{
if (SelectedIndex > -1)
{
SelectedItem = ItemsSource[SelectedIndex];
}
}
}
Xaml代码
<userControls:CustomPicker BackgroundColor="Transparent" x:Name="testpicker" HorizontalOptions="FillAndExpand" ItemsSource="{Binding Services}" SelectedItem="{Binding SelectedServiceName}" DisplayProperty="{Binding ServiceDescription}" />
别忘了输入 Xaml header
xmlns:userControls="clr-namespace:MyNameSpace"
错误是由于将选择器绑定到源的自定义类型。
ItemsSource="{Binding Services}
我没有使用字符串作为绑定对象,而是将类型更改为:
public String SelectedServiceName
为此:
public Service SelectedServiceName
以下示例工作正常 (https://developer.xamarin.com/samples/xamarin-forms/UserInterface/BindablePicker/)
当我尝试在我的代码中实现它时,未设置为 selectedItem 引用的对象。选择器正在加载和选择数据,只是没有更新对象。
这是我正在使用的一些代码: XAML页数
<Picker x:Name="testpicker" Title="Select a Service" ItemsSource="{Binding Services}, Mode=TwoWay}" ItemDisplayBinding="{Binding ServiceDescription}" SelectedItem="{Binding SelectedServiceName, Mode=TwoWay}" />
我在视图模型中有对象,但在选择选取器项时从未调用它。:
string selectedServiceName;
public string SelectedServiceName
{
get { return selectedServiceName; }
set
{
if (selectedServiceName != value)
{
selectedServiceName = value;
PickerOnPropertyChanged();
PickerOnPropertyChanged("SelectedService");
}
}
}
顺便说一下,绑定是在视图加载时从控制器完成的....
protected async override void OnAppearing()
{
base.OnAppearing();
await viewModel.LoadPreferenceData();
await viewModel.LoadServiceData();
testpicker.SelectedIndex = 5;
}
我还更新了基础 class 以反映教程,我更改了名称。
你能看出为什么这不起作用吗?如果需要,我很乐意提供更多代码。
创建自定义选择器并在您的代码中实现它对我有用请尝试以下代码:
public class CustomPicker : Picker
{
public CustomPicker()
{
SelectedIndexChanged += OnSelectedIndexChanged;
}
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create("SelectedItem", typeof(object), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnSelectedItemChanged);
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set
{
SetValue(SelectedItemProperty, value);
if (value != null && ItemsSource!=null && ItemsSource.Contains(value))
SelectedIndex = ItemsSource.IndexOf(value);
else
SelectedIndex = -1;
}
}
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnItemsSourceChanged);
public IList ItemsSource
{
get { return (IList)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly BindableProperty DisplayPropertyProperty =
BindableProperty.Create("DisplayProperty", typeof(string), typeof(CustomPicker), null, BindingMode.TwoWay, null, OnDisplayPropertyChanged);
public string DisplayProperty
{
get { return (string)GetValue(DisplayPropertyProperty); }
set { SetValue(DisplayPropertyProperty, value); }
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
var picker = (CustomPicker)bindable;
picker.SelectedItem = newValue;
if (picker.ItemsSource != null && picker.SelectedItem != null)
{
var count = 0;
foreach (var obj in picker.ItemsSource)
{
if (obj == picker.SelectedItem)
{
picker.SelectedIndex = count;
break;
}
count++;
}
}
}
private static void OnDisplayPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var picker = (CustomPicker)bindable;
picker.DisplayProperty = (string)newValue;
LoadItemsAndSetSelected(bindable);
}
private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
var picker = (CustomPicker)bindable;
picker.ItemsSource = (IList)newValue;
var oc = newValue as INotifyCollectionChanged;
if (oc != null)
{
oc.CollectionChanged += (a, b) =>
{
LoadItemsAndSetSelected(bindable);
};
}
LoadItemsAndSetSelected(bindable);
}
private static void LoadItemsAndSetSelected(BindableObject bindable)
{
var picker = (CustomPicker)bindable;
if (picker.ItemsSource == null)
return;
var count = 0;
foreach (var obj in picker.ItemsSource)
{
var value = string.Empty;
if (picker.DisplayProperty != null)
{
var prop = obj.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, picker.DisplayProperty, StringComparison.OrdinalIgnoreCase));
if (prop != null)
value = prop.GetValue(obj).ToString();
}
else
{
value = obj.ToString();
}
if (!picker.Items.Contains(value))
{
picker.Items.Add(value);
}
if (picker.SelectedItem != null && picker.SelectedItem == obj)
picker.SelectedIndex = count;
count++;
}
if (picker.ItemsSource.Count == picker.Items.Count - 1)
picker.SelectedIndex++;
}
private void OnSelectedIndexChanged(object sender, EventArgs e)
{
if (SelectedIndex > -1)
{
SelectedItem = ItemsSource[SelectedIndex];
}
}
}
Xaml代码
<userControls:CustomPicker BackgroundColor="Transparent" x:Name="testpicker" HorizontalOptions="FillAndExpand" ItemsSource="{Binding Services}" SelectedItem="{Binding SelectedServiceName}" DisplayProperty="{Binding ServiceDescription}" />
别忘了输入 Xaml header
xmlns:userControls="clr-namespace:MyNameSpace"
错误是由于将选择器绑定到源的自定义类型。
ItemsSource="{Binding Services}
我没有使用字符串作为绑定对象,而是将类型更改为:
public String SelectedServiceName
为此:
public Service SelectedServiceName