How to display custom layout multiple times in Xamarin Forms

Adeel984Adeel984 Member ✭✭✭

I have a Custom Rating bar layout in Xamarin, I want to display it multiple times in my form but it is displaying only once even though i have declared it multiple times but is showing only one time & last layout.

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             Title="Reviews"
             xmlns:customcontrol="clr-namespace:MyApp.NestedLayouts"
             x:Class="MyApp.Pages.Reviews">
    <ContentPage.Content>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="110"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="100"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Label Text="4.5" FontSize="30" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
                   FontAttributes="Bold"/>
            <StackLayout Grid.Column="1">
                <customcontrol:RattingBar x:Name="layout1" ImageWidth="20" ImageHeight="20" RequiredStarValue="5"
                                          SelectedStarValue="5" FillStarImage="StarF.png" EmptyStarImage="star.png" />
                <Label Text="2 Reviews"/>
            </StackLayout>

            <Grid Grid.ColumnSpan="2" Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="110"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="40"/>
                    </Grid.ColumnDefinitions>

                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <!-- Row 0 -->
                <customcontrol:RattingBar ImageWidth="18" ImageHeight="18" RequiredStarValue="5" x:Name="layout2"
                                          SelectedStarValue="5" FillStarImage="StarF.png" EmptyStarImage="star.png" />
                <BoxView Grid.Column="1" HeightRequest="1" VerticalOptions="CenterAndExpand"
                         BackgroundColor="{DynamicResource gray}"/>
                <Label Grid.Column="2" Text="1" HorizontalOptions="CenterAndExpand"/>

                <!-- Row 1 -->
                <customcontrol:RattingBar ImageWidth="18" ImageHeight="18" RequiredStarValue="4" Grid.Row="1" x:Name="layout3"
                                          SelectedStarValue="4" FillStarImage="StarF.png" EmptyStarImage="star.png" />
                <BoxView Grid.Column="1" HeightRequest="1" VerticalOptions="CenterAndExpand" Grid.Row="1"
                         BackgroundColor="{DynamicResource gray}"/>
                <Label Grid.Column="2" Text="1" HorizontalOptions="CenterAndExpand" Grid.Row="1"/>

            </Grid>
        </Grid>
    </ContentPage.Content>
</ContentPage>

This is the layout Which i want to use multiple times but can't achieve (I have added my Views in backend).

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.NestedLayouts.RattingBar">
        <StackLayout Orientation="Horizontal"/>
</ContentView>
Tagged:

Best Answer

