Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xamarin.forms CollectionView使用可观察项进行分组_Xamarin.forms_Grouping_Observablecollection_Inotifypropertychanged_Collectionview - Fatal编程技术网

Xamarin.forms CollectionView使用可观察项进行分组

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

下面的示例为CollectionView创建了一个分组,我注意到没有任何属性是INotifyPropertyChanged,基类也不是ObservableCollection

通过将列表更改为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); }
}
公共类动物组: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();
        }
}