Xamarin.Forms binding does not work

12,136

Finally is working!

XAML should looks like code below. Imporant is xmls:viewModel="..." and <ContentPage.BindingContext>...</>.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"                                                  
             xmlns:viewModel="clr-namespace:XamarinTest.ViewModel;assembly=XamarinTest"
             x:Class="XamarinTest.MainPage"         
             >
    <ContentPage.BindingContext>
        <viewModel:RecordingViewModel/>
    </ContentPage.BindingContext>
<ListView x:Name="listView" ItemsSource="{Binding Recordings}" Grid.Row="1" Grid.Column="1">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ViewCell.View>
                            <StackLayout Orientation="Horizontal">
                                <Image Source="Accept" WidthRequest="40" HeightRequest="40" />
                                <StackLayout Orientation="Vertical" HorizontalOptions="StartAndExpand">
                                    <Label Text="{Binding TestName}" HorizontalOptions="FillAndExpand" />
                                    <Label Text="{Binding TestNote}" />
                                </StackLayout>
                            </StackLayout>
                        </ViewCell.View>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</ContentPage>

and MainPage.xaml.cs is okey

namespace XamarinTest
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.AllTestViewModel = new RecordingViewModel();
            this.BindingContext = AllTestViewModel;                
        }
        public RecordingViewModel AllTestViewModel { get; set; }
    }
}
Share:
12,136
Jakub Kameniar
Author by

Jakub Kameniar

Updated on July 13, 2022

