Xamarin.forms 更新ListView的ObservableCollection中一项的显示
我有一个绑定到可观察集合的ListView 是否有一种方法可以在SomeModel项的属性发生更改时更新单个单元格,而无需通过更改ObservableCollection重新加载ListViewXamarin.forms 更新ListView的ObservableCollection中一项的显示,xamarin.forms,Xamarin.forms,我有一个绑定到可观察集合的ListView 是否有一种方法可以在SomeModel项的属性发生更改时更新单个单元格,而无需通过更改ObservableCollection重新加载ListView 问题是从中复制的,我的答案也是从中复制的。如果将模型项替换为其自身,则与模型项关联的任何UI都将在可观察集合中刷新 详情: 在ViewModel中,给定属性: public ObservableCollection<Item> Items { get; set; } = new Observ
问题是从中复制的,我的答案也是从中复制的。如果将模型项替换为其自身,则与模型项关联的任何UI都将在可观察集合中刷新 详情: 在ViewModel中,给定属性:
public ObservableCollection<Item> Items { get; set; } = new ObservableCollection<Item>();
注:以上代码假定项已知为项中的项。如果未知,则在执行替换之前测试IndexOf是否返回>=0
在我的例子中,我在集合上有一个DataTemplateSelector,该项被更改为需要一个不同的模板。具体来说,通过TemplateSelector从模型项读取IsExpanded属性,单击该项可以在折叠视图和展开/详细视图之间切换
注意:使用CollectionView进行测试,但AFAIK也将使用旧的ListView类。
在iOS和Android上测试
技术说明:
此项的替换可能会触发一个事件,其中newItems和oldItems都只包含项 正如我所看到的,您正在尝试将MVVM用作Xamarin.Forms应用程序的模式。您已经在使用ObservableCollection来显示数据列表。当从集合中添加或删除新项时,UI将相应刷新,这是因为ObserverbleCollection正在实现INotifyCollectionChanged 当您想要更改集合中项目的特定值并更新UI时,此问题要实现的是下一个行为。实现这一点的最佳和最简单的方法是为集合中项目的模型实现INotifyPropertyChanged 贝娄,我有一个简单的演示例子如何实现这一点,你的答案是工作,因为我可以看到,但我相信这个例子会更好地为你使用它 我有一个简单的按钮,带有命令和ListView,它保存着我的收集数据 这是我的页面SimpleMvvmExamplePage.xaml: 在Github上的完整演示示例中,我使用的是BindableBase类,在该类中,当在props的setter中使用此SetProperty方法更改某些属性值时,我将处理引发INotifyPropertyChanged的问题 您可以找到以下实现: 最后要显示的是此页面的我的ViewModel,在ViewModel内部,当用户单击ListView上方的按钮时,我会将集合中项目的Seed属性值更改为True。这是我的SimpleMvvmExamplePageViewModel.cs 这段代码将帮助我们实现这种行为:当用户单击按钮时,我们将更改集合中项目属性的值,UI将刷新,复选框值将被选中 这个演示的最终结果可以在下面的gif文件中看到 另外,我可以将它与ListView中的ItemTapped事件结合起来,但我想让它变得非常简单,所以这个例子是这样的
希望这对你有帮助,祝你在编码方面好运 几天后又增加了一个更好的答案;我已经接受了这个答案。对于这个问题,这不是最好的答案,但如果需要,这种方法也会更新项目模板。
public void RefreshMe(Item item)
{
// Replace the item with itself.
Items[Items.IndexOf(item)] = item;
}
<StackLayout>
<Button Text="Set status"
Command="{Binding SetStatusCommand}"
Margin="6"/>
<ListView ItemsSource="{Binding Cars}"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical"
Margin="8">
<Label Text="{Binding Name}"
FontAttributes="Bold" />
<StackLayout Orientation="Horizontal">
<Label Text="Seen?"
VerticalOptions="Center"/>
<CheckBox IsChecked="{Binding Seen}"
Margin="8,0,0,0"
VerticalOptions="Center"
IsEnabled="False" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
public class Car : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged();
}
}
private bool seen;
public bool Seen
{
get { return seen; }
set
{
seen = value;
OnPropertyChanged();
}
}
// Make base class for this logic, something like BindableBase
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class SimpleMvvmExamplePageViewModel
{
public ObservableCollection<Car> Cars { get; set; }
public ICommand SetStatusCommand { get; private set; }
public SimpleMvvmExamplePageViewModel()
{
// Set simple dummy data for our ObservableCollection of Cars
Cars = new ObservableCollection<Car>()
{
new Car()
{
Name = "Audi R8",
Seen = false
},
new Car()
{
Name = "BMW M5",
Seen = false
},
new Car()
{
Name = "Ferrari 430 Scuderia",
Seen = false
},
new Car()
{
Name = "Lamborghini Veneno",
Seen = false
},
new Car()
{
Name = "Mercedes-AMG GT R",
Seen = false
}
};
SetStatusCommand = new Command(SetStatus);
}
private void SetStatus()
{
Car selectedCar = Cars.Where(c => c.Seen == false)
.FirstOrDefault();
if (selectedCar != null)
{
// Change the value and update UI automatically
selectedCar.Seen = true;
}
}
}