1
votes

I'm wanting to create a GUI that has a similar to what the following code generates, a scroll of frames.

However I want to be able to have a scroll of dynamic content frames, ideally in XAML and populated with an Item source. I don't think this is possible without creating a custom view based on itemsview from what I can see. ListView and CollectionView don't quite do what I want.

I think I need to use the preview CarouselView, I was wondering if there is a way of doing what I'm after without.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FlexTest.MainPage">

    <ContentPage.Resources>
    <Style TargetType="Frame">
        <Setter Property="WidthRequest" Value="300"/>
        <Setter Property="HeightRequest" Value="500"/>
        <Setter Property="Margin" Value="10"/>
        <Setter Property="CornerRadius" Value="20"/>
    </Style>
    </ContentPage.Resources>
    
    
    <ScrollView Orientation="Both">
        <FlexLayout>
            <Frame BackgroundColor="Yellow">
                <FlexLayout Direction="Column">
                    <Label Text="Panel 1"/>
                    <Label Text="A Panel"/>
                    <Button Text="Click Me"/>
                </FlexLayout>
            </Frame>
            <Frame BackgroundColor="OrangeRed">
                <FlexLayout Direction="Column">
                    <Label Text="Panel 2"/>
                    <Label Text="Another Panel"/>
                    <Button Text="Click Me"/>
                </FlexLayout>
            </Frame>
            <Frame BackgroundColor="ForestGreen">
                <FlexLayout Direction="Column">
                    <Label Text="Panel 3"/>
                    <Label Text="A Third Panel"/>
                    <Button Text="Click Me"/>
                </FlexLayout>
            </Frame>
        </FlexLayout>
    </ScrollView>
</ContentPage>

Thanks Andy.

2
What do you mean by dynamic content frames?SomeStudent
Do you want to implement a scrollable view and each child contains multiple content that can be scrolled horizontally?For this feature, try to display the CarouselView in a ListView. Tutorial about CarouselView: docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/…Jarvan Zhang - MSFT
@Andy Pelton Hi, any updates? If you've solved the issue, please accept the soution as the answer. It will be beneficial for other community members who have similar questions. If you are facing some issues while implementing, try to post the particular error with the corresponding codes here.Jarvan Zhang - MSFT
Hi, sorry. I've been away and haven't had chance to fully check out the code in the answer by SomeStudent. Providing I'm understanding it correctly, it is limited to the predefined number of items in the template selector, which isn't what I'm after What I am after is providing a list of items as a data source, now this can be 3 or 50. I think the solution is to use the CarouselView sa you mention Jarvan but due to it still being marked as preview I am hesitant in using it. I think I will check it out though.Andy Pelton

2 Answers

1
votes

Preface: I hope I understood your request correctly :)

If by dynamic content you mean having a dynamic ItemTemplate then you can try doing following:

Step One:

