Xamarin CarouselView, display currentItem details in another page.

Abraham John 111 Reputation points
2021-03-05T23:20:14.117+00:00

I'm working on Lyrics app. It has two tabs. Lyrics tab and Details tab.

Lyrics tab is a carousel view which shows only id, title and lyrics of the songs.

When the page is swiped I want to display current song's all other information such as lyricist, album, year, etc in Details Tab.

Lyrics tab perfectly displays id, title and lyrics of all the songs. But Details tab is always blank.

In SongModel:

public class Song
{
   public string id {get; set;}
   public string title { get; set; }
   public string lyrics { get; set; }
   public string lyricist { get; set; }
   public string album{ get; set; }
   public string genre{ get; set; }
}

In SongViewModel:

class SongsViewModel : BaseViewModel
{
   public Song currentsong { get; set; }
   public List<Song> songlist { get; private set; } 
}

The songs are parsed from a json file and are binded to ItemsSource of DataTemplate in lyrics.xaml. And it is working very well.

In Lyrics.xaml.cs, detecting current item change(Lyrics Tab with CarouselView ):

public partial class Lyrics : ContentPage
{
   public Lyrics()
   {
       InitializeComponent();
       BindingContext = new SongsViewModel();
   }

   public void OnCurrentItemChanged(object sender, CurrentItemChangedEventArgs e)
   {
       var item = e.CurrentItem as Song;
       ((SongsViewModel)this.BindingContext).currentsong = item;
   }
}

In Details.xaml page,

<ListView ItemsSource="{Binding currentsong}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Label FontSize="17" HorizontalOptions="Start" TextColor="Black" LineBreakMode="WordWrap">
                <Label.Text>
                    <MultiBinding StringFormat="{}Lyricist : {0};&#x0a;Album: {1}&#x0a;Genre : {2}">
                        <Binding Path="lyricist"/>
                        <Binding Path="album"/>
                        <Binding Path="genre"/>
                    </MultiBinding>
                </Label.Text>
            </Label>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

In Details.xaml.cs page,

 public partial class Details : ContentPage
 {
        public Details()
        {
            InitializeComponent();
            BindingContext = new SongsViewModel();
        }
 }

Please tell me what's wrong here.

Thanks.

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

