ItemsSource 更改时选择器未更新
Picker not updating when ItemsSource changed
我有一个Xamarin.Forms(3.2,最新版本)Picker
实现为
<Picker x:Name="ClassSelector"
Title="Select Class"
ItemsSource="{Binding Classrooms}"
ItemDisplayBinding="{Binding ClassroomName}"
SelectedItem="{Binding SelectedClassroom}">
</Picker>
BindingContext 是这个 ViewModel:
public class ClassroomsViewModel : BaseViewModel
{
public ObservableCollection<Classroom> Classrooms { get; set; }
public ClassroomsViewModel()
{
Classrooms = new ObservableCollection<Classroom>(_ClassroomsRepository.GetAll());
}
}
现在,当我在 ViewModel
中添加教室时,选择器尽职尽责地将项目添加到其列表中:
Classrooms.Add(new Classroom() { ClassroomName = "test" }); // this works fine
但是如果我修改一个教室,Picker
不会更新它的项目列表:
Classrooms[0].ClassroomName = "test"; // this doesn't have an effect,
// although the value is set
// in the ObservableCollection
我也试过显式调用:
OnPropertyChanged(); // nothing
OnPropertyChanged("Classrooms"); // nope
如果它很重要,Classroom
确实派生自 ObservableObject
:
public class Classroom : ObservableObject
{
private string classroomName;
public string ClassroomName { get => classroomName; set => SetProperty(ref classroomName, value); }
}
编辑,我在此澄清 不是 collection-replacement 问题:
请注意,我 不是 将 Classrooms
collection 替换为新的 ObservableCollection —— 就像在其他可能与我的问题类似的帖子中发生的那样.我只是 修改 collection 的成员之一。当此 collection 绑定到不同的控件(如 ListView
)时,它的行为完全符合预期——ListView
更新以反映新的 ClassroomName
。
谁能指出我做错了什么?
通常,当我们使用绑定时,我们希望目标(选择器项)与绑定源(在本例中为 Classroom
对象)保持同步 - 因此,您的代码,通过设计,是正确的。
然而,在深入研究 XF github 中的 Picker
源代码之后 - 看起来它在从 Binding
中提取第一个值后取消了对 binding/property-changes 的订阅。 Here you can see the explicit call to UnApply()
到绑定,然后到 picker-item 显示名称的绑定表达式。
在 CustomerViewModel
上调用 OnPropertyChanged("Classrooms");
(而不是在 Customer
上)在技术上应该可行。或者,您可以尝试从集合中删除修改后的 Customer
对象,然后在同一索引处重新添加以解决此问题。这两个操作都会触发 ResetItems()
- which in turn should trigger the refresh for picker-item's display name.
出于某种原因,将源设置为 null 然后重置它对我有用:
var items = picker.ItemsSource as List<string>;
items.Add("item");
picker.ItemsSource = null;
picker.ItemsSource = items;
我有一个Xamarin.Forms(3.2,最新版本)Picker
实现为
<Picker x:Name="ClassSelector"
Title="Select Class"
ItemsSource="{Binding Classrooms}"
ItemDisplayBinding="{Binding ClassroomName}"
SelectedItem="{Binding SelectedClassroom}">
</Picker>
BindingContext 是这个 ViewModel:
public class ClassroomsViewModel : BaseViewModel
{
public ObservableCollection<Classroom> Classrooms { get; set; }
public ClassroomsViewModel()
{
Classrooms = new ObservableCollection<Classroom>(_ClassroomsRepository.GetAll());
}
}
现在,当我在 ViewModel
中添加教室时,选择器尽职尽责地将项目添加到其列表中:
Classrooms.Add(new Classroom() { ClassroomName = "test" }); // this works fine
但是如果我修改一个教室,Picker
不会更新它的项目列表:
Classrooms[0].ClassroomName = "test"; // this doesn't have an effect,
// although the value is set
// in the ObservableCollection
我也试过显式调用:
OnPropertyChanged(); // nothing
OnPropertyChanged("Classrooms"); // nope
如果它很重要,Classroom
确实派生自 ObservableObject
:
public class Classroom : ObservableObject
{
private string classroomName;
public string ClassroomName { get => classroomName; set => SetProperty(ref classroomName, value); }
}
编辑,我在此澄清 不是 collection-replacement 问题:
请注意,我 不是 将 Classrooms
collection 替换为新的 ObservableCollection —— 就像在其他可能与我的问题类似的帖子中发生的那样.我只是 修改 collection 的成员之一。当此 collection 绑定到不同的控件(如 ListView
)时,它的行为完全符合预期——ListView
更新以反映新的 ClassroomName
。
谁能指出我做错了什么?
通常,当我们使用绑定时,我们希望目标(选择器项)与绑定源(在本例中为 Classroom
对象)保持同步 - 因此,您的代码,通过设计,是正确的。
然而,在深入研究 XF github 中的 Picker
源代码之后 - 看起来它在从 Binding
中提取第一个值后取消了对 binding/property-changes 的订阅。 Here you can see the explicit call to UnApply()
到绑定,然后到 picker-item 显示名称的绑定表达式。
在 CustomerViewModel
上调用 OnPropertyChanged("Classrooms");
(而不是在 Customer
上)在技术上应该可行。或者,您可以尝试从集合中删除修改后的 Customer
对象,然后在同一索引处重新添加以解决此问题。这两个操作都会触发 ResetItems()
- which in turn should trigger the refresh for picker-item's display name.
出于某种原因,将源设置为 null 然后重置它对我有用:
var items = picker.ItemsSource as List<string>;
items.Add("item");
picker.ItemsSource = null;
picker.ItemsSource = items;