Comments

  • Jakub Kameniar
    Jakub Kameniar almost 2 years

    I try to rewrite my UWP C# app for Windows10 to Xamarin app using XAML. But Binding (for example here in ListView ItemSource=...) is not working for me and I don´t know why.

    Visual Studio tells me, Cannot Resolve Symbol Recording due to unknown Data Context.

    Here is my XAML (MainPage.xaml) for testing purpose:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"             
                 xmlns:local="clr-namespace:XamarinTest;assembly=XamarinTest"
                 x:Class="XamarinTest.MainPage">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
                <RowDefinition Height="100" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="100" />
            </Grid.ColumnDefinitions>
            <ListView x:Name="listView" IsVisible="false" ItemsSource="{Binding Recording}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <ViewCell.View>
                                <StackLayout Orientation="Horizontal">
                                    <Image Source="Accept" WidthRequest="40" HeightRequest="40" />
                                    <StackLayout Orientation="Vertical" HorizontalOptions="StartAndExpand">
                                        <Label Text="TEST" HorizontalOptions="FillAndExpand" />
                                        <Label Text="TEST" />
                                    </StackLayout>
                                </StackLayout>
                            </ViewCell.View>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>
    </ContentPage>
    

    Here is C# (MainPage.xaml.cs):

    namespace XamarinTest
    {
        public partial class MainPage : ContentPage
        {
            public MainPage()
            {
                this.InitializeComponent();
                this.AllTestViewModel = new RecordingViewModel();
                this.BindingContext = AllTestViewModel;                
            }
            public RecordingViewModel AllTestViewModel { get; set; }
        }
    }
    

    And finally ViewModel (RecordingViewModel.cs):

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading.Tasks;
    using XamarinTest.Model;
    
    namespace XamarinTest.ViewModel
    {
        public class RecordingViewModel : INotifyPropertyChanged
        {
            public ObservableCollection<Recording> Recordings { get; } = new TrulyObservableCollection<Recording>();
    
            public RecordingViewModel()
            {
                Recordings.Add(new RecordingTest2()
                {
                    TestName = "Test 1",
                    TestNote = "Vytvoreni DB",
                    TestTime = new TimeSpan(0, 0, 0)
                });
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
            where T : INotifyPropertyChanged
        {
            public TrulyObservableCollection()
            {
                CollectionChanged += FullObservableCollectionCollectionChanged;
            }
    
            public TrulyObservableCollection(IEnumerable<T> pItems) : this()
            {
                foreach (var item in pItems)
                {
                    this.Add(item);
                }
            }
    
            private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.NewItems != null)
                {
                    foreach (Object item in e.NewItems)
                    {
                        ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
                    }
                }
                if (e.OldItems != null)
                {
                    foreach (Object item in e.OldItems)
                    {
                        ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
                    }
                }
            }
    
            private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
                OnCollectionChanged(args);
            }
        }
    }
    

    Everything (models and viewmodels) are working in native UWP Windows 10 app. Only the Binding and making same view is problem in Xamarin. Could someone please help with binding? Thx.

    EDIT

    Recording.cs is here:

    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace XamarinTest.Model
    {
        public abstract class Recording : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            public string TestName { get; set; }
            private TimeSpan _testTime;
            private string _testNote;
            private string _actualIco = "Play";
            private bool _isActive = false;
            private bool _enabled = true;
            public double IcoOpacity { get; private set; } = 1.0;
            public string ActualIco
            {
                get => _actualIco;
                set
                {
                    if (_actualIco == null) _actualIco = "Admin";
                    _actualIco = value;
                    NotifyPropertyChanged("ActualIco");
                }
            }
            public bool IsActive
            {
                get => _isActive;
                set
                {
                    if (_isActive == value) return;
                    _isActive = value;
                    IcoOpacity = !value ? 1.0 : 0.3;
                    NotifyPropertyChanged("IsActive");
                    NotifyPropertyChanged("IcoOpacity");
                }
            }
            public bool Enabled
            {
                get => _enabled;
                set
                {
                    if (_enabled == value) return;
                    _enabled = value;
                    NotifyPropertyChanged("Enabled");
                }
            }
            public string TestNote
            {
                get => _testNote;
                set
                {
                    if (_testNote == value) return;
                    _testNote = value;
                    NotifyPropertyChanged("TestNote");
                }
            }
            public TimeSpan TestTime
            {
                get => _testTime;
                set
                {
                    if (_testTime == value) return;
                    _testTime = value;
                    NotifyPropertyChanged("TestTime");
                }
            }
    
            protected Recording()
            {
                TestName = "Unkonwn";
                TestNote = "";
                _testTime = new TimeSpan(0, 0, 0);
            }
    
            protected Recording(string testName, string testNote, TimeSpan testTime)
            {
                TestName = testName;
                TestNote = testNote;
                _testTime = testTime;
            }
            public string OneLineSummary => $"{TestName}, finished: "
                                            + TestTime;
    
            private void NotifyPropertyChanged(string propertyName = "")
            {
                var handler = PropertyChanged;
                handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            public abstract bool playTest();
    
        }
    }
    

    I tried add DataContext in XAML (postet in origin question), because of intellisence like this:

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    mc:Ignorable="d"
    xmlns:dvm="clr-namespace:XamarinTest.ViewModel"
    xmlns:system="clr-namespace:System;assembly=System.Runtime"
    d:DataContext="{system:Type dvm:RecordingViewModel}"
    

    and this to Grid:

    <Label Text="{Binding Recordings[0].TestName}" Grid.Row="0" Grid.Column="2" />
    

    IntelliSence is OK, but text doesn´t show in app.

  • Jakub Kameniar
    Jakub Kameniar almost 7 years
    I added Recording.cs to question. Yes, I think missing DataContext could be a problem. Could you please tell me how exactly I should it write? Because I tried it many times and it wasn´t working.
  • Jakub Kameniar
    Jakub Kameniar almost 7 years
    Oh, yes you right. But it didn´t help. Build and Deploy is sucess, but no text shows.
  • Jakub Kameniar
    Jakub Kameniar almost 7 years
    I tried DataContext in XAML but it didn´t help, only IntelliSence is working. I edited original question about it.
  • Jakub Kameniar
    Jakub Kameniar almost 7 years
    This label I created for testing purpose outside of ListView. Sorry for confusion. But If I do it in Label in ListView it isn´t working too (build and deploy work, but I see only empty page).
  • robjam
    robjam almost 7 years
    If you use a static Label: '<Label Text="Test message" Grid.Row="0" Grid.Column="2" />' does it show?
  • Jakub Kameniar
    Jakub Kameniar almost 7 years
    yes, I have this "for sure" label there all the time.
  • c-sharp-and-swiftui-devni
    c-sharp-and-swiftui-devni about 2 years
    Same situation thats so odd u think binding context should be enough