我有一个绑定到 ObservableCollection 的 ListView。
有没有办法在 SomeModel 项的属性发生更改时更新单个单元格,而无需通过更改 ObservableCollection 重新加载 ListView?
(问题是从https://forums.xamarin.com/discussion/40084/update-item-properties-in-a-listviews-observablecollection复制的,我的回答也是如此。)
正如我所看到的,您正在尝试使用 MVVM 作为 Xamarin.Forms 应用程序的模式。您已经在使用ObservableCollection来显示数据列表。当从集合中添加或删除新项目时,UI 将相应刷新,这是因为ObserverbleCollection正在实现INotifyCollectionChanged.
您想用这个问题实现的是下一个行为,当您想更改集合中项目的特定值并更新 UI 时,实现该目标的最佳和最简单的方法是为INotifyPropertyChanged您的集合中的项目模型实现.
波纹管,我有一个关于如何实现这一点的简单演示示例,正如我所看到的,您的答案正在发挥作用,但我相信这个示例对您来说更适合使用它。
我有简单Button的命令并ListView保存我的收集数据。
这是我的页面,SimpleMvvmExamplePage.xaml:
<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>
Run Code Online (Sandbox Code Playgroud)
此演示的基本思想是更改属性的值Seen并设置CheckBox当用户单击ListView.
这是我的Car.cs课。
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));
}
}
Run Code Online (Sandbox Code Playgroud)
在我的 Github 上的完整演示示例中,我正在使用我的BindableBase类,INotifyPropertyChanged当某些属性值在道具的 setter 中使用此 SetProperty 方法更改时,我会处理提升。
你可以在这里找到实现:https : //github.com/almirvuk/Theatrum/tree/master/Theatrum.Mobile/Theatrum.Mobile
到节目的最后一件事是我ViewModel这个页面,内ViewModel,我会的值更改Seen属性True集合中的物品时,在用户点击Button上方ListView。这是我的SimpleMvvmExamplePageViewModel.cs
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
此代码将帮助我们实现这种行为:当用户单击时,Button我们将从集合中更改项目属性的值,并且将刷新 UI,将选中复选框值。
这个演示的最终结果可以在这个 gif 波纹管上看到。
PS我可以将它与ItemTapped事件结合起来,ListView但我想让它变得非常简单,所以这个例子是这样的。
希望这对您有所帮助,祝您在编码方面好运!
如果在 Observable Collection 中将模型项替换为模型项本身,则任何与模型项关联的 UI 都将被刷新。
细节:
在 ViewModel 中,给定属性:
public ObservableCollection<Item> Items { get; set; } = new ObservableCollection<Item>();
Run Code Online (Sandbox Code Playgroud)
Item你的模型类在哪里。
添加一些项目(未显示)后,假设您想让项目“item”自行刷新:
public void RefreshMe(Item item)
{
// Replace the item with itself.
Items[Items.IndexOf(item)] = item;
}
Run Code Online (Sandbox Code Playgroud)
注意:上面的代码假设“item”已知位于“Items”中。如果未知,请在执行替换之前测试IndexOf返回值。>= 0
就我而言,我有一个DataTemplateSelector集合,并且该项目以需要不同模板的方式进行了更改。(具体来说,通过 TemplateSelector 从模型项中读取 IsExpanded 属性,单击该项可在折叠视图和展开/详细视图之间切换。)
注意:使用 进行了测试CollectionView,但 AFAIK 也适用于旧ListView类。
在 iOS 和 Android 上测试。
技术说明:
此项目替换可能会触发Replace NotifyCollectionChangedEvent,newItems和oldItems两者仅包含item。
| 归档时间: |
|
| 查看次数: |
2940 次 |
| 最近记录: |