1
votes

I have been looking through all the suggestions i got when i wrote the Title for this but not one could help me with my problem. Since this is my first question here you will have to excuse me if im asking it all wrong and please let me know if i need to ellaborate.

I am however working in Xamarin with a ListView. The listView is populated through setting the ItemSource with a List containing a class of mine that extends the ViewCell Class, this is done basically as shown below.

The Problem

The problem i am having is using a ViewModel for class MeasurePointView.xaml.cs. When trying to access any property in the MeasurePointViewModel which is set to BindingContext for MeasurePointView.xaml.cs i am getting for example: [0:] Binding: 'MeasurePointProps' property not found on 'Mobile.Pages.MeasurePointView', target property: 'Xamarin.Forms.Label.Text' from debugger and of course nothing shows up on screen.

So my question is: How do i set a Binding between ViewCell class "MeasurePointView" and ViewModel "MeasurePointViewViewModel" to get this working?

And also, please let me know how bad i may have misunderstood the databinding. its just that i have been getting this approach to work all over the Application except here.

Just to clarify: The pages extends BasePage (Extends ContentPage) And the Viewmodels derive from BaseViewModel (Which basically implements INotifyPropertyChanged)

ListOneView.xaml.cs

using Mobile.Controls;
using Mobile.Pages;
using Mobile.ViewModels;
using System.Collections.ObjectModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Mobile.Views {
  [XamlCompilation(XamlCompilationOptions.Compile)]
  public partial class ListOneView : BasePage {

    public ListView ListView;

    public ObservableCollection<MeasurePoint> MeasurePointList { get; set; }

    public ListOneView(ObservableCollection<MeasurePoint> list) {
      MeasurePointList = list;
      InitializeComponent();
      InitializeBindings();
      InitializeMeasurePoints();
    }

    public void InitializeBindings() {
      BindingContext = ViewModel = new ListOneViewViewModel(MeasurePointList);
    }

    private void InitializeMeasurePoints() {
      ListView = MeasurePointListView;
      MeasurePointListView.ItemTemplate = new DataTemplate(typeof(MeasurePointView));
      MeasurePointListView.ItemsSource = (ViewModel as ListOneViewViewModel).MeasurePointViewList;
    }
}


ListOneView.xaml


<?xml version="1.0" encoding="utf-8" ?>
<pages:BasePage
    xmlns:pages="clr-namespace:Mobile.Pages"
    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="Mobile.Views.ListOneView"
    BackgroundColor="{StaticResource BackgroundGrey}">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="FontSize" Value="12" />
                <Setter Property="TextColor" Value="Black" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ListView
        x:Name="MeasurePointListView"
        BackgroundColor="{StaticResource BackgroundGrey}"
        HasUnevenRows="True">
        <!--Empty-->
    </ListView>

</pages:BasePage>


ListOneViewViewModel.cs


using Mobile.Controls;
using Mobile.Pages;
using System.Collections.ObjectModel;

namespace Mobile.ViewModels {
  public class ListOneViewViewModel : BaseViewModel {

    public ObservableCollection<MeasurePointView> MeasurePointViewList { get; set; }

    public ListOneViewViewModel(ObservableCollection<MeasurePoint> measurePointList) {
      if (MeasurePointViewList == null)
        MeasurePointViewList = new ObservableCollection<MeasurePointView>();

      foreach (MeasurePoint mp in measurePointList) {
        MeasurePointViewList.Add(new MeasurePointView() {
          MeasurePoint = mp
        });
      }
    }
  }
}

MeasurePointView.xaml.cs


using Mobile.Controls;
using Mobile.ViewModels;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Mobile.Pages {
  [XamlCompilation(XamlCompilationOptions.Compile)]
  public partial class MeasurePointView : ViewCell {
    public MeasurePoint MeasurePoint { get; set; }
    public MeasurePointView() {
      InitializeComponent();
      InitializeBindings();
    }

    private void InitializeBindings() {
      BindingContext = new MeasurePointViewViewModel() {
        MeasurePointProps = this.MeasurePoint
      };
    }
  }

  public class MeasurePointViewViewModel : BaseViewModel {
    public MeasurePoint MeasurePointProps { get; set; }
  }
}

MeasurePointView.xaml


<?xml version="1.0" encoding="UTF-8"?>
<ViewCell
    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"
    x:Class="Mobile.Pages.MeasurePointView"
    mc:Ignorable="d">
    <ViewCell.View>
        <ContentView>
            <Label Text="{Binding MeasurePointProps.Title}" />
        </ContentView>
    </ViewCell.View>
</ViewCell>

2
each item in the ListView will have it's BindingContext set automatically. You do not need to do this yourself.Jason
Ok thanks, but i want it set to the ViewModel i assign it in its own class. not just the xaml.cs classBurritobreakfast
you are creating a lot of extra work for yourself for no apparent reason. If your ItemsSource is a List<x>, then each Cell in the ListView will have a BindingContext of the corresponding x. It's not clear to me what you're trying to accomplish by doing it your way.Jason
The reason is to separate some logic from the bare "visual logic" as this is the end in a long line of listing and visual logic. I would like to use the xaml.cs for just visual logic and the viewmodel i want to bind for a more data-oriented logic. It will be used to validate the input and send it on to API communications.Burritobreakfast

2 Answers

0
votes

I think you have complicated it a bit. Using ListView with view cells are very simple. You can create ListView and define your own ItemTemplate and start using the ViewCell directly in it. You can also create your own custom view cells and use it as well.

<?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="demoListView.ImageCellPage">
    <ContentPage.Content>
        <ListView  x:Name="listView">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout BackgroundColor="#eee" Orientation="Vertical">
                            <StackLayout Orientation="Horizontal">
                                <Image Source="{Binding image}" />
                                <Label Text="{Binding title}" TextColor="#f35e20" />
                                <Label Text="{Binding subtitle}" HorizontalOptions="EndAndExpand" TextColor="#503026" />
                            </StackLayout>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage.Content>
</ContentPage>

Refer below links for more idea about how to use ListView with view cells.

https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/customizing-cell-appearance

0
votes

i am getting for example: [0:] Binding: 'MeasurePointProps' property not found on 'Mobile.Pages.MeasurePointView', target property: 'Xamarin.Forms.Label.Text' from debugger and of course nothing shows up on screen.

MeasurePoint.cs

public class MeasurePoint
{
    public string Title { get; set; }
    public string Point { get; set; }

}

MeasurePointViewViewModel.cs

public class MeasurePointViewViewModel : INotifyPropertyChanged
{
    public MeasurePointViewViewModel()
    {
        MeasurePointProps = new MeasurePoint() { Point = "B", Title = "2" };
    }

    private MeasurePoint _MeasurePointProps;
    public MeasurePoint MeasurePointProps
    {
        get { return _MeasurePointProps; }
        set
        {
            _MeasurePointProps = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Solution1:

If you want to binding MeasurePointProps.Title, you could set BindingContent with the MeasurePointViewViewModel directly.

Xaml:

<Label Text="{Binding MeasurePointProps.Title}"/>

Code:

  public MainPage()
    {
        InitializeComponent();
        InitializeBindings();
    }

    private void InitializeBindings()
    {
        BindingContext = new MeasurePointViewViewModel();
    }

Solution2:

If you want to binding Title, you could check the code below.

Xaml:

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

Code:

public MainPage()
    {
        InitializeComponent();
        InitializeBindings();
    }

    private void InitializeBindings()
    {
        //BindingContext = new MeasurePointViewViewModel();
        BindingContext = new MeasurePointViewViewModel().MeasurePointProps;
    }