xamarin.forms - 使用 Observable 进行 CollectionView 分组
问题描述
按照这个示例为 CollectionView 创建分组,我注意到没有一个属性是 INotifyPropertyChanged,基类也不是 ObservableCollection。
而后者很容易通过将 List 更改为 ObservableCollection 来修复:
public class AnimalGroup : ObservableCollection<Animal>
{
public string Name { get; private set; }
public AnimalGroup(string name, ObservableCollection<Animal> animals) : base(animals)
{
Name = name;
}
private string _someOtherPropertyIWantToChangeAtRuntime = "hey";
public string SomeOtherPropertyIWantToChangeAtRuntime { get => _someOtherPropertyIWantToChangeAtRuntime, set => SetProperty(ref _someOtherPropertyIWantToChangeAtRuntime, value); }
}
目前尚不清楚如何使 Name 或任何其他属性(例如 SomeOtherPropertyIWantToChangeAtRuntime),我想与组关联为 INotifyPropertyChanged。通过将接口添加到 base 将其视为普通类会导致此警告:
基本接口“INotifyPropertyChanged”是多余的,因为 AnimalGroup 继承了“ObservableCollection”
然而,setter 没有任何东西可以调用,例如 SetProperty(ref _name, Value) 并且现有的 PropertyChanged 对象仅用于监视组的集合更改。它不是可调用的,只是可处理的。
如果我忽略警告并无论如何实施 INotifyPropertyChanged(并将我的事件命名为 PropChanged 以避免与 ObservableCollection.PropertyChanged 发生冲突),
protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName]string propertyName = "", Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
PropChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
public event PropertyChangedEventHandler PropChanged;
并让我的 ViewModel 管理 SomeOtherPropertyIWantToChangeAtRuntime 的值,绑定<Label>
永远不会看到任何更改。
<CollectionView ItemsSource="{Binding AnimalGroups}" HorizontalOptions="FillAndExpand">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label
Text="{Binding Name}"
HorizontalOptions="Start"
FontSize="24.44"
TextColor="Black"
FontAttributes="Bold"
Margin="0,0,0,10"/>
<Label
Text="{Binding SomeOtherPropertyIWantToChangeAtRuntime}" FontSize="15"
TextColor="Black"
Margin="0,0,0,0">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.FindGroupAndChangeTextCommand, Source{x:Reference thisPageName}" CommandParameter="{Binding Name}"/>
</Label.GestureRecognizers>
</Label>
...
视图模型:
public ObservableCollection<AnimalGroup> AnimalGroups {get; private set;}
public ICommand FindGroupAndChangeTextCommand {get; private set;}
public void FindGroupAndChangeText(string name)
{
var group = AnimalGroups.FirstOrDefault(t => t.Name == name);
if (group != null)
group.SomeOtherPropertyIWantToChangeAtRuntime = DateTime.Now.ToString();
}
ViewModel()
{
AnimalGroups = LoadData(); // not shown
FindGroupAndChangeTextCommand = new Command(FindGroupAndChangeText);
}
结果是标签保持“嘿”(这是默认值)并且永远不会改变,即使我可以看到上面的命令触发并且代码找到了组并设置了文本。
解决方案
同意杰森,ObservableCollection
继承了INotifyPropertyChanged
接口,所以你会得到警告
基本接口“INotifyPropertyChanged”是多余的,因为 AnimalGroup 继承了“ObservableCollection”
请参阅以下有关ObservableCollection<T>
.
如果你想像这个 GIF 一样在运行时更改项目。
根据您的代码。Animal
我在类中添加了两个属性。为了实现在运行时更改属性的文本,我们可以INotifyPropertyChanged
在Animal
类中实现。这是AnimalGroup.cs
public class AnimalGroup : ObservableCollection<Animal>
{
public string Name { get; private set; }
public AnimalGroup(string name, ObservableCollection<Animal> animals) : base(animals)
{
Name = name;
}
}
public class Animal : INotifyPropertyChanged
{
string animalName;
public string AnimalName
{
set
{
if (animalName != value)
{
animalName = value;
OnPropertyChanged("AnimalName");
}
}
get
{
return animalName;
}
}
string animalArea;
public string AnimalArea
{
set
{
if (animalArea != value)
{
animalArea = value;
OnPropertyChanged("AnimalArea");
}
}
get
{
return animalArea;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
为了测试点击命令,我实现了MyAnimalViewModel.cs
类似下面的代码。
public class MyAnimalViewModel
{
public ObservableCollection<AnimalGroup> AnimalGroups { get; private set; } = new ObservableCollection<AnimalGroup>();
public ICommand FindGroupAndChangeTextCommand { protected set; get; }
public MyAnimalViewModel()
{
ObservableCollection<Animal> ts = new ObservableCollection<Animal>();
ts.Add(new Animal() { AnimalArea = "Asia", AnimalName = "cat" });
ts.Add(new Animal() { AnimalArea = "Asia", AnimalName = "dog" });
ObservableCollection<Animal> ts2 = new ObservableCollection<Animal>();
ts2.Add(new Animal() { AnimalArea = "Eourp", AnimalName = "keep" });
ts2.Add(new Animal() { AnimalArea = "Eourp", AnimalName = "gggg" });
AnimalGroups.Add(new AnimalGroup("Animal1", ts));
AnimalGroups.Add(new AnimalGroup("Animal2", ts2));
FindGroupAndChangeTextCommand = new Command<Animal>((key) =>
{
key.AnimalName = "testggggg";
});
}
}
我注意到您想要实现 CollectionView 的组。这是我编辑的布局。
<ContentPage.Content>
<CollectionView x:Name="MyCollectionView" ItemsSource="{Binding AnimalGroups}" IsGrouped="True" HorizontalOptions="FillAndExpand">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"/>
</CollectionView.ItemsLayout>
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<Label Text="{Binding Name}"
BackgroundColor="LightGray"
FontSize="Large"
FontAttributes="Bold" >
</Label>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label
Text="{Binding AnimalArea}"
HorizontalOptions="Start"
FontSize="24.44"
TextColor="Black"
FontAttributes="Bold"
Margin="0,0,0,10"/>
<Label
Text="{Binding AnimalName}" FontSize="15"
TextColor="Black"
Margin="0,0,0,0">
<Label.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1"
Command="{ Binding BindingContext.FindGroupAndChangeTextCommand, Source={x:Reference Name=MyCollectionView} }" CommandParameter="{Binding .}"
/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage.Content>
这是布局背景代码。
public partial class Page2 : ContentPage
{
public Page2()
{
InitializeComponent();
this.BindingContext = new MyAnimalViewModel();
}
}
推荐阅读
- c# - C# 解析来自不同语言环境的 int
- laravel-backpack - 将字段添加到仅将值传递给存储/更新方法的 CrudController
- linux - 使用 grep 的两个文件之间的相似性,为什么会这样: grep -i "-ffile1" file2
- python - Python:尝试遍历列表并仅打印正值时出错
- java - 如何防止视图重叠?
- database-design - 为星型模式中的分辨率设置时间维度
- encryption - FFmpeg concat demuxer 和处理加密块
- database - Mongodb 有条件地聚合返回数据
- jenkins - Jenkins:java.lang.NoSuchMethodError:在步骤中找不到这样的 DSL 方法“$”
- r - 在 Quanteda 中构建语料库,同时跟踪 ID