How to Databind in Xamarin PCL project? - xamarin

I want to make a simple login UI in xaml using Xamarin. I create a username and password field with Entry in the MainPage and then I try to bind them to my LoginViewModel where I can access my connexion method.
When I define the Binding context in the Mainpage codebehind the application simply shutdown and I dont understand why, what am I doing wrong ?
MainPage.xaml
<?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:suivAAndroid"
x:Class="suivAAndroid.MainPage">
<StackLayout
VerticalOptions="CenterAndExpand">
<Image></Image>
<Label
Text="Login"
StyleId="lbl_login"></Label>
<Entry
StyleId="ent_login"
Text="{Binding Username}"></Entry>
<Label
Text="Mot de passe"
StyleId="ent_mdp"></Label>
<Entry
StyleId="ent_mdp"
Text="{Binding Password}"></Entry>
<Button
Clicked="connexion_click"
Text="Connexion"></Button>
</StackLayout>
</ContentPage>
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace suivAAndroid
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new LoginViewModel(); // Here is where it does not work. If the line is commented out, then the application launch without stopping but because there is no binding context I cant get the user inputs.
}
private void connexion_click(object sender, EventArgs e)
{
LoginViewModel connexionBtn = new LoginViewModel();
Device.BeginInvokeOnMainThread(async () =>
{
await connexionBtn.Connexion();
});
}
}
}
LoginViewModel.cs
using suivAAndroid.Models;
using suivAAndroid.Views;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace suivAAndroid
{
public class LoginViewModel
{
#region propriétés
public string Username
{
get
{
return Username;
}
set
{
Username = value;
}
}
public string Password
{
get
{
return Password;
}
set
{
Password = value;
}
}
#endregion
#region constructor
public LoginViewModel()
{
}
#endregion
#region methodes
public void CreerListeVisiteurDur(List<Visiteur> uneListe)
{
Visiteur unVisiteur = new Visiteur("Clooney", "George", "cgeorge", "azerty", "rue du port", "59", "lille", new DateTime(2015 / 07 / 13));
uneListe.Add(unVisiteur);
}
public async Task Connexion()
{
List<Visiteur> uneListe = new List<Visiteur>();
CreerListeVisiteurDur(uneListe);
if (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password))
{
foreach (Visiteur unVisiteur in uneListe)
{
string login = unVisiteur.login;
string pass = unVisiteur.mdp;
if (login == Username && pass == Password)
{
App.Current.MainPage = new CreerVisite();
}
}
}
}
#endregion
}
}

