Listview within a scrollable view

j9070749j9070749 Member

I have a page which has 3 static questions, followed by a Listview which is binded to a dynamic list of questions (number of questions can change meaning the height of the listview needs to change)

Currently the listview is a static height. I need the listview to be dynamic and change height based on the number of questions.

The listview is in a scrollable view, if i take it out I end up having two scrollable sections within the page which I do not want.

How do I get the listview to expand as needed? I'm happy to use another control if more suitable. I'd like a solution which uses the MVVM framework if possible.

Below is the XAML for the listview:

            <ListView ItemsSource="{Binding AdditionalFields}" RowHeight="75" BackgroundColor="Green" VerticalOptions="FillAndExpand"  HasUnevenRows="True">
                <ListView.ItemTemplate >
                    <DataTemplate>
                        <ViewCell>
                            <ContentView BackgroundColor="Yellow">
                                <Grid>
                                    <Image Source="{Binding ProductImage}"/> <!--Image not showing-->
                                    <Label Text="{Binding DefaultName}" Style="{DynamicResource labelInformationStyle}" HorizontalOptions="StartAndExpand" Margin="15, 10, 0, 0"/>
                                    <controls:AdditionalFieldControl  />
                                </Grid>
                            </ContentView>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

Here is my AdditionalFieldControl constructor (which allows the user to enter an answer to the question) which is used in the snippet above (I know the fields aren't binded yet).

public AdditionalFieldControl()
        {
            //Set the the entry to fill and expand
            this.HorizontalOptions = new LayoutOptions() { Alignment = LayoutAlignment.Start, Expands = true,  };

            _entry = new Entry()
            {
                Placeholder = "Type input ...",// this.TextPlaceholder,
                PlaceholderColor = Xamarin.Forms.Color.Gray,
                Text = this.Text,
                TextColor = Xamarin.Forms.Color.Black,
                FontAttributes = FontAttributes.None,
                HeightRequest = 200,
                Margin = new Thickness(15, 25, 0, 0)
            };

            //add the entry to the stack layout 
            this.Children.Add(_entry);
        }

Please let me know if you need anymore information, thanks in advance for any help.

I'm debugging on a Samsung Galaxy S5 mini
Android version: 6.0.1

Best Answer

  • j9070749j9070749
    Accepted Answer

    If anyone else is having this problem here is what I did to get around this issue (feedback welcome).

    I created a custom control which I referenced in the XAML (within the scroll view) and set the binding to the ObservableCollection.

      <!--Additional Fileds section-->
                    <StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
                        <controls:BindableStackLayout Items="{Binding AdditionalFields, Mode=TwoWay}" />
                    </StackLayout>
    

    I had two different question types (single line and multiline) so I created two different custom control classes, which inhered from a base control class.

    Below are my custom control classes:

    Base Class:
    public class AdditionalFieldControl : StackLayout
    {
    public AdditionalFieldControl()
    {
    }

                public static readonly BindableProperty EntryTextProperty = BindableProperty.Create( 
                    "Text",
                    typeof(string),
                    typeof(AdditionalFieldSingleLineControl),
                    defaultValue: string.Empty,
                    propertyChanged: (obj, oldVal, newVal) =>
                    {
                    });
    
    
                /// <summary>
                /// The text to .
                /// Bindable property.
                /// </summary>
                public string Text
                {
                    get
                    {
                        return (string)GetValue(EntryTextProperty);
                    }
                    set
                    {
                        SetValue(EntryTextProperty, value);
                    }
                }
    
                public static readonly BindableProperty EntryPlaceholderProperty = BindableProperty.Create(
                    "Text",
                    typeof(string),
                    typeof(AdditionalFieldSingleLineControl),
                    defaultValue: "Type input ",
                    propertyChanged: (obj, oldVal, newVal) =>
                    {
                        ((AdditionalFieldSingleLineControl)obj).TextPlaceholder = string.Empty;
                    });
    
    
                /// <summary>
                /// The text to .
                /// Bindable property.
                /// </summary>
                public string TextPlaceholder
                {
                    get
                    {
                        return (string)GetValue(EntryPlaceholderProperty);
                    }
                    set
                    {
                        SetValue(EntryPlaceholderProperty, value);
                    }
                }
    
                public static readonly BindableProperty TextColorProperty = BindableProperty.Create(
                    "TextColor",
                    typeof(Xamarin.Forms.Color),
                    typeof(AdditionalFieldSingleLineControl),
                    defaultValue: Xamarin.Forms.Color.Black,
                    propertyChanged: (obj, oldVal, newVal) =>
                    {
                    });
    
                /// <summary>
                /// The colour of the input text.
                /// Bindable property.
                /// </summary>
                public Xamarin.Forms.Color TextColor
                {
                    get
                    {
                        return (Xamarin.Forms.Color)GetValue(TextColorProperty);
                    }
                    set
                    {
                        SetValue(TextColorProperty, value);
                    }
                }
    
                public InputView Entry; //public for inheritance
    

    Single Line control:
    public class AdditionalFieldSingleLineControl : AdditionalFieldControl //Entry
    {
    public AdditionalFieldSingleLineControl()
    {
    Entry = new Entry()
    {
    Placeholder = this.TextPlaceholder,
    PlaceholderColor = Xamarin.Forms.Color.Gray,
    Text = this.Text,
    TextColor = Xamarin.Forms.Color.Black,
    FontAttributes = FontAttributes.None,
    Margin = new Thickness(25, 5, 5, 5),
    HorizontalOptions = new LayoutOptions() { Alignment = LayoutAlignment.Fill, Expands = true }
    };

                                //add the entry to the stack layout 
                                this.Children.Add(Entry);
                            }
                        }
    

    MultiLine
    public AdditionalFieldMultiLineControl()
    {
    Entry = new Editor()
    {
    Text = this.Text,
    TextColor = Xamarin.Forms.Color.Black,
    FontAttributes = FontAttributes.None,
    Margin = new Thickness(25, 5, 5, 5),
    HorizontalOptions = new LayoutOptions() { Alignment = LayoutAlignment.Fill, Expands = true },
    HeightRequest = 100
    };

                        this.Children.Add(Entry);
                    }
    

    In the main custom control which I call from the XAML I have a bindable property for the ObservableList of questions. On the change event of this property I loop through the observable collection and create a new instance of the custom property required and add the elements to the child.

    Below is the change event for the

Answers

  • j9070749j9070749 Member
    Accepted Answer

    If anyone else is having this problem here is what I did to get around this issue (feedback welcome).

    I created a custom control which I referenced in the XAML (within the scroll view) and set the binding to the ObservableCollection.

      <!--Additional Fileds section-->
                    <StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
                        <controls:BindableStackLayout Items="{Binding AdditionalFields, Mode=TwoWay}" />
                    </StackLayout>
    

    I had two different question types (single line and multiline) so I created two different custom control classes, which inhered from a base control class.

    Below are my custom control classes:

    Base Class:
    public class AdditionalFieldControl : StackLayout
    {
    public AdditionalFieldControl()
    {
    }

                public static readonly BindableProperty EntryTextProperty = BindableProperty.Create( 
                    "Text",
                    typeof(string),
                    typeof(AdditionalFieldSingleLineControl),
                    defaultValue: string.Empty,
                    propertyChanged: (obj, oldVal, newVal) =>
                    {
                    });
    
    
                /// <summary>
                /// The text to .
                /// Bindable property.
                /// </summary>
                public string Text
                {
                    get
                    {
                        return (string)GetValue(EntryTextProperty);
                    }
                    set
                    {
                        SetValue(EntryTextProperty, value);
                    }
                }
    
                public static readonly BindableProperty EntryPlaceholderProperty = BindableProperty.Create(
                    "Text",
                    typeof(string),
                    typeof(AdditionalFieldSingleLineControl),
                    defaultValue: "Type input ",
                    propertyChanged: (obj, oldVal, newVal) =>
                    {
                        ((AdditionalFieldSingleLineControl)obj).TextPlaceholder = string.Empty;
                    });
    
    
                /// <summary>
                /// The text to .
                /// Bindable property.
                /// </summary>
                public string TextPlaceholder
                {
                    get
                    {
                        return (string)GetValue(EntryPlaceholderProperty);
                    }
                    set
                    {
                        SetValue(EntryPlaceholderProperty, value);
                    }
                }
    
                public static readonly BindableProperty TextColorProperty = BindableProperty.Create(
                    "TextColor",
                    typeof(Xamarin.Forms.Color),
                    typeof(AdditionalFieldSingleLineControl),
                    defaultValue: Xamarin.Forms.Color.Black,
                    propertyChanged: (obj, oldVal, newVal) =>
                    {
                    });
    
                /// <summary>
                /// The colour of the input text.
                /// Bindable property.
                /// </summary>
                public Xamarin.Forms.Color TextColor
                {
                    get
                    {
                        return (Xamarin.Forms.Color)GetValue(TextColorProperty);
                    }
                    set
                    {
                        SetValue(TextColorProperty, value);
                    }
                }
    
                public InputView Entry; //public for inheritance
    

    Single Line control:
    public class AdditionalFieldSingleLineControl : AdditionalFieldControl //Entry
    {
    public AdditionalFieldSingleLineControl()
    {
    Entry = new Entry()
    {
    Placeholder = this.TextPlaceholder,
    PlaceholderColor = Xamarin.Forms.Color.Gray,
    Text = this.Text,
    TextColor = Xamarin.Forms.Color.Black,
    FontAttributes = FontAttributes.None,
    Margin = new Thickness(25, 5, 5, 5),
    HorizontalOptions = new LayoutOptions() { Alignment = LayoutAlignment.Fill, Expands = true }
    };

                                //add the entry to the stack layout 
                                this.Children.Add(Entry);
                            }
                        }
    

    MultiLine
    public AdditionalFieldMultiLineControl()
    {
    Entry = new Editor()
    {
    Text = this.Text,
    TextColor = Xamarin.Forms.Color.Black,
    FontAttributes = FontAttributes.None,
    Margin = new Thickness(25, 5, 5, 5),
    HorizontalOptions = new LayoutOptions() { Alignment = LayoutAlignment.Fill, Expands = true },
    HeightRequest = 100
    };

                        this.Children.Add(Entry);
                    }
    

    In the main custom control which I call from the XAML I have a bindable property for the ObservableList of questions. On the change event of this property I loop through the observable collection and create a new instance of the custom property required and add the elements to the child.

    Below is the change event for the

Sign In or Register to comment.