1
votes

I am following this tutorial to create Models and ContentViews but I am getting errors when I try to adjust some of the class names and templates to fit more so towards the project I am doing.

If I copy the code exactly from the tutorial it works fine however. I am thinking there is something so small I am missing here but I have scanned through my code for well over an hour and everything looks fine.

The error I am getting is coming from MainPage, 2 issues

[0:] Binding: 'SelectedItem' property not found on 'testProject_xamarin.MainPage', target property: 'Xamarin.Forms.ListView.SelectedItem'
[0:] Binding: 'listBands' property not found on 'testProject_xamarin.MainPage', target property: 'Xamarin.Forms.ListView.ItemsSource'

I have a simple Band C# class...

public class Band
{

    public string Name { get; set; }
    public string Genre { get; set; }
    public string Description { get; set; }

}

BandViewModel.cs

public class BandViewModel
{

    public IList<Band> listBands { get; set; }

    public object SelectedItem { get; set; }

    public BandViewModel()
    {
        listBands = new List<Band>();
        GenerateBandModel();
    }

    private void GenerateBandModel()
    {
        string name = "Test";
        string genre = "Music";
        string description = "Description";
        var band = new Band()
        {
            Name = name,
            Description = description,
            Genre = genre
        };
        listBands.Add(band);
    }
}

Here is my BandViewTemplate.xaml


<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="testProject_xamarin.Templates.BandViewTemplate">
  <ContentView.Content>
        <Frame IsClippedToBounds="True"
               HasShadow="True"
               Padding="0"
               BackgroundColor="White">
            <Frame.Margin>
                <OnPlatform x:TypeArguments="Thickness"  
                     Android="10"   
                     iOS="10"/>
            </Frame.Margin>
            <StackLayout Orientation="Horizontal">
                <BoxView Color="Green" WidthRequest="6"/>
                <Grid VerticalOptions="CenterAndExpand"  
                 Padding="0"  
                 HorizontalOptions="FillAndExpand"  
                 BackgroundColor="Transparent">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Label FontAttributes="Bold"  
                   Grid.Row="0"  
                   HorizontalTextAlignment="Start"  
                   VerticalTextAlignment="Center"  
                   FontSize="16"  
                   Text="{Binding Name, Mode = TwoWay}">
                        <Label.LineBreakMode>
                            <OnPlatform x:TypeArguments="LineBreakMode"  
                          Android="NoWrap"   
                          iOS="TailTruncation"/>
                        </Label.LineBreakMode>
                    </Label>
                    <BoxView Grid.Row="1" Color="Gray"  
                    HorizontalOptions="FillAndExpand"  
                    HeightRequest="1"/>
                    <Grid Grid.Row="2"  
                   BackgroundColor="Transparent"  
                   Padding="4">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Label Grid.Row="0"  
                          Grid.Column="0"  
                          Text="User Age"/>
                        <Label Grid.Row="0"  
                          Grid.Column="1"  
                          Text="{Binding Description, Mode = TwoWay}"/>
                    </Grid>
                </Grid>
            </StackLayout>
        </Frame>
    </ContentView.Content>
</ContentView>

And lastly the MainPage.xaml.. This is where the error is being thrown.


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:bandit_xamarin.Templates"
             x:Class="testProject_xamarin.MainPage">

    <StackLayout Orientation="Vertical">
        <!-- Place new controls here -->
        <Label Text="Welcome to Xamarin.Forms!" 
           FontAttributes="Bold"  
               FontSize="Medium"  
               VerticalOptions="Start"  
               HorizontalTextAlignment="Center"  
               VerticalTextAlignment="Center"  
               BackgroundColor="Transparent"  
               HorizontalOptions="CenterAndExpand" />
        <ListView x:Name="listView"
                  SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                  HasUnevenRows="True"
                  ItemsSource="{Binding listBands}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <local:BandViewTemplate/>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

</ContentPage>

MainPage.xaml.cs

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        this.BindingContext = new BandViewModel();
    }
}
1
Is your MainPage BindingContext set to your BandViewModel and does that ViewModel inherit from INotifyPropertyChanged?Nick Peppers
@NickPeppers I have updated the post to also include my MainPage.xaml.cs. You can see that I have set the BindingContect to BandViewModel but it does not inherit from INotifyPropertyChanged. The example was working without that as wellTree55Topz
Personally, that link looks like a really bad tutorial. I would reference something actually from the docs and without INotifyPropertyChanged you can't fire OnPropertyChanged() to indicate to your bindings a property has changed.Nick Peppers

1 Answers

0
votes

I test your code at my side, but I have no problem, this is the link about my project, you can download it and test it.

https://github.com/CherryBu/ContentViewSample

About your code, I have a few suggestions, you can refer to it.

Firstly, I suggest you to replace List() using ObservableCollection(), because it inherits INotifyPropertyChanged interface, represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.

Secondly, you can consider to make BandViewModel inherit INotifyPropertyChanged, because SelectedItem property need to update data when you change ListView selecteditem.

I modify your code, please take a look:

  public class BandViewModel: INotifyPropertyChanged
{
    public IList<Band> listBands { get; set; }
    private object _SelectedItem;
    public object SelectedItem
    {
        get { return _SelectedItem; }
        set
        {
            _SelectedItem = value;
            RaisePropertyChanged("SelectedItem");
        }
    }
    public BandViewModel()
    {
        listBands = new List<Band>(); 

        GenerateBandModel();
        //SelectedItem = listBands[0];
    }

    private void GenerateBandModel()
    {
        string name = "Test";
        string genre = "Music";
        string description = "Description";

        for(int i=0;i<10;i++)
        {
            var band = new Band()
            {
                Name = name + " "+i,
                Description = description+ " " +i,
                Genre = genre
            };
            listBands.Add(band);
        }

    }


    public event PropertyChangedEventHandler PropertyChanged;     
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}