Answers

  • HarshitaHarshita INMember ✭✭✭✭

    @Adeel984
    Hey where is your grid row column inside your element?

    <customcontrol:RattingBar ImageWidth="18" ImageHeight="18" RequiredStarValue="5" x:Name="layout2"
                                              SelectedStarValue="5" FillStarImage="StarF.png" EmptyStarImage="star.png" />
    

    add this
    Grid.Row="RowNumber" Grid.Column="ColumnNumber"

    final result:

    <customcontrol:RattingBar ImageWidth="18" ImageHeight="18" RequiredStarValue="5" x:Name="layout2"
                                              SelectedStarValue="5" FillStarImage="StarF.png" EmptyStarImage="star.png" Grid.Row="0" Grid.Column="0"/>
    

    You first learn how to use gridview properly

  • JarvanJarvan Member, Xamarin Team Xamurai

    I tested your code using a native control to replace the 'customcontrol:RattingBar' and it works fine. Could you post the related code about the customcontrol? It'll help to reproduce the issue to get a solution.

  • igorkr_10igorkr_10 Member ✭✭✭✭
    Agree with @Harshita
    You need to check your layout first.
  • igorkr_10igorkr_10 Member ✭✭✭✭
    Just draw in paint what exact do you want to create and show us.
  • Adeel984Adeel984 Member ✭✭✭

    Thanks all for your reply i have re tested my code and found the issue , i am drawing images in stack layout on runtime when the same page re draws the images the previous one gets destroyed i think. Here is my backend code.

    The XAML Now

    <?xml version="1.0" encoding="UTF-8"?>
    <StackLayout xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="MyApp.NestedLayouts.RattingBar">
    
    </StackLayout>
    
    

    The Code behind

    using System;
    using System.Collections.Generic;
    using System.Windows.Input;
    using Xamarin.Forms;
    
    namespace MyApp.NestedLayouts
    {
        public partial class RattingBar : StackLayout
        {
            public event EventHandler ItemTapped = delegate { };
            public static int selectedStarValue = 0;
            public static int StarsRequired = 0;
            private static string emptyStarImage = string.Empty;
            private static string fillStarImage = string.Empty;
            private static Image star1;
            private static Image star2;
            private static Image star3;
            private static Image star4;
            private static Image star5;
            public static RattingBar page;
            StackLayout stkRattingbar;
            public RattingBar()
            {
                InitializeComponent();
                page = this;
                //stkRattingbar = new StackLayout();
                stkRattingbar = this;
                stkRattingbar.Orientation = StackOrientation.Horizontal;
                star1 = new Image();
                star2 = new Image();
                star3 = new Image();
                star4 = new Image();
                star5 = new Image();
    
    
                #region adding Gesture Recognizer on Star(Image Control)
                star1.GestureRecognizers.Add(new TapGestureRecognizer
                {
                    Command = ItemTappedCommand,
                    CommandParameter = 1
                });
    
                star2.GestureRecognizers.Add(new TapGestureRecognizer
                {
                    Command = ItemTappedCommand,
                    CommandParameter = 2
                });
    
                star3.GestureRecognizers.Add(new TapGestureRecognizer
                {
                    Command = ItemTappedCommand,
                    CommandParameter = 3
                });
                star4.GestureRecognizers.Add(new TapGestureRecognizer
                {
                    Command = ItemTappedCommand,
                    CommandParameter = 4
                });
                star5.GestureRecognizers.Add(new TapGestureRecognizer
                {
                    Command = ItemTappedCommand,
                    CommandParameter = 5
                });
                #endregion
                addStarsInLayout(5);
    
                // here i added pan gesture recognizer for selecting the star 
                var panGesture = new PanGestureRecognizer();
                panGesture.PanUpdated += (s, e) => {
                    // Handle the pan
                    var obj = e;
                    double width = star1.Width;
                    if (obj.TotalX > 0)
                    {
                        fillStar(1);
                        Command?.Execute(1);
                    }
                    if (obj.TotalX > width)
                    {
                        fillStar(2);
                        Command?.Execute(2);
                    }
                    if (obj.TotalX > (width * 2))
                    {
                        fillStar(3);
                        Command?.Execute(3);
    
                    }
                    if (obj.TotalX > (width * 3))
                    {
                        fillStar(4);
                        Command?.Execute(4);
    
                    }
                    if (obj.TotalX > (width * 4))
                    {
                        fillStar(5);
                        Command?.Execute(5);
                    }
                };
                stkRattingbar.GestureRecognizers.Add(panGesture);
            }
    
            // this event will fire when you click on image(star)
            private ICommand ItemTappedCommand
            {
                get
                {
                    return new Command((Object obj) =>
                    {
                        CommandParameter = obj;
                        Command?.Execute(CommandParameter);
                    });
    
                }
            }
    
          public void addStarsInLayout(int value)
            {
                if (stkRattingbar != null)
                    stkRattingbar.Children.Clear();
                switch (value)
                {
                    case 1:
                        stkRattingbar.Children.Add(star1);
                        break;
                    case 2:
                        stkRattingbar.Children.Add(star1);
                        stkRattingbar.Children.Add(star2);
                        break;
                    case 3:
                        stkRattingbar.Children.Add(star1);
                        stkRattingbar.Children.Add(star2);
                        stkRattingbar.Children.Add(star3);
                        break;
                    case 4:
                        stkRattingbar.Children.Add(star1);
                        stkRattingbar.Children.Add(star2);
                        stkRattingbar.Children.Add(star3);
                        stkRattingbar.Children.Add(star4);
                        break;
                    case 5:
                        stkRattingbar.Children.Add(star1);
                        stkRattingbar.Children.Add(star2);
                        stkRattingbar.Children.Add(star3);
                        stkRattingbar.Children.Add(star4);
                        stkRattingbar.Children.Add(star5);
                        break;
                    default:
                        stkRattingbar.Children.Add(star1);
                        stkRattingbar.Children.Add(star2);
                        stkRattingbar.Children.Add(star3);
                        stkRattingbar.Children.Add(star4);
                        stkRattingbar.Children.Add(star5);
                        break;
    
                }
            }
    
            #region  Image Height Width Property
            public static readonly BindableProperty ImageHeightProperty = BindableProperty.Create(
            propertyName: "ImageHeight",
            returnType: typeof(double),
            declaringType: typeof(RattingBar),
            defaultBindingMode: BindingMode.TwoWay,
            propertyChanged: ImageHeightPropertyChanged
             );
    
            public double ImageHeight
            {
                get { return (double)base.GetValue(ImageHeightProperty); }
                set { base.SetValue(ImageHeightProperty, value); }
            }
    
            private static void ImageHeightPropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                // set all images height  equal
                star1.HeightRequest = (double)newValue;
                star2.HeightRequest = (double)newValue;
                star3.HeightRequest = (double)newValue;
                star4.HeightRequest = (double)newValue;
                star5.HeightRequest = (double)newValue;
            }
    
    
            //image width
            public static readonly BindableProperty ImageWidthProperty = BindableProperty.Create(
            propertyName: "ImageWidth",
            returnType: typeof(double),
            declaringType: typeof(RattingBar),
            defaultBindingMode: BindingMode.TwoWay,
            propertyChanged: ImageWidthPropertyChanged
             );
    
            public double ImageWidth
            {
                get { return (double)base.GetValue(ImageWidthProperty); }
                set { base.SetValue(ImageWidthProperty, value); }
            }
    
            private static void ImageWidthPropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                // set all images width  equal
                star1.WidthRequest = (double)newValue;
                star2.WidthRequest = (double)newValue;
                star3.WidthRequest = (double)newValue;
                star4.WidthRequest = (double)newValue;
                star5.WidthRequest = (double)newValue;
            }
            #endregion
    
    
    
            #region Horizontal Vertical Allignment 
            public static readonly BindableProperty HorizontalOptionsProperty = BindableProperty.Create(
            propertyName: "HorizontalOptions",
            returnType: typeof(LayoutOptions),
            declaringType: typeof(RattingBar),
            defaultBindingMode: BindingMode.TwoWay,
            propertyChanged: HorizontalOptionsPropertyChanged
             );
    
            public LayoutOptions HorizontalOptions
            {
                get { return (LayoutOptions)base.GetValue(HorizontalOptionsProperty); }
                set { base.SetValue(HorizontalOptionsProperty, value); }
            }
    
            private static void HorizontalOptionsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                var control = (RattingBar)bindable;
                control.stkRattingbar.HorizontalOptions = (LayoutOptions)newValue;
            }
    
            //VERTICLE option set
    
            public static readonly BindableProperty VerticalOptionsProperty = BindableProperty.Create(
            propertyName: "VerticalOptions",
            returnType: typeof(LayoutOptions),
            declaringType: typeof(RattingBar),
            defaultBindingMode: BindingMode.TwoWay,
            propertyChanged: VerticalOptionsPropertyChanged
             );
    
            public LayoutOptions VerticalOptions
            {
                get { return (LayoutOptions)base.GetValue(VerticalOptionsProperty); }
                set { base.SetValue(VerticalOptionsProperty, value); }
            }
    
            private static void VerticalOptionsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                var control = (RattingBar)bindable;
                control.stkRattingbar.VerticalOptions = (LayoutOptions)newValue;
            }
            #endregion
    
            #region Command binding property
            public static readonly BindableProperty CommandProperty = BindableProperty.Create(
             propertyName: "Command",
             returnType: typeof(ICommand),
             declaringType: typeof(RattingBar)
             );
    
            public ICommand Command
            {
                get { return (ICommand)base.GetValue(CommandProperty); }
                set { base.SetValue(CommandProperty, value); }
            }
    
            //  this property is private becuase i don't wanna access it globally
            private static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(
             propertyName: "CommandParameter",
             returnType: typeof(object),
             declaringType: typeof(ImageButton),
             propertyChanged: CommandParameterPropertyChanged
             );
            private object CommandParameter
            {
                get { return base.GetValue(CommandParameterProperty); }
                set { base.SetValue(CommandParameterProperty, value); }
            }
    
            // on the change of command parameter replace empty star image with fillstar image
            private static void CommandParameterPropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                var selectedValue = (int)newValue;
                fillStar(selectedValue);
    
            }
    
            #endregion
    
    
            // this function will replace empty star with fill star
            private static void fillStar(int selectedValue)
            {
                selectedStarValue = selectedValue;
                switch (selectedValue)
                {
                    case 0:
                        star1.Source = emptyStarImage;
                        star2.Source = emptyStarImage;
                        star3.Source = emptyStarImage;
                        star4.Source = emptyStarImage;
                        star5.Source = emptyStarImage;
                        break;
                    case 1:
                        star1.Source = fillStarImage;
                        star2.Source = emptyStarImage;
                        star3.Source = emptyStarImage;
                        star4.Source = emptyStarImage;
                        star5.Source = emptyStarImage;
                        break;
                    case 2:
                        star1.Source = fillStarImage;
                        star2.Source = fillStarImage;
                        star3.Source = emptyStarImage;
                        star4.Source = emptyStarImage;
                        star5.Source = emptyStarImage;
                        break;
                    case 3:
                        star1.Source = fillStarImage;
                        star2.Source = fillStarImage;
                        star3.Source = fillStarImage;
                        star4.Source = emptyStarImage;
                        star5.Source = emptyStarImage;
                        break;
                    case 4:
                        star1.Source = fillStarImage;
                        star2.Source = fillStarImage;
                        star3.Source = fillStarImage;
                        star4.Source = fillStarImage;
                        star5.Source = emptyStarImage;
                        break;
                    case 5:
                        star1.Source = fillStarImage;
                        star2.Source = fillStarImage;
                        star3.Source = fillStarImage;
                        star4.Source = fillStarImage;
                        star5.Source = fillStarImage;
                        break;
    
                }
            }
    
    
            #region EmptyStar and fillstar property
            public static readonly BindableProperty EmptyStarImageProperty = BindableProperty.Create(
                propertyName: "EmptyStarImage",
                returnType: typeof(string),
                declaringType: typeof(RattingBar),
                defaultValue: "",
                defaultBindingMode: BindingMode.TwoWay,
                propertyChanged: EmptyStarImagePropertyChanged
             );
    
            public string EmptyStarImage
            {
                get { return (string)base.GetValue(EmptyStarImageProperty); }
                set { base.SetValue(EmptyStarImageProperty, value); }
            }
    
            private static void EmptyStarImagePropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                var control = (RattingBar)bindable;
                emptyStarImage = (string)newValue;
                //default set to all images as emptyStar
                star1.Source = emptyStarImage;
                star2.Source = emptyStarImage;
                star3.Source = emptyStarImage;
                star4.Source = emptyStarImage;
                star5.Source = emptyStarImage;
    
                // when default SelectedStarValue is assign  first and fillstariamge or emptystart image assign later then on the Property Change of
                //SelectedStar fillStartImage and emptyStart Image show emty string so to handle this  here i write this logic
                // < customcontrol:RattingBar x:Name = "customRattingBar"  ImageWidth = "25" ImageHeight = "25" SelectedStarValue = "1"    FillStarImage = "fillstar" EmptyStarImage = "emptystar" />
                if (!string.IsNullOrEmpty(fillStarImage))
                {
                    fillStar(selectedStarValue);
                }
            }
    
    
            public static readonly BindableProperty FillStarImageProperty = BindableProperty.Create(
              propertyName: "FillStarImage",
              returnType: typeof(string),
              declaringType: typeof(RattingBar),
              defaultValue: "",
              defaultBindingMode: BindingMode.TwoWay,
              propertyChanged: FillStarImagePropertyChanged
           );
    
            public string FillStarImage
            {
                get { return (string)base.GetValue(FillStarImageProperty); }
                set { base.SetValue(FillStarImageProperty, value); }
            }
    
            private static void FillStarImagePropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                var control = (RattingBar)bindable;
                fillStarImage = (string)newValue;
    
                // when default SelectedStarValue is assign  first and fillstariamge or emptystart image assign later then on the Property Change of
                //SelectedStar fillStartImage and emptyStar Image show emty string so to handle this  here i write this logic
                // < customcontrol:RattingBar x:Name = "customRattingBar"  ImageWidth = "25" ImageHeight = "25" SelectedStarValue = "1"    FillStarImage = "fillstar" EmptyStarImage = "emptystar" />
                if (!string.IsNullOrEmpty(emptyStarImage))
                {
                    fillStar(selectedStarValue);
                }
            }
            #endregion
    
    
            #region this will return the selected star value and also you can set the default selected star
            public static readonly BindableProperty SelectedStarValueProperty = BindableProperty.Create(
              propertyName: "SelectedStarValue",
              returnType: typeof(int),
              declaringType: typeof(RattingBar),
              defaultValue: 0,
              defaultBindingMode: BindingMode.OneWay,
              propertyChanged: SelectedStarValuePropertyChanged
           );
    
            public static readonly BindableProperty RequiredStarValueProperty = BindableProperty.Create(
              propertyName: "RequiredStarValue",
              returnType: typeof(int),
              declaringType: typeof(RattingBar),
              defaultValue: 0,
              defaultBindingMode: BindingMode.OneWay,
              propertyChanged: RequiredStarValuePropertyChanged
           );
    
            private static void SelectedStarValuePropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                var control = (RattingBar)bindable;
                selectedStarValue = (int)newValue;
    
                // if the SelectedStarValue is assign first and later fillStarImage & EmptyStar assign   
                if (!string.IsNullOrEmpty(fillStarImage) && !string.IsNullOrEmpty(emptyStarImage))
                {
                    fillStar(selectedStarValue);
                }
            }
    
            private static void RequiredStarValuePropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                var control = (RattingBar)bindable;
                StarsRequired = (int)newValue;
                   page.addStarsInLayout(StarsRequired);
            }
    
            public int SelectedStarValue
            {
                get { return selectedStarValue; }
                set { selectedStarValue = value; }
            }
    
            public int RequiredStarValue
            {
                get { return StarsRequired; }
                set { StarsRequired = value; }
            }
            #endregion
    
        }
    
    }
    
    
    
  • Adeel984Adeel984 Member ✭✭✭
    edited January 1

    Dear @Harshita Thanks for your kind suggestion. I am very well known about how to use Grid. but the situation here is a bit different.

  • Adeel984Adeel984 Member ✭✭✭

    Dear @Jarvan the issue has not yet been solved.

  • JarvanJarvan Member, Xamarin Team Xamurai
    edited January 3

    I have reproduced your problem and tried to create a simple custom StackLayout to test the functionality, but faced the same problem. I am working on this problem and will let you know as soon as a solution is available.

  • Adeel984Adeel984 Member ✭✭✭

    Ohh many thanks dear @Jarvan :smile:

  • Adeel984Adeel984 Member ✭✭✭

    Thank you so much Dear @Jarvan :smile:

Sign In or Register to comment.