-1

I have a CollectionView with a GridItemsLayout with a list of subjects as the ItemsSource. I want the footer to appear at the end of the CollectionView as if it were the last item, but at this time, it simply appears at the vertical end of the list.

Screenshot of what is currently happening

Here is the CollectionView XAML:

<CollectionView x:Name="collectionViewSubjects">
                <CollectionView.ItemsLayout>
                    <GridItemsLayout Span="2" HorizontalItemSpacing="15" VerticalItemSpacing="20"
                                 Orientation="Vertical"/>
                </CollectionView.ItemsLayout>

                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <border:SfBorder Style="{DynamicResource listItemBorder}">
                            <AbsoluteLayout HeightRequest="180">

                                <gradient:SfGradientView AbsoluteLayout.LayoutFlags="All"
                                                         AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 1"
                                                         Style="{StaticResource subjectItemGradient}"/>

                                <Label Text="{Binding Name}"
                                       AbsoluteLayout.LayoutFlags="All"
                                       AbsoluteLayout.LayoutBounds="0.5, 0.1, 0.9, 0.2"
                                       FontAttributes="Bold"/>
                                
                                <Label Text="{Binding Credits, StringFormat='0 / {0} credits'}"
                                       AbsoluteLayout.LayoutFlags="All"
                                       AbsoluteLayout.LayoutBounds="0.5, 0.35, 0.9, 0.2"/>
                                
                                <Label Text="{Binding Standards, StringFormat='{0} standards'}"
                                       AbsoluteLayout.LayoutFlags="All"
                                       AbsoluteLayout.LayoutBounds="0.5, 0.53, 0.9, 0.2"/>

                                <Button:SfButton Text="View Info" CornerRadius="30"
                                                 TextColor="Black"
                                                 FontAttributes="Bold"
                                                 FontSize="17"
                                                 AbsoluteLayout.LayoutFlags="All"
                                                 AbsoluteLayout.LayoutBounds="0.5, 0.85, 0.7, 0.2"
                                                 Style="{StaticResource subjectButtonGradient}"/>

                            </AbsoluteLayout>
                        </border:SfBorder>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
                
                <CollectionView.Footer>
                    <border:SfBorder Style="{DynamicResource listItemBorder}"
                                     BackgroundColor="Black"
                                     HeightRequest="180">
                        <Button Text="Add Subject"
                                TextColor="Yellow"
                                BackgroundColor="Transparent"/>
                    </border:SfBorder>
                </CollectionView.Footer>

            </CollectionView>

Edit: Here is my code-behind for the same page:

SubjectsPageViewModel ViewModel;
    public SubjectsPage()
    {
        InitializeComponent();

        ViewModel = new SubjectsPageViewModel();
        BindingContext = ViewModel;
        collectionViewSubjects.ItemsSource = ViewModel.Subjects;

        //var model = 
        //model.IsVisible = true;
    }
DaddyProphet
  • 128
  • 2
  • 8

1 Answers1

0

You could define the Button in DataTemplate in advance . And set the property IsVisible as true of the last item .

in Xaml

<DataTemplate>

  <StackLayout>

    <border:SfBorder IsVisible="{Binding IsVisible,Converter={StaticResource BoolConverter}}" Style="{DynamicResource listItemBorder}">
      <AbsoluteLayout HeightRequest="180">

        //...
      </AbsoluteLayout>
    </border:SfBorder>

    <border:SfBorder IsVisible="{Binding IsVisible}" Style="{DynamicResource listItemBorder}"
                                     BackgroundColor="Black"
                                     HeightRequest="180">
                        <Button Text="Add Subject"
                                TextColor="Yellow"
                                BackgroundColor="Transparent"/>
    </border:SfBorder>

   </StackLayout>

 </DataTemplate>

in your model

public class xxxModel : INotifyPropertyChanged
{
   

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    bool isVisible=false;   // the button is invisible in default

    public bool IsVisible
    {
        get
        {
            return isVisible;
        }

        set
        {
            if (isVisible != value)
            {
                isVisible = value;
                NotifyPropertyChanged("IsVisible");
            }
        }
    }

    //other properties
}

in code behind

Create a converter

public class BoolConverter : IValueConverter
    {
       
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var isVisible = (bool)value;

            return !isVisible;
        }
      

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

invoke the following line after you initialize the ItemSource

var model = ItemSource[ItemSource.Count - 1] as xxxModel;

model.IsVisible = true;
Lucas Zhang
  • 18,630
  • 3
  • 12
  • 22
  • I'm getting error CS0021 "Cannot apply indexing with [] to an expression of type 'IEnumerable'". Also, the collectionView's ItemsSource does not contain a definition for Count. – DaddyProphet Jul 07 '20 at 00:30
  • Also, when you say 'xxxModel' in your last snippet about the ItemsSource, do you mean the original data model used as the type in the view model's observable collection? – DaddyProphet Jul 07 '20 at 00:35
  • Yes, and you could share your sample so that I can test it on my side – Lucas Zhang Jul 07 '20 at 01:02
  • My code is just for demo . You need to modify it as you need . – Lucas Zhang Jul 07 '20 at 01:02
  • I have updated my question, adding the significant parts of the code-behind – DaddyProphet Jul 07 '20 at 03:26
  • I'm not sure how I can use a IsVisible property if the model variable is set to my Subject data model. – DaddyProphet Jul 07 '20 at 03:32
  • Did you add the property IsVisible to your model ? – Lucas Zhang Jul 07 '20 at 03:54
  • `var model =ViewModel.Subjects[ViewModel.Subjects - 1] as xxxModel; model.IsVisible = true;` – Lucas Zhang Jul 07 '20 at 03:54
  • If the reply is helpful, please do not forget the accept this answer(click the ✔ in the upper left corner), it will help others who have similar issue. – Lucas Zhang Jul 07 '20 at 04:40
  • I thought that OnPropertyChanged should only be implemented in a view model, not directly in the data model, since that is dealing with a view related issue (whether something is visible or not)? – DaddyProphet Jul 07 '20 at 05:36
  • It would be better to implement it both in ViewModel and Model . – Lucas Zhang Jul 07 '20 at 05:37
  • Okay, all the conversion works, but the problem with this is that the actual last item will be invisible while the Add Subject button is visible. All items must be visible, with the button at the end along with them. I'd have to create a dummy subject item, which results in very dirty code. – DaddyProphet Jul 07 '20 at 07:47
  • Or you could use `DataTemplateSelector` . Check https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/selector – Lucas Zhang Jul 07 '20 at 08:01
  • Again, I’d still need a dummy item to act as the last item for an AddSubject datatemplate to consume. Unless you can explain how I don’t need another item. Is there a way that doesn’t rely on data templates since the button isn’t using model data in any way? – DaddyProphet Jul 07 '20 at 08:28