Xamarin Forms Access every child element's Property

aquabind 21 Reputation points
2022-01-25T09:34:07.62+00:00

First of all, I am a beginner.

I want to access every child element of different types inside a Stack Layout.

I tried but could not find any solution.

I am using Microsoft Visual Studio Community 2019 Version 16.11.9.

MainPage.xaml

<?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="NewExp.MainPage"
             x:Name="mainPage">

  <StackLayout x:Name="first">
    <StackLayout x:Name="second">
      <Label Text="label1"/>
      <Label Text="label2"/>
      <Label Text="label3"/>
      <Label Text="label4"/>
      <Label Text="label5"/>
    </StackLayout>
    <AbsoluteLayout x:Name="third">
      <Button Text="BTN" Clicked="Button_Clicked" />
    </AbsoluteLayout>
  </StackLayout>
</ContentPage>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace NewExp
{
  public partial class MainPage : ContentPage
  {
    public MainPage()
    {
      InitializeComponent();
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
      Type type;
      Label label;
      // I want to access each child and change there's property eg. Text

      var _list = second.Children.ToList();

      for (int i = 0; i < _list.Count; i++)
      {
        // Not working
        //_list[i].Text = "New Text";


        // Not working
        //type = _list[i].GetType();
        //var _lst = (type)_list[i];
        //_lst.Text = "New Text";


        // Working, but I need to know previously that it is a Label
        // and this is not real world case.
        // I also used Linq, but no benefit

        label = (Label)_list[i];
        label.Text = "New Text";        
      }
    }
  }
}

Any suggestion will be most appreciable. Thanks in advance.

N.B. Its a sample, to clear the basics. Actually casting dynamically seems to be a problem.

Developer technologies | .NET | Xamarin
Developer technologies | C#
0 comments No comments
{count} votes

Accepted answer
  1. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 36,436 Reputation points Microsoft External Staff
    2022-01-26T07:49:24.457+00:00

    Hello,

    Welcome to our Microsoft Q&A platform!

    If you want to access every child element, you have to determine the type of each item, refer to the following code:
    Xaml

    <StackLayout x:Name="second" >  
            <Label Text="label1"/>  
            <Label Text="label2"/>  
            <Label Text="label3"/>  
            <Label Text="label4"/>  
            <Label Text="label5"/>  
            <Entry Placeholder="enter"></Entry>  
        </StackLayout>  
    

    Code

      for (int i = 0; i < _list.Count; i++)  
                {  
                    var a = _list[i];  
                    if (a is Label)  
                    {  
                        var mylabel = (Label)a;  
                        mylabel.Text = "some new text";  
                    }  
                    if (a is Entry)  
                    {  
                        var myEntry = (Entry)a;  
                        myEntry.Placeholder = "Please enter  some new text";  
                    }  
                }  
    

    If you want to update the UI by accessing every child element, you could try using Data Binding which allow properties of two objects to be linked so that a change in one causes a change in the other and using Model-View-ViewModel (MVVM) pattern which helps to cleanly separate the business and presentation logic of an application from its user interface (UI). Refer to
    https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm
    https://learn.microsoft.com/en-us/learn/modules/design-a-mvvm-viewmodel-for-xamarin-forms/
    https://learn.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/mvvm

    Since the several Labels look similar, you could also try putting them in an array and using Bindable Layouts in Xamarin.Forms, refer to the following code:
    Xaml

    <?xml version="1.0" encoding="utf-8" ?>  
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"  
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
                 xmlns:ViewModels="clr-namespace:ChildrenDemo.ViewModels"  
                 x:Class="ChildrenDemo.MainPage">  
    
    <ContentPage.BindingContext>  
        <ViewModels:StackLayoutViewModel></ViewModels:StackLayoutViewModel>  
    </ContentPage.BindingContext>  
    <StackLayout x:Name="first">  
        <!--<StackLayout x:Name="second" >  
            <Label Text="label1"/>  
            <Label Text="label2"/>  
            <Label Text="label3"/>  
            <Label Text="label4"/>  
            <Label Text="label5"/>  
            <Entry Placeholder="enter"></Entry>  
        </StackLayout>  
        <Button Text="click" Clicked="Button_Clicked"></Button>-->  
        <StackLayout BindableLayout.ItemsSource="{Binding Items}">  
            <BindableLayout.ItemTemplate>  
                <DataTemplate>  
                    <Label Text="{Binding TitleText}"></Label>  
                </DataTemplate>  
            </BindableLayout.ItemTemplate>  
        </StackLayout>  
        <Entry Text="{Binding MyUser.TitleText}"></Entry>  
    
        <AbsoluteLayout x:Name="third">  
            <Button Text="BTN" Command="{Binding ChangeTextCommand}" />  
        </AbsoluteLayout>  
    </StackLayout>  
    </ContentPage>  
    

    The BindingContext is StackLayoutViewModel :

    namespace ChildrenDemo.ViewModels  
    {  
        public class StackLayoutViewModel  
        {  
            public ObservableCollection<ItemModel> Items { get; set; }// this is for the BindableLayout.ItemsSource  
            IList<ItemModel> source = new List<ItemModel>()  
            {  
                new ItemModel() { TitleText = "1"},  
                new ItemModel() { TitleText = "2"},  
                new ItemModel() { TitleText = "3"},  
                new ItemModel() { TitleText = "4"},  
                new ItemModel() { TitleText = "5"},  
            };  
            public ItemModel MyUser { get; set; }//this model is for the entry,  I use the same model, you could create other models according to your needs  
            public ICommand ChangeTextCommand { get; set; }  
            public StackLayoutViewModel()  
            {  
                Items = new ObservableCollection<ItemModel>(source);  
                MyUser = new ItemModel() { TitleText = "qwe" };  
      
                ChangeTextCommand = new Command(() => {   
                    foreach (var ItemModel in Items)  
                    {  
                        ItemModel.TitleText = "New Text";  
                    }  
                    MyUser.TitleText = "new name";  
                });  
            }  
             
        }  
    }  
    

    The Model is ItemModel :

    namespace ChildrenDemo.Models  
    {  
        public class ItemModel :INotifyPropertyChanged  
        {  
            string _titletext = "";  
            public string TitleText  
        {  
                set  
                {  
                    if (_titletext != value)  
                    {  
                        _titletext = value;  
                        OnPropertyChanged("TitleText");  
                    }  
                }  
                get { return _titletext; }  
            }  
            public event PropertyChangedEventHandler PropertyChanged;  
            protected void OnPropertyChanged(string propertyName)  
            {  
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  
            }  
        }  
    }  
    

    Best Regards,
    Wenyan Zhang


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.