Search code examples
listviewxamarinbindingviewmodel

Xamarin - Binding ListView children to custom list properties


I've got an issue with binding to a listview.

ViewModel:

public class MainPageViewModel : INotifyPropertyChanged
{

    public MainPageViewModel()
    {

    }

    private ObservableCollection<Player> players;

    public ObservableCollection<Player> Players
    {
        get { return players; }
        set 
        { 
            players = value;                
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Players")); 
        }
    }

    private List<string> playerNames = new List<string>();
    public List<string> PlayerNames
    {
        get { return playerNames; }
        set
        {
            playerNames = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PlayerNames"));
        }
    }

    private GameType selectedGame;

    public GameType SelectedGame
    {
        get { return selectedGame; }
        set 
        {
            selectedGame = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedGame"));
        }
    }

    private string gameName;

    public string GameName
    {
        get { return gameName; }
        set
        {
            gameName = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("GameName"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    
}

Player:

public class Player : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); }
    }

    private string currentScore = "0";

    public string CurrentScore
    {
        get { return currentScore; }
        set { currentScore = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentScore")); }
    }

    private string gamesWon = "0";

    public string GamesWon
    {
        get { return gamesWon; }
        set { gamesWon = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("GamesWon")); }
    }

    //public override string ToString()
    //{
    //    return Name;
    //}


}

ListView:

<ListView x:Name="listviewPlayers" HorizontalOptions="End" ItemsSource="{Binding Players}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Label Text="{Binding Players.Name}" />

                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

Updating viewmodel:

public void InitGame(Game game)
    {
        //initialize points and setup first player
        viewModel.Players = game.Players;
        viewModel.SelectedGame = game.SelectedGame;
        viewModel.GameName = game.SelectedGame.Name;
        contentMain.BindingContext = viewModel;            
    }

The above ListView bindings don't work - with error : The property 'Name' was not found in type 'ObservableCollection`1'. But if I remove the ItemTemplate and bind the listview's itemssource to {Binding Players[0].Name} the listview displays every name in the List Players. I can't see what I'm doing incorrectly. Would appreciate some help here.

Thanks, Mike


Solution

  • do this

    <Label Text="{Binding Name}" />
    

    the BindingContext for each row is the matching element of the ItemsSource, so in your case it's the individual Player instance

    you should also add this

    <DataTemplate x:DataType="model:Player" >
    

    where model is an xmlns defined in the header of the XAML

    see docs