c# – How to transfer data 2 pages from one TabPage?

Question:

I have a doubt, I am working with Xamarin and I have had to make a tabbedpage and add 2 pages (ContentPage) and everything has been fine, the problem is when I am going to do an event, that is, I have a ListView and when I select an item I want that on page 2 it is updated, the closest I could investigate was to use ObservableCollection that I used to add data to that listview but what I want now is that the selected data has to update some labels of the second page.

I am going to show the XAML code of the first page (the one with the Listview)

<ContentPage.Content>
        <StackLayout>
            <ListView x:Name="ListItems">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                                <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="70"/>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <Image Grid.Column="0" HorizontalOptions="Start" Source="{Binding Icon}" Margin="5"></Image>
                                <Label Grid.Column="1" Text="{Binding Name}"/>
                                <Label Grid.Column="1" Grid.Row="1" Text="{Binding Author}" VerticalTextAlignment="Center" FontSize="11"/>
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    </ContentPage.Content>

As we can see, internally to that Listview I pass an Observable and the rest is excellent. Now I am going to show the CS code of the Listview event:

ListItems.ItemsSource = listMusic.Musics();
ListItems.ItemSelected += (sender, e) =>
{
     if(ListItems.SelectedItem != null)
     {
     }
};

As we can see, the Musics method returns an ObservableCollection, now in the if is where I would send or in a nutshell I would modify the current value of the second page and that is where my question is, how can I modify that data? I'm going to show the XAML of the second page:

<ContentPage.Content>
        <StackLayout>
            <Image x:Name="IMG"  Background="Red" HeightRequest="300" Margin="35, 100, 35, 0" Aspect="Fill"/>
            <Label x:Name="Titulo" Text="Título de la canción" Margin="35, 0, 0, 0" FontSize="Title"/>
            <Label x:Name="Artista" Text="Artita" Margin="35, 0, 0, 0"/>
            <Slider x:Name="Slider" Maximum="100" Minimum="1" Value="1" Margin="22, 0, 0, 0" WidthRequest="200" HeightRequest="35" MinimumTrackColor="#FFFE4164" MaximumTrackColor="White"/>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                </Grid.RowDefinitions>

                <Button WidthRequest="60" HeightRequest="60" CornerRadius="30" VerticalOptions="Center" HorizontalOptions ="Center" Grid.Column="0" Margin="55,0,-55,0" BackgroundColor="White" ImageSource="tocarr"   />
                <ImageButton   VerticalOptions="Center" HorizontalOptions ="Center" Grid.Column="1" Source="playy"/>
                <Button WidthRequest="60" HeightRequest="60" CornerRadius="30" VerticalOptions="Center" HorizontalOptions ="Center" Grid.Column="2" Margin="-55,0,55,0" />
            </Grid>
          
        </StackLayout>
    </ContentPage.Content>

Upgrade:

I have added this to my Music class:

public class Music : INotifyPropertyChanged
    {
        private string _Author;
        public event PropertyChangedEventHandler PropertyChanged;
        private Android.Graphics.Bitmap _Img;
        private string _Name;
        private string _Path;

        public string Name { 
            get => _Name; 
            set {
                if(value != _Name)
                {
                    _Name = value;
                    NotifyPropertyChanged();
                }
            }
        }

        public string Author {
            get => _Author;
            set
            {
                if(value != _Author)
                {
                    _Author = value;
                    NotifyPropertyChanged();
                }
            }
        }

        public Android.Graphics.Bitmap Icon { 
            get => _Img;
            set
            {
                if (value != _Img)
                {
                    _Img = value;
                    NotifyPropertyChanged();
                }
            } 
        }
        public string Path {
            get => _Path;
            set
            {
                if (value != _Path)
                {
                    _Path = value;
                    NotifyPropertyChanged();
                }
            }
        }


        public Music(string Name, string Author, Android.Graphics.Bitmap Icon, string Path)
        {
            this.Name = Name;
            this.Author = Author;
            this.Icon = Icon;
            this.Path = Path;
        }

        public Music()
        {

        }

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

        public override string ToString()
        {
            return "Nombre de la Canción: " + Name + ".\nNombre del Autor: " 
                + Author + ".\nÍcono: " + Icon +".\nRuta: " + Path;
        }


    }