Your ViewModel properties have infinite loops:
public string Username
{
get
{
return Username;
}
set
{
Username = value;
}
}
calling Username = value will call set on Username which in turn calls Username = value again.
Also, in order for your ViewModel to be bindable, you must implement INotifyPropertyChanged.
If you want a framework that is easy to use to help you do this, I would suggest Mvvm Light.
Here's an example of what your ViewModel should look like:
public class MyViewModel : INotifyPropertyChanged
{
public event EventHandler<PropertyChangedEventArgs> OnPropertyChanged;
private string _username;
public string Username
{
get
{
return _username;
}
set
{
_username = value;
PropertyChanged?.Invoke(new PropertyChangedEventArgs("Username");
}
}
....
}

in connexion_click you are creating a new copy of your VM that has no relation to the prior copy you created for your BindingContext.
public partial class MainPage : ContentPage
{
private LoginViewModel vm;
public MainPage()
{
InitializeComponent();
vm = new LoginViewModel();
BindingContext = vm;
}
private void connexion_click(object sender, EventArgs e)
{
Device.BeginInvokeOnMainThread(async () =>
{
await vm.Connexion();
});
}
}
your VM should implement INotifyPropertyChanged
your VM has a recursive getter

Related

Why does my Datagrid not populate after button click

My Datagrid does not populate after I click a button in my ViewModel
Model Code:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace Mist_Management.SubmissionStatusBySite
{
public class Table
{
[JsonProperty("Company")]
public string Company { get; set; }
[JsonProperty("DATE")]
public string Date { get; set; }
[JsonProperty("EODNUMBER")]
public string EODNumber { get; set; }
[JsonProperty("SUBSTATUS")]
public string SubStatus { get; set; }
[JsonProperty("DAYENDSTATUS")]
public string DayEndStatus { get; set; }
}
public class BySite
{
public List<Table> Table { get; set; }
}
}
ViewModel Code:
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using Mist_Management.CompanyModels;
using Mist_Management.SubmissionStatusBySite;
using System;
using System.Diagnostics;
namespace Mist_Management.ViewModels
{
class SubmissionStatusBySiteViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public ObservableCollection<CompanyModels.Table> Company { get; set; }
public ObservableCollection<SubmissionStatusBySite.Table> BySite { get; set; }
public SubmissionStatusBySiteViewModel()
{
Company = new ObservableCollection<CompanyModels.Table>();
GetCompany();
}
private async void GetCompany()
{
string requestUrl = "https://mist.zp.co.za:6502/MIST.svc/CMP/M#H$#203#R";
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(requestUrl);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string content = await response.Content.ReadAsStringAsync();
Company root = JsonConvert.DeserializeObject<Company>(content);
List<CompanyModels.Table> dates = root.Table;
foreach (var item in dates)
{
Company.Add(item);
}
}
}
}
public CompanyModels.Table selectedCompany;
public CompanyModels.Table SelectedCompany
{
get { return selectedCompany; }
set
{
selectedCompany = value;
OnPropertyChanged("SelectedCompany");
Debug.WriteLine(value.Company);
}
}
public DateTime _selectedFromDate;
public DateTime SelectedFromDate
{
get { return _selectedFromDate; }
set
{
if (_selectedFromDate == value)
return;
_selectedFromDate = value;
Debug.WriteLine(_selectedFromDate);
}
}
public string FromDate
{
get
{
return this.SelectedFromDate.ToString("yyyy-MM-dd");
}
}
public DateTime _selectedEndDate;
public DateTime SelectedEndDate
{
get { return _selectedEndDate; }
set
{
if (_selectedEndDate == value)
return;
_selectedEndDate = value;
Debug.WriteLine(_selectedEndDate);
}
}
public string EndDate
{
get
{
return this.SelectedEndDate.ToString("yyyy-MM-dd");
}
}
private async void GetData()
{
string requestUrl = "https://mist.zp.co.za:6502/MIST.svc/SUB2/M#H$#203#R/"
+ selectedCompany.Company + "/" + FromDate + "/" + EndDate;
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(requestUrl);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string content = await response.Content.ReadAsStringAsync();
BySite root = JsonConvert.DeserializeObject<BySite>(content);
List<SubmissionStatusBySite.Table> dates = root.Table;
foreach (var item in dates)
{
BySite.Add(item);
}
}
}
Debug.WriteLine(requestUrl);
}
public ICommand LoadButton_Clicked
{
get
{
return new Command(() =>
{
BySite = new ObservableCollection<SubmissionStatusBySite.Table>();
GetData();
});
}
}
}
}
XAML code:
<?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:dg="clr-namespace:Xamarin.Forms.DataGrid;assembly=Xamarin.Forms.DataGrid"
xmlns:system="clr-namespace:System;assembly=mscorlib"
x:Class="Mist_Management.Views.SubmissionStatusBySite"
Title="Submission Status By Site">
<StackLayout>
<Picker Title="Company List" ItemsSource="{Binding Company}"
ItemDisplayBinding="{Binding Company}"
SelectedItem="{Binding SelectedCompany}"/>
<Label Text="From Date"
FontSize="Medium"/>
<DatePicker HorizontalOptions="CenterAndExpand"
Format="yyyy-MM-dd"
MinimumDate="2015-01-01"
Date="{Binding SelectedFromDate}"/>
<Label Text="To Date"
FontSize="Medium"/>
<DatePicker HorizontalOptions="CenterAndExpand"
x:Name="EndDate"
Format="yyyy-MM-dd"
MinimumDate="2015-01-01"
Date="{Binding SelectedEndDate}"/>
<Button Text="Load" Command="{Binding LoadButton_Clicked}"/>
<ContentView>
<ScrollView Orientation="Horizontal">
<dg:DataGrid x:Name="BySiteGrid" ItemsSource="{Binding BySite}" RowHeight="70" HeaderHeight="50"
BorderColor="#CCCCCC" HeaderBackground="#E0E6F8">
<x:Arguments>
<ListViewCachingStrategy>RetainElement</ListViewCachingStrategy>
</x:Arguments>
<dg:DataGrid.HeaderFontSize>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Tablet>15</OnIdiom.Tablet>
<OnIdiom.Phone>12</OnIdiom.Phone>
</OnIdiom>
</dg:DataGrid.HeaderFontSize>
<dg:DataGrid.Columns>
<dg:DataGridColumn Title="Company" PropertyName="Company" Width="200"/>
<dg:DataGridColumn Title="Date" PropertyName="Date" Width="150"/>
<dg:DataGridColumn Title="EOD Number" PropertyName="EODNumber" Width="150"/>
<dg:DataGridColumn Title="Sub Status" PropertyName="SubStatus" Width="150"/>
<dg:DataGridColumn Title="Day End Status" PropertyName="DayEndStatus" Width="150"/>
</dg:DataGrid.Columns>
</dg:DataGrid>
</ScrollView>
</ContentView>
</StackLayout>
</ContentPage>
ContentView Code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Mist_Management.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SubmissionStatusBySite : ContentPage
{
public SubmissionStatusBySite()
{
InitializeComponent();
BindingContext = new ViewModels.SubmissionStatusBySiteViewModel();
}
}
}
I have other content viewModels that load on screen create but when I click a button the Datagrid does not want to load.
I have tried everything I can think off. I'm at my end with this problem.
Any help would be appreciated