Define an ItemTemplateSelector, you can give it w.e name you want. In this class we will define what sort of templates we have, let us say we have the three which you defined: Yellow, OrangeRed, ForestGreen

   public class FrameTemplateSelector : DataTemplateSelector {
       public DataTemplate YellowFrameTemplate {get; set;}
       public DataTemplate OrangeRedFrameTemplate {get; set;}
       public DataTemplate ForestGreenFrameTemplate {get; set;}

       public FrameTemplateSelector() {
          this.YellowFrameTemplate = new DataTemplate(typeof (YellowFrame));
          this.OrangeRedFrameTemplate = new DataTemplate(typeof (OrangeRedFrame));
          this.ForestGreenFrameTemplate = new DataTemplate(typeof (ForestGreenFrame));
       }

       //This part is important, this is how we know which template to select.
       protected override DataTemplate OnSelectTemplate(object item, BindableObject container) {
          var model = item as YourViewModel;
          switch(model.FrameColor) {
            case FrameColorEnum .Yellow:
              return YellowFrameTemplate;
            case FrameColorEnum .OrangeRed:
              return OrangeRedFrameTemplate;
            case FrameColorEnum .ForestGreen:
              return ForestGreenFrameTemplate;
            default:
             //or w.e other template you want.
              return YellowFrameTemplate;
       }
   }

Step Two:

Now that we have defined our Template Selector let us go ahead and define our templates, in this case our Yellow, OrangeRed, and ForestGreen frames respectively. I will simply show how to make one of them since the others will follow the same paradigm excluding, with of course the color changing. Let's do the YellowFrame

In the XAML you will have:

YellowFrame.xaml:

<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:d="http://xamarin.com/schemas/2014/forms/design"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         mc:Ignorable="d"
         x:Class="YourNameSpaceGoesHere.YellowFrame">
      <Frame BackgroundColor="Yellow">
                <FlexLayout Direction="Column">
                    <Label Text="Panel 1"/>
                    <Label Text="A Panel"/>
                    <Button Text="Click Me"/>
                </FlexLayout>
      </Frame>
</StackLayout>

In the code behind:

YellowFrame.xaml.cs:

public partial class YellowFrame : StackLayout {
   public YellowFrame() {
      InitializeComponent();
   }
}

Step Three

Now we need to create our ViewModel that we will use for our ItemSource that we will apply to FlexLayout, per the documentation for Bindable Layouts, any layout that "dervies from Layout" has the ability to have a Bindable Layout, FlexLayout is one of them.

So let us make the ViewModel, I will also create an Enum for the Color frame we want to render as I showed in the switch statement in step one, however, you can choose what ever means of deciding how to tell which template to load; this is just one possible example.

BaseViewModel.cs:

public abstract class BaseViewModel : INotifyPropertyChanged {

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = ""){
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public virtual void CleanUp(){
        }
    }

ParentViewModel.cs:

public class ParentViewModel: BaseViewModel {
   private ObservableCollection<YourViewModel> myViewModels {get; set;}
   public ObservableCollection<YourViewModel> MyViewModels {
      get { return myViewModels;}
      set { 
          myViewModels = value;
          OnPropertyChanged("MyViewModels");
      }
   }

   public ParentViewModel() {
     LoadData();
   }

   private void LoadData() {
       //Let us populate our data here. 
       myViewModels = new ObservableCollection<YourViewModel>();

       myViewModels.Add(new YourViewModel {FrameColor = FrameColorEnum .Yellow});
       myViewModels.Add(new YourViewModel {FrameColor = FrameColorEnum .OrangeRed});
       myViewModels.Add(new YourViewModel {FrameColor = FrameColorEnum .ForestGreen});
      MyViewModels = myViewModels;
   }
}

YourViewModel.cs:

public class YourViewModel : BaseViewModel {
    public FrameColorEnum FrameColor {get; set;}
}

FrameColorEnum.cs:

public enum FrameColorEnum {
   Yellow,
   OrangeRed,
   ForestGreen
}

We're almost there, so what we have done so far is we defined our view models that we will use on that page, the final step is to update our overall XAML where we will call our Template Selector. I will only update the snippets needed.

<ContentPage 
...
    **xmlns:views="your namespace where it was defined here, 
    normally you can just type the name of the Selector then have VS add the proper
    namespace and everything"**
<ContentPage.Resources>
<!--New stuff below-->
   <ResourceDictionary>
       <views:FrameTemplateSelector x:Key="FrameTemplateSelector"/>
   </ResourceDictionary>
</ContentPage.Resources>

<ScrollView Orientation="Both">
        <FlexLayout BindableLayout.ItemsSource="{Binding MyViewModels, Mode=TwoWay}"
                    BindableLayout.ItemTemplateSelector ="{StaticResource FrameTemplateSelector}"/>
    </ScrollView>

Live Picture:

enter image description here

1
votes

Do you want to implement a scrollable view and each child contains multiple content that can be scrolled horizontally?

For this feature, try to display the CarouselView in a ListView.

Check the code:

<ListView ...>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <CarouselView>
                    <CarouselView.ItemTemplate>
                        <DataTemplate>
                            ...
                        </DataTemplate>
                    </CarouselView.ItemTemplate>
                </CarouselView>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Tutorial about CarouselView:
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/carouselview/introduction