And I also added the bindings in the second tab:

<Image x:Name="IMG" Source="{Binding Icon}" Background="Red" HeightRequest="300" Margin="35, 100, 35, 0" Aspect="Fill"/>
            <Label x:Name="Titulo" Text="{Binding Name}" Margin="35, 0, 0, 0" FontSize="Title"/>
            <Label x:Name="Artista" Text="{Binding Author}" Margin="35, 0, 0, 0"/>

My method to send the information from tab 1 to tab 2:

 if(ListItems.SelectedItem != null)
                    {
                        var Music = ListItems.SelectedItem as Music;
                        MessagingCenter.Send("EnviarA", "Enviar", Music);
                        await DisplayAlert("info", Music.ToString(), "e");
                   
                    }

And the constructor where it receives the information:

public Music Music { get; set; }
        public MusicPage()
        {
            InitializeComponent();
            BindingContext = Music;

            MessagingCenter.Subscribe<Music>("EnviarA", "Enviar", (tema) =>
            {
                Music = tema;
            });
        }

Answer:

As a first point, it does not return an ObservableCollection since that is a List Type, which in its class already implements INotifyPropertyChanged , which means that if you make a change to a data in that list, that data is automatically reflected in your ListView . What the Listview returns is an object that is inside its ObservableCollection

Second for your example, what you need to use is an event or an object that you have global, if you change it on one side it will be reflected on your second screen.

Now moving from concepts to practice, it should be something like this with the MessagingCenter class. You have to adapt this example to your real problem.

        public class Pestaña1
        {
            public void enviar()
            {
                Music music = new Music()
                {
                    Artista = "",
                    Titulo = ""
                };

                MessagingCenter.Send(this, "Enviar", Music);
            }
        }
        public class Pestaña2
        {

            public Pestaña2()
            {
                
                
                MessagingCenter.Subscribe<ListMusicPage, Music>(this,"Enviar", (tema) =>
                {
                    BindingContext = tema;
                });
            }
        }

using System.ComponentModel;
using System.Runtime.CompilerServices;

    public class Musica : INotifyPropertyChanged
    {
        private string _Artista;
        private string _Img;
        private string _Titulo;

        public string Artista
        {
            get => _Artista;
            set
            {
                if (value != _Artista)
                {
                    _Artista = value;
                    OnProperty();
                }
            }
        }

        public string Img
        {
            get => _Img;
            set
            {
                if (value != _Img)
                {
                    _Img = value;
                    OnProperty();
                }
            }
        }
        public string Titulo
        {
            get => _Titulo;
            set
            {
                if(value != _Titulo)
                {
                    _Titulo = value;
                    OnProperty();
                }
            }
        }

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

Here I added the Bindeadas properties. Notice the change in the Text Property of each component.

 <StackLayout>
            <Image x:Name="IMG" Text="{Binding Img}" Background="Red" HeightRequest="300" Margin="35, 100, 35, 0" Aspect="Fill"/>
            <Label x:Name="Titulo" Text="{Binding Titulo}" Margin="35, 0, 0, 0" FontSize="Title"/>
            <Label x:Name="Artista" Text="{Binding Artista}" Margin="35, 0, 0, 0"/>
            <Slider x:Name="Slider" Maximum="100" Minimum="1" Value="1" Margin="22, 0, 0, 0" WidthRequest="200" HeightRequest="35" MinimumTrackColor="#FFFE4164" MaximumTrackColor="White"/>

Now your option 2, with the Global property. In class App.cs you declare a Music object;

 public Musica musica {get;set;}

Then in your tab 1,

 if(ListItems.SelectedItem != null)
     {
        App.Musica = ListItems.SelectedItem as Musica;
     }

Then in your tab 2: You leave the example that leaves you with the BindingContext, which is going to need INotifyPropertyChanged inheritance.

Now in your tab two, you pass the BindingContext your global property.

        public Pestaña2()
        {
            BindingContext = App.musica;
        }
Scroll to Top