How to setup my bindingcontext for my xamarin.forms app with mvvm and sqlite

The basic of my app is that i have an AgendaPage which has a collectionview of items and when i click the add icon, i can fill a form to populate this collectionview.
My app was working when i didn't set my app MVVM style but i am trying to apply the MVVM logic to my app.
Currently if i set the BindingContext of my NewFormPage to Agenda() my NewFormPage opens when i click the add button BUT if i set my BindingContext to NewFormViewModel, nothing open up and my app crash so i am trying to figure out what i am doing wrong in setting up this MVVM.
Note: currently i only have a clicked function to open up the page ( didn't implement the command yet, i was trying to implement the save command).
Agenda.cs in the database folder
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using SQLite;
using Calculette.Database;
namespace Calculette.Models
{
[Table("Agenda")]
public class Agenda
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Topic { get; set; }
public string Duration { get; set; }
public DateTime Date { get; set; }
}
}
NewFormViewModel.cs in the ViewModel folder
using Calculette.Database;
using Calculette.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
namespace Calculette.ViewModel
{
class NewFormViewModel : BaseViewModel
{
public Command AgendaSaveFormCommand { get; set; }
public NewFormViewModel()
{
AgendaSaveFormCommand = new Command(async () => await SaveForm(), () => !IsBusy);
}
public string Topic
{
get => Topic;
set
{
Topic = value;
NotifyPropertyChanged();
}
}
public string Duration
{
get => Duration;
set
{
Duration = value;
NotifyPropertyChanged();
}
}
public DateTime Date
{
get => Date;
set
{
Date = value;
NotifyPropertyChanged();
}
}
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set
{
isBusy = value;
//OnPropertyChanged();
AgendaSaveFormCommand.ChangeCanExecute();
}
}
public int ID { get; }
async Task SaveForm()
{
IsBusy = true;
await Task.Delay(4000);
IsBusy = false;
Agenda agenda = new Agenda();
await App.Database.SaveAgendaAsync(agenda);
await Application.Current.MainPage.DisplayAlert("Save", "La tâche a été enregistrée", "OK");
}
}
}
NewFormPage.xaml.cs in the Views folder
using Calculette.Models;
using Calculette.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Calculette.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class NewFormPage : ContentPage
{
public NewFormPage ()
{
InitializeComponent ();
// BindingContext = new Agenda();
BindingContext = new NewFormViewModel();
}
}
}
AgendaPage.xaml in the views folder (xaml that calls Clicked that open NewFormPage
<ImageButton Source="iconplus.png" HeightRequest="30" WidthRequest="30" Clicked="GoToNewFormPage"></ImageButton>
the GoToNewFormPage function in AgendaPage.xaml.cs
protected async void GoToNewFormPage(object sender, EventArgs e)
{
await Navigation.PushAsync(new Views.NewFormPage());
}
You did not set value for the object's property when clicking on the add icon.
async Task SaveForm()
{
IsBusy = true;
await Task.Delay(4000);
IsBusy = false;
Agenda agenda = new Agenda();
//here you should set value of a blank object
Agenda.Topic = xx;
Agenda.Date = xx;
Agenda.Duration = xx;
await App.Database.SaveAgendaAsync(agenda);
await Application.Current.MainPage.DisplayAlert("Save", "La tâche a été enregistrée", "OK");
}
all of your properties are implemented incorrectly
this will lead to an infinite recursive loop - Duration will call Duration will call Duration... until your app crashes
public string Duration
{
// this will just call the capital-D Duration property again
// which will then call itself again, and again, and again
get => Duration;
set
{
// this will call the setter for the capital-D Duration property recursively
Duration = value;
NotifyPropertyChanged();
}
}
you need to have a private backing field that is named differently than the property
private string duration;
public string Duration
{
get => duration;
set
{
duration = value;
NotifyPropertyChanged();
}
}

Binding text label on a home page to a timer

We have a really simple app, the idea is the timer will update a label on the home screen depending on different configuration within the mobile app. I have created the binding and can update the homepage from it's self but not from the timer. I think what is missing is a OnChange within the home page to detect if the string has changed.
Display layout code, bind the label to the name "LabelText"
<Label
Text = "{Binding LabelText, Mode=TwoWay}"
x:Name="MainPageStatusText"
HorizontalOptions="CenterAndExpand"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="6"
VerticalOptions="CenterAndExpand"
TextColor="White"
FontSize="Medium"/>
This is the class file to link the text string to the label, I can see it been called from the different places but when it's called from the app.cs it does not work
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Xamarin.Forms;
namespace Binding_Demo
{
public class MyClass : INotifyPropertyChanged
{
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{ PropertyChanged?.Invoke(this, e); }
protected void OnPropertyChanged(string propertyName)
{ OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); }
public event PropertyChangedEventHandler PropertyChanged;
private string labelText;
public string LabelText
{
get {
return labelText;
}
set
{
labelText = value;
OnPropertyChanged("LabelText");
}
}
}
}
This is the code inside the homepage, this works and I can see it sending data to the text label
public static MyClass _myClass = new MyClass();
public Homepage()
{
BindingContext = _myClass;
_myClass.LabelText = "Inside the home page";
}
This is the App.cs code, we start the timer and then want to set the text on the Homepage label. I can see the class been called, but it does not set the text.
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Binding_Demo
{
public partial class App : Application
{
public static MyClass _myClass = new MyClass();
public App()
{
//InitializeComponent();
Device.StartTimer(TimeSpan.FromSeconds(10), () =>
{
Task.Run(() =>
{
Debug.WriteLine("Timer has been triggered");
// !!!!! This is not setting the text in the label !!!!!
BindingContext = _myClass;
_myClass.LabelText = "Inside the timer app";
});
return true; //use this to run continuously
});
MainPage = new NavigationPage(new MainPage());
}
protected override void OnStart()
{
//
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
// force app to mainpage and clear the token
}
}
}
I have created the binding and can update the homepage from it's self but not from the timer.
As Jason said, please make sure the binding model is unique. You could create a global static instance of MyClass in App class, then bind this instance to HomePage.
Check the code:
App.xaml.cs
public partial class App : Application
{
public static MyClass _myClass = new MyClass();
public App()
{
InitializeComponent();
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
{
Task.Run(() =>
{
_myClass.LabelText = "Inside the timer app";
});
return true;
});
MainPage = new NavigationPage(new Homepage());
}
}
Homepage.xaml.cs:
public Homepage()
{
InitializeComponent();
BindingContext = App._myClass;
}