Accepted answer
  1. JessieZhang-MSFT 7,716 Reputation points Microsoft External Staff
    2021-03-08T03:44:10.117+00:00

    Hello,

    Welcome to our Microsoft Q&A platform!

    There are several problem in your code.

    1. When navigating to page Details, you created a new instance for model SongsViewModel , so there is no value for currentsong .
        public Details()  
        {  
            InitializeComponent();  
            BindingContext = new SongsViewModel();  
        }  
      
    2. When you set ItemsSource for listView in page Details, it's type should be a list not currentsong. <ListView ItemsSource="{Binding currentsong}">

    According to your need, when we navigating to page Details, we can pass the data of selected Item to page Details:

    In page Lyrics:

            public void OnCurrentItemChanged(object sender, CurrentItemChangedEventArgs e)  
        {  
            Song item = e.CurrentItem as Song;  
           // ((SongsViewModel)this.BindingContext).currentsong = item;  
            Navigation.PushAsync(new Details(item));  
        }  
    

    In page Details,we can get the item from the constructor :

       public partial class Details : ContentPage  
        {  
            Song currentSong;  
      
            public Details(Song song)  
            {  
                InitializeComponent();  
      
                currentSong = song;  
                BindingContext = currentSong;  
            }  
      
        }  
    

    Details.xaml

    <ContentPage.Content>  
        <StackLayout>  
            <Label FontSize="17" HorizontalOptions="Start" TextColor="Black" LineBreakMode="WordWrap">  
                <Label.Text>  
                    <MultiBinding StringFormat="{}Lyricist : {0};&#x0a;Album: {1}&#x0a;Genre : {2}">  
                        <Binding Path="lyricist"/>  
                        <Binding Path="album"/>  
                        <Binding Path="genre"/>  
                    </MultiBinding>  
                </Label.Text>  
            </Label>  
        </StackLayout>  
    </ContentPage.Content>  
    

    Update

    It has two tabs. Lyrics tab and Details tab.

    If you have two tabs, you can achieve this function by the following steps:(I have tested on my side ,it works properly)

    1. add static for the currentsong in model SongsViewModel, then page Lyrics and Details will share the same field currentsong:
       public class SongsViewModel  
      { // set static for currentsong   
          public static Song currentsong { get; set; }  
          public List<Song> songlist { get; private set; }  
      
          public SongsViewModel()  
          {  
              songlist = new List<Song>();  
              songlist.Add(new Song { title = "title1", lyricist = "Jack", album = "Album1", genre = "classical" });  
              songlist.Add(new Song { title = "title2", lyricist = "hello", album = "Album2", genre = "Country" });  
              songlist.Add(new Song { title = "title3", lyricist = "May", album = "Album3", genre = "pop" });  
          }  
      }  
      
    2. make model Song implement interface INotifyPropertyChanged, when the value of currentsong changes, the UI will refresh automatically.
        public class Song: INotifyPropertyChanged  
       {  
           public string id { get; set; }  
           public string title { get; set; }  
      
           public string lyrics { get; set; }  
      
      
          // public string lyricist { get; set; }  
      
           string _lyricist;  
           public string lyricist  
           {  
               set { SetProperty(ref _lyricist, value); }  
      
               get { return _lyricist; }  
           }  
      
      
          // public string album { get; set; }  
      
           string _album;  
           public string album  
           {  
               set { SetProperty(ref _album, value); }  
      
               get { return _album; }  
           }  
      
      
           //public string genre { get; set; }  
           string _genre;  
           public string genre  
           {  
               set { SetProperty(ref _genre, value); }  
      
               get { return _genre; }  
           }  
      
           bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)  
           {  
               if (Object.Equals(storage, value))  
                   return false;  
      
               storage = value;  
               OnPropertyChanged(propertyName);  
               return true;  
           }  
      
           protected void OnPropertyChanged([CallerMemberName] string propertyName = null)  
           {  
               PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  
           }  
      
           public event PropertyChangedEventHandler PropertyChanged;  
       }  
      
    3. Lyrics.xaml.cs public partial class Lyrics : ContentPage
      {
      SongsViewModel viewModel;
       public Lyrics()  
       {  
           InitializeComponent();  
           viewModel = new SongsViewModel();  
           BindingContext = viewModel;  
       }  
      
       public void OnCurrentItemChanged(object sender, CurrentItemChangedEventArgs e)  
       {  
           Song item = e.CurrentItem as Song;  
      
           SongsViewModel.currentsong = item;  
       }  
      
      }
    4. Lyrics.xaml <ContentPage.BindingContext>
      tabbedpagewithnavigationpage:SongsViewModel</tabbedpagewithnavigationpage:SongsViewModel>
      </ContentPage.BindingContext>
      <ContentPage.Content>
      <StackLayout>
      <CarouselView ItemsSource="{Binding songlist}" CurrentItemChanged="OnCurrentItemChanged">
      <CarouselView.ItemsLayout>
      <LinearItemsLayout Orientation="Vertical" />
      </CarouselView.ItemsLayout>
      <CarouselView.ItemTemplate>
      <DataTemplate>
      <StackLayout>
      <Frame HasShadow="True"
      BorderColor="DarkGray"
      CornerRadius="5"
      Margin="20"
      HeightRequest="100"
      HorizontalOptions="Center"
      VerticalOptions="CenterAndExpand">
      <StackLayout>
      <Label Text="{Binding title }"
      FontAttributes="Bold"
      FontSize="Large"
      HorizontalOptions="Center"
      VerticalOptions="Center" />
      <Label
      Text="{Binding lyricist }"
      HeightRequest="150"
      WidthRequest="150"
      HorizontalOptions="Center" />
                               </StackLayout>  
                           </Frame>  
                       </StackLayout>  
                   </DataTemplate>  
               </CarouselView.ItemTemplate>  
           </CarouselView>  
       </StackLayout>  
      
      </ContentPage.Content>
    5. Details.xaml.cs public partial class Details : ContentPage
      {
       Song song;  
       public Details()  
       {  
           InitializeComponent();  
      
       }  
      
       protected override void OnAppearing()  
       {  
           base.OnAppearing();  
      
           song = SongsViewModel.currentsong;  
           BindingContext = song;  
       }  
      
      }
    6. Details.xaml <ContentPage.Content>
      <StackLayout>
      <Label FontSize="17" HorizontalOptions="Start" TextColor="Black" LineBreakMode="WordWrap">
      <Label.Text>
      <MultiBinding StringFormat="{}Lyricist : {0}; Album: {1} Genre : {2}">
      <Binding Path="lyricist"/>
      <Binding Path="album"/>
      <Binding Path="genre"/>
      </MultiBinding>
      </Label.Text>
      </Label>
      </StackLayout>
      </ContentPage.Content>

    Best Regards,

    Jessie Zhang

    ---
    If the response is helpful, please click "Accept Answer" and upvote it.

    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.