Xamarin.forms CollectionView使用可观察项进行分组
下面的示例为CollectionView创建了一个分组,我注意到没有任何属性是INotifyPropertyChanged,基类也不是ObservableCollection 通过将列表更改为ObservableCollection,后者很容易修复:Xamarin.forms CollectionView使用可观察项进行分组,xamarin.forms,grouping,observablecollection,inotifypropertychanged,collectionview,Xamarin.forms,Grouping,Observablecollection,Inotifypropertychanged,Collectionview,下面的示例为CollectionView创建了一个分组,我注意到没有任何属性是INotifyPropertyChanged,基类也不是ObservableCollection 通过将列表更改为ObservableCollection,后者很容易修复: public class AnimalGroup : ObservableCollection<Animal> { public string Name { get; private set; } public Ani
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); }
}
公共类动物组:ObservableCollection
{
公共字符串名称{get;private set;}
公共动物组(字符串名称,可观察收集动物):基础(动物)
{
名称=名称;
}
私有字符串\u someOtherPropertyIWantToChangeAtRuntime=“嘿”;
公共字符串SomeOtherPropertyIwantChangeAtRuntime{get=>\u SomeOtherPropertyIwantChangeAtRuntime,set=>SetProperty(ref _SomeOtherPropertyIwantChangeAtRuntime,value);}
}
我不清楚如何命名或创建任何其他属性(例如,SomeOtherPropertyIWantToChangeAtRuntime),我希望将组作为INotifyPropertyChanged进行关联。通过将接口添加到基类,将其视为普通类,会导致以下警告:
基本接口“INotifyPropertyChanged”是多余的,因为AnimalGroup继承了“ObservableCollection”
但是,setter没有什么可调用的,比如SetProperty(ref _name,Value),现有的PropertyChanged对象只是用于监视组的集合更改。它不是可调用的,只是可处理的
如果我忽略警告并实现INotifyPropertyChanged(并将我的事件命名为PropChanged以避免与ObservableCollection.PropertyChanged冲突)
protected bool SetProperty(ref T backingStore,T value,[CallerMemberName]string propertyName=”“,Action onChanged=null)
{
if(EqualityComparer.Default.Equals(backingStore,value))
返回false;
backingStore=价值;
onChanged?.Invoke();
PropChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
返回true;
}
公共事件属性发生变化,处置者属性发生变化;
并且让我的ViewModel管理其他属性的值i希望更改运行时间,绑定的
从未看到任何更改
<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);
}
public observateCollection动物组{get;private set;}
public ICommand FindGroupAndChangeTextCommand{get;private set;}
public void FindGroupAndChangeText(字符串名称)
{
var group=AnimalGroups.FirstOrDefault(t=>t.Name==Name);
如果(组!=null)
group.SomeOtherPropertyIWantToChangeAtRuntime=DateTime.Now.ToString();
}
ViewModel()
{
AnimalGroups=LoadData();//未显示
FindGroupAndChangeText命令=新命令(FindGroupAndChangeText);
}
结果是标签保持“hey”(这是默认值),并且永远不会更改,即使我可以看到上面的命令触发,代码找到组并设置文本。同意Jason的说法,
ObservableCollection
继承了INotifyPropertyChanged
接口,因此您将得到警告
基本接口“INotifyPropertyChanged”是多余的,因为AnimalGroup继承了“ObservableCollection”
请参见以下关于可观察收集的屏幕截图。
如果您想在运行时像下面这样更改项目
基于你的代码。我在Animal
类中添加了两个属性。为了在运行时实现属性文本的更改,我们可以在Animal
类中实现INotifyPropertyChanged
。这里是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));
}
}
我注意到您希望实现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>
ObservableCollection有一个OnPropertyChanged方法我想你不明白我的问题。ObservableCollection确实具有PropertyChanged,但它仅在添加和删除项时激发。这与我的需要无关。我理解,现在我明白了,你应该能够在你的属性设置中调用PropertyChanged。setter的工作原理如下:set{u propname=value;OnPropertyChanged(newPropertyChangedEventArgs(nameof(propname));}如果上述答案有用,请将其作为答案接受(单击✔” 在这个答案的左上角),它将帮助其他有类似问题的人您的示例更新组内的项目。我想更新与组本身相关的项目。例如“Animal1-corvid子类型”,然后单击它并将其更改为“Animal1-原始人子类型”您没有CollectionView。GroupHeaderTemplate
,标题和数据在同一个项目中?您能给我一个关于您的数据结构的屏幕截图吗?这是真的。我的子项目是水平呈现的,我无法使用常规的分组隐喻来实现这一点。因此,我的组由垂直CollectionView处理,项目是水平的CollectionView在前者的ItemTemplate中。Jason帮我解决了我发布的问题。顺便说一句,我不确定如何标记这个问题。
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";
});
}
}
<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();
}
}