Multiple Tiles ItemClickCommand issue for Grail

i have follow grial grid to enable the itemClickCommand.
below is the source code DashboardMultipleTilesPage.xaml:
<grial:GridView
WidthRequest="320"
Margin="0"
Padding="10"
ColumnSpacing="10"
RowSpacing="10"
ItemsSource="{ Binding Items }"
ItemClickCommand="{ Binding ItemCommand }"
ItemTemplate="{ StaticResource Selector }"
ColumnCount="2"/>
and below is from DashboardMultipleTilesViewModel.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows.Input;
using UXDivers.Grial;
using Xamarin.Forms;
namespace QlikApps
{
public class DashboardMultipleTilesViewModel :ObservableObject
{
private readonly Command _itemCommand;
public ICommand ItemCommand => _itemCommand;
public DashboardMultipleTilesViewModel(): base(listenCultureChanges: true)
{
_itemCommand = new Command<DashboardMultipleTilesPage>(ItemAction);
LoadData();
}
public ObservableCollection<DashboardMultipleTileItemData> Items { get; } = new ObservableCollection<DashboardMultipleTileItemData>();
protected override void OnCultureChanged(CultureInfo culture)
{
LoadData();
}
private void LoadData()
{
Items.Clear();
JsonHelper.Instance.LoadViewModel(this, source:"NavigationDashboards.json");
}
private void ItemAction(DashboardMultipleTilesPage items)
{
Application.Current.MainPage.DisplayAlert("Hello",
items.Title, "OK");
string id = items.id;
}
}
}
ItemAction(DashboardMultipletilesPage item) not fire at all?
How to access data which currently point to the grid?
please help.
You can improve
public ICommand ItemCommand {get; set;}
And
ItemCommand = new Command<DashboardMultipleTilesPage>(ItemAction);
Update:
Make sure you have set the BindingContext in your ContentPage.

Xamarin ListView binding is not working

I have been trying to bind my ListView to my View model. The view model successfully retrieves 5 records from the database and the Listview seems to display 5 blank rows, however it is not showing binding for each field within each row.
I have spent a couple of days searching internet but I don't seem to be doing anything different. I was using master detail pages so I thought that it may be the issue so I set my Events page as first navigation page without master/detail scenario but to no avail. Please note that I am using Portable Ninject for my dependencies/IoC.
My App.Xamal.cs is is as follows:
public App (params INinjectModule[] platformModules)
{
InitializeComponent();
var eventsPage = new NavigationPage(new EventsPage());
//Register core services
Kernel = new StandardKernel(new MyAppCoreModule(), new MyAppNavModule(eventsPage.Navigation));
//Register platform specific services
Kernel.Load(platformModules);
//Get the MainViewModel from the IoC
eventsPage.BindingContext = Kernel.Get<EventsViewModel>();
((BaseViewModel)(eventsPage.BindingContext)).Init();
MainPage = eventsPage;
}
My EventsPage.Xaml is provided below:
<?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="MyApp.Views.EventsPage"
Title="Events">
<ContentPage.Content>
<ListView x:Name="Events" ItemsSource="{Binding Events}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding EventID}" BackgroundColor="Red" TextColor="White"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
My EventsPage.xaml.cs is provided below:
namespace MyApp.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class EventsPage : ContentPage, IBaseViewFor<EventsViewModel>
{
public EventsPage ()
{
InitializeComponent ();
}
EventsViewModel _vm;
public EventsViewModel ViewModel
{
get => _vm;
set
{
_vm = value;
BindingContext = _vm;
}
}
}
}
My EventsViewModel is as follows, it successfully retrieves 5 records and OnPropertyChanged is fired for Events property:
namespace MyApp.ViewModels
{
public class EventsViewModel : BaseViewModel, IBaseViewModel
{
ObservableCollection<Event> _events;
readonly IEventDataService _eventDataService;
public ObservableCollection<Event> Events
{
get { return _events; }
set
{
_events = value;
OnPropertyChanged();
}
}
public EventsViewModel(INavService navService, IEventDataService eventDataService) : base(navService)
{
_eventDataService = eventDataService;
Events = new ObservableCollection<Event>();
}
public override async Task Init()
{
LoadEntries();
}
async void LoadEntries()
{
try
{
var events = await _eventDataService.GetEventsAsync();
Events = new ObservableCollection<Event>(events);
}
finally
{
}
}
}
}
My BaseViewModel is as follows:
namespace MyApp.ViewModels
{
public abstract class BaseViewModel : INotifyPropertyChanged
{
protected INavService NavService { get; private set; }
protected BaseViewModel(INavService navService)
{
NavService = navService;
}
bool _isBusy;
public bool IsBusy
{
get
{
return _isBusy;
}
set
{
_isBusy = value;
OnPropertyChanged();
OnIsBusyChanged();
}
}
protected virtual void OnIsBusyChanged()
{
}
public abstract Task Init();
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
// Secod BaseViewModel abstract base class with a generic type that will be used to pass strongly typed parameters to the Init method
public abstract class BaseViewModel<TParameter> : BaseViewModel
{
protected BaseViewModel(INavService navService) : base(navService)
{
}
public override async Task Init()
{
await Init(default(TParameter));
}
public abstract Task Init(TParameter parameter);
}
}
IBaseViewModel is just a blank interface:
public interface IBaseViewModel
{
}
IBaseViewFor is given below:
namespace MyApp.ViewModels
{
public interface IBaseViewFor
{
}
public interface IBaseViewFor<T> : IBaseViewFor where T : IBaseViewModel
{
T ViewModel { get; set; }
}
}
My Event model is as follows:
namespace MyApp.Models
{
public class Event
{
public int EventID;
}
}
Finally, the image of the output, as you can see that 5 rows are created with red background but EventID is not binding in each row. I have checked the data and EventID is returned. I have even tried to manually add records into Events list but to no avail, see the manual code and image below:
async void LoadEntries()
{
try
{
Events.Add((new Event() { EventID = 1 }));
Events.Add((new Event() { EventID = 2 }));
Events.Add((new Event() { EventID = 3 }));
Events.Add((new Event() { EventID = 4 }));
Events.Add((new Event() { EventID = 5 }));
}
finally
{
}
}
I have spent a lot of time on it but unable to find a reason for this anomaly, can someone please cast a fresh eye and provide help!?
You can only bind to public properties - ie, you need a getter
public class Event
{
public int EventID { get; set; }
}

Resources