I have a CalendarioView from this Xamarin.Plugin.Calendar nuget package.
I've been following this tutorial, and I want to have the same result. Instead of assigning the EventCollection list manually, as in the example, I have my List.
How to fill it in the EventCollection? I've searched and didn't find anything that worked.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:c ="clr-namespace:Minha_Carteira_Hospitalar.Controls"
x:Class="Minha_Carteira_Hospitalar.Views.PlanoReceita"
xmlns:controls="clr-namespace:Xamarin.Plugin.Calendar.Controls;assembly=Xamarin.Plugin.Calendar">
<controls:Calendar
Events="{Binding Events}"
>
<controls:Calendar.EventTemplate>
<DataTemplate>
<StackLayout Padding="15,0,0,0">
<Label
Text="{Binding Name}"
FontAttributes="Bold"
FontSize="Medium" />
</StackLayout>
</DataTemplate>
</controls:Calendar.EventTemplate>
</controls:Calendar>
MVVM code
public EventCollection Events;
public ObservableCollection<Plans> myPlans= new ObservableCollection<Plans>();
public ObservableCollection<Plans> MyPlans
{
get => myPlans;
set => myPlans= value;
}
public MyPlansViewModel()
{
Events = new EventCollection();
}
public ICommand LoadingMyPlans
{
get
{
return new Command(async () =>
{
try
{
List<Plans> tmp = await App.Database.GetMyPlans();
foreach(var item in tmp)
{
MyPlans.Clear();
tmp.ForEach(i => MyPlans.Add(i));
Events.Add(item.DatePlan, MyPlans);
}
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
}
});
}
}
I am not sure where you use the LoadingMyPlans for. I make a simple example about how to fill your own list into EventCollection for your reference.
The same Xaml as yours.
Model:
public class Plans
{
public DateTime dateTime { get; set; }
public List<Plan> plans { get; set; }
}
public class Plan
{
public string Name { get; set; }
public string Desc { get; set; }
}
ViewModel:
public class CalendarViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value))
{
return false;
}
storage = value;
OnPropertyChanged(propertyName);
return true;
}
public EventCollection Events { get; set; }
public ObservableCollection<Plans> plans { get; set; }
public CalendarViewModel()
{
plans = new ObservableCollection<Plans>()
{
new Plans(){ dateTime=DateTime.Now, plans=new List<Plan>() { new Plan() { Name = "Plan_A", Desc = "aaaaa" }, new Plan() { Name = "Plan_A2", Desc = "aaaaa2" } }},
new Plans(){ dateTime=DateTime.Now.AddDays(5), plans=new List<Plan>() { new Plan() { Name = "Plan_B", Desc = "bbbbb" }, new Plan() { Name = "Plan_B2", Desc = "aaaaa2" } }},
new Plans(){ dateTime=DateTime.Now.AddDays(-3), plans=new List<Plan>() { new Plan() { Name = "Plan_C", Desc = "ccccc" }}}
};
Events = new EventCollection();
foreach (var item in plans)
{
Events.Add(item.dateTime, item.plans);
}
}
}
Code behind:
public Page2()
{
InitializeComponent();
this.BindingContext = new CalendarViewModel();
}
Related
I have 1 question here: How to get data from ViewModel in Xamarin, however I still haven't solved the problem. I created a new post with some changes.
I have:
PageOne.xaml
<StackLayout>
<RefreshView x:DataType="locals:ViewCustomerViewModel" Command="{Binding LoadUserinfoCommand}" IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<Label Text="{Binding Customer.Address}" />
</RefreshView>
</StackLayout>
PageOne.xaml.cs
ViewCustomerViewModel viewCustomerViewModel;
public Customer CustomerGet { get; set; }
public PageOne()
{
InitializeComponent();
BindingContext = viewCustomerViewModel = new ViewCustomerViewModel();
viewCustomerViewModel.OnAppearing();
}
Class Customer
public class Customer
{
public string Address{ get; set; }
........
}
ViewCustomerViewModel
public class ViewCustomerViewModel:BaseCustomerViewModel
{
ApiServiceUserinfo apiServiceUserinfo = new ApiServiceUserinfo();
public Command LoadUserinfoCommand { get; }
public ObservableCollection<Customer> CustomerInfos { get; set; }
public ViewCustomerViewModel()
{
LoadUserinfoCommand = new Command(async () => await ExecuteLoadUserinfoCommand());
CustomerInfos = new ObservableCollection<Customer>();
}
public void OnAppearing()
{
IsBusy = true;
}
async Task ExecuteLoadUserinfoCommand()
{
string userget = "1";
IsBusy = true;
try
{
CustomerInfos.Clear();
var customerList = await apiServiceUserinfo.GetCustomersInfo(userget);
CustomerInfos.Add(customerList);
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
}
And I got the result CustomerInfos.Add(customerList);
However <Label Text="{Binding Customer.Address}" /> does not get results
Please help me again clearly in the answer. Thank you.
Update
ViewCustomerViewModel
public class ViewCustomerViewModel:BaseCustomerViewModel
{
ApiServiceUserinfo apiServiceUserinfo = new ApiServiceUserinfo();
public Command LoadUserinfoCommand { get; set;}
public Customer CustomerGets { get; set;}--> update
public ViewCustomerViewModel()
{
LoadUserinfoCommand = new Command(async () => await ExecuteLoadUserinfoCommand());
//CustomerGets = new Customer();
}
public void OnAppearing()
{
IsBusy = true;
}
async Task ExecuteLoadUserinfoCommand()
{
string userget = "1";
IsBusy = true;
try
{
var customerList = await apiServiceUserinfo.GetCustomersInfo(userget);
CustomerGets = customerList;
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
}
PageOne.xaml
<StackLayout>
<RefreshView x:DataType="locals:ViewCustomerViewModel" Command="{Binding LoadUserinfoCommand}" IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<Label Text="{Binding CustomerGets.Address}" />
</RefreshView>
</StackLayout>
We need to call the OnPropertyChanged method to notify the change in setter method of the property .
private Customer customerGets;
public Customer CustomerGets {
get { return customerGets; }
set {
customerGets = value;
NotifyPropertyChanged(); //the method is declared in BaseCustomerViewModel
}
}
Ensure that BaseCustomerViewModel has implemented INotifyPropertyChanged , something like that
public class BaseCustomerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Suppose I have the following classes:
class Person
{
public string Name { get; set; }
public IList<Expense> Expenses { get; set; }
public int Total => Expenses.Sum(o => o.Amount);
}
class Expense
{
public string ExpenseName { get; set; }
public int Amount { get; set; }
}
And then I have a collection of persons: IList<Person> Persons
How can I design an XAML page in Xamarin, in order to show something like this?:
You can use Label to display the variable number of expenses, In the end of item, add "\n" to wrap.
The running screenshot like following img.
First, here is my layout.
<StackLayout>
<ListView x:Name="EmployeeView" HasUnevenRows="True"
ItemsSource="{Binding Persons}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label FontSize="Large" Text="{Binding Name}"></Label>
<Label FontSize="Body" Text="{Binding ExpensesList}"></Label>
<Label FontSize="Body" Text="{Binding Total}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Here is layout's background code.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext =new MyViewModel();
}
}
Here is my viewModel. I add some testing data to viewModel, And add "\n" to the end of every expense's text.
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace App83
{
internal class MyViewModel
{
public ObservableCollection<Person> Persons { get; set; }
public MyViewModel()
{
Persons = new ObservableCollection<Person>();
ObservableCollection<Expense> expenses= new ObservableCollection<Expense>();
expenses.Add(new Expense() { Amount=1, ExpenseName="name1" });
expenses.Add(new Expense() { Amount = 1, ExpenseName = "name2" });
expenses.Add(new Expense() { Amount = 1, ExpenseName = "name3" });
expenses.Add(new Expense() { Amount = 1, ExpenseName = "name4" });
ObservableCollection<Expense> expenses2 = new ObservableCollection<Expense>();
expenses2.Add(new Expense() { Amount = 1, ExpenseName = "name1" });
ObservableCollection<Expense> expenses3 = new ObservableCollection<Expense>();
string expensesList1="";
for (int i = 0; i < expenses.Count; i++)
{
if(i== (expenses.Count - 1))
{
expensesList1 += expenses[i].ToString();
}
else
{
expensesList1 += expenses[i].ToString() + "\n";
}
}
string expensesList2 = "";
for (int i = 0; i < expenses2.Count; i++)
{
if (i == (expenses2.Count - 1))
{
expensesList2 += expenses2[i].ToString();
}
else
{
expensesList2 += expenses2[i].ToString() + "\n";
}
}
string expensesList3 = "";
for (int i = 0; i < expenses3.Count; i++)
{
if (i == (expenses3.Count - 1))
{
expensesList3 += expenses3[i].ToString();
}
else
{
expensesList3 += expenses3[i].ToString() + "\n";
}
}
Person per =new Person( ) { Name="test1", Expenses= expenses, expensesList= expensesList1 };
Person per2 = new Person() { Name = "test2", Expenses = expenses2,expensesList= expensesList2 };
Person per3 = new Person() { Name = "test3", Expenses = expenses3, expensesList = expensesList3 };
Persons.Add(per);
Persons.Add(per2);
Persons.Add(per3);
}
}
}
Here is my edited Model. AddExpensesList perperty to show variable number of expenses, keep the ExpenseName and Amountin the same line, I override the ToString method.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace App83
{
public class Person: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Person() {
}
public string Name { get; set; }
public string expensesList;
public string ExpensesList
{
set
{
if (expensesList != value)
{
expensesList = value;
OnPropertyChanged("Image");
}
}
get
{
return expensesList;
}
}
public IList<Expense> Expenses { get; set; }
public int Total => Expenses.Sum(o => o.Amount);
}
public class Expense
{
public string ExpenseName { get; set; }
public int Amount { get; set; }
public override string ToString()
{
return ExpenseName+" "+Amount;
}
}
}
Within your DataTemplate you can add another View that supports the ItemSource property.
So it could be another ListView, CollectionView or a StackLayout. The latter is great if you know that you won't have too many items under expense as otherwise it might cause serious app performance issues.
So inside of your DataTemplate just add
<CollectionView ItemSource={Binding Expenses}>
<DataTemplate>
//your UI goes here
.
.
.
Binding command to a Button - yields no effect (Xamarin, MVVM):
notes:
Pressing the Button and nothing happens: no CanExecute check occur.
Binding a Button in a ContentPage which is Part of a Tabbed-Template
functionality check and the rest of related MVVM binding works well: Defined a clicked-event and manually triggered the command from the code behind.
//Could someone see the reason?// editted
editted, new:
What would be a good practice when CanExecute relies on fields of a compound data type that are updated independently ? (*can take of the command parameter which is the compound data type, which is accessible to the command directly through the VM).
xaml for the View:
<ContentPage.Content>
<StackLayout>
<Entry Placeholder="Notes"/>
<Entry x:Name="courseIDEntry"
Text="{Binding CourseID, Mode=TwoWay}"
IsReadOnly="{Binding !ExistUnit}"
Placeholder="CourseID *"/>
<Entry x:Name="unitIDEntry"
Text="{Binding UnitID, Mode=TwoWay}"
IsReadOnly="{Binding !ExistUnit}"
Placeholder="UnitID *"/>enter code here
<Label Text="* Fields are mandatory"/>
<Button x:Name="AddSave"
Text="{Binding CommandText}"
Command="{Binding AddSaveCMD}"
CommandParameter="{Binding EdittedUnit}"/>
<!--Clicked="AddSave_Clicked"/>-->
</StackLayout>
</ContentPage.Content>enter code here
c# code behind for the view (*including the Button-Clicked check for)
public partial class EditUnitPage : ContentPage
{
EditUnitViewModel editUVM;
public EditUnitPage()
{
InitializeComponent();
editUVM = new EditUnitViewModel();
BindingContext = editUVM;
}
public EditUnitPage(Unit6 unitSelected) : this()
{
if (unitSelected != null)
{
editUVM.EdittedUnit = unitSelected;
editUVM.ExistUnit = true;
}
}
protected override void OnAppearing()
{
base.OnAppearing();
}
//private void AddSave_Clicked(object sender, EventArgs e)
//{
// if (editUVM.AddSaveCMD.CanExecute(editUVM.EdittedUnit))
// {
// editUVM.AddSaveCMD.Execute(null);
// }
//}
}
C# MyCommand (newbie. using ICommand and not the Command Class)
public class AddSaveUnitCommand : ICommand
{
public EditUnitViewModel EditUVM { get; set; }
public event EventHandler CanExecuteChanged;
public AddSaveUnitCommand(EditUnitViewModel euvm)
{
EditUVM = euvm;
}
public bool CanExecute(object parameter)
{
var editted = parameter as Unit6;
if (editted != null )
{
if (!string.IsNullOrEmpty(editted.CourseID) || !string.IsNullOrEmpty(editted.UnitID))
return true;
}
return false;
}
public void Execute(object parameterf)
{
EditUVM.AddSaveUnitAsync();
}
}
c# for VM (BaseViewModel implements INotify)
public class EditUnitViewModel : BaseViewModel
{
public AddSaveUnitCommand AddSaveCMD { get; set; }
private Unit6 edittedUnit;
public Unit6 EdittedUnit
{
get { return edittedUnit; }
set { edittedUnit = value; OnPropertyChanged(); }
}
private bool existUnit;
public bool ExistUnit
{
get { return existUnit; }
set
{
existUnit = value;
//OnPropertyChanged();
}
}
public string CommandText
{
get { return ExistUnit? "Save": "Add"; }
}
public string CourseID
{
get { return EdittedUnit.CourseID; }
set { EdittedUnit.CourseID = value; OnPropertyChanged(); }
}
public string UnitID
{
get { return EdittedUnit.UnitID; }
set { EdittedUnit.UnitID = value; OnPropertyChanged(); }
}
public EditUnitViewModel()
{
EdittedUnit = new Unit6();
AddSaveCMD = new AddSaveUnitCommand(this);
}
public async void AddSaveUnitAsync()
{
var curPage = App.Current.MainPage;
try
{
switch (ExistUnit)
{
case false: //insert new unit to the DB
EdittedUnit.UnitKey = ""; //Todo: look for more elegant of assigning auto value to property
Unit6.Insert(EdittedUnit);
break;
case true: //update details on existing unit
EdittedUnit.UnitKey = ""; //Todo: look for more elegant of assigning auto value to property
Unit6.Update(EdittedUnit);
break;
}
await curPage.DisplayAlert("Success", "Unit was succesffuly updateded", "OK");
}
catch
{
await curPage.DisplayAlert("Error", "Unit was not updated", "OK");
}
finally
{
EdittedUnit = null;
await curPage.Navigation.PushAsync(new MyTabbedPage());
}
}
}
xaml for the TabbedPage:
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:P205.Views"
x:Class="P205.Views.MyTabbedPage">
<views:UnitsPage Title="Units" />
<views:EditUnitPage x:Name="editOrAddUnit" Title="Edit U"/>
<views:DBChangesPage Title="Edit DB"/>
<views:CoursesPage Title="Course"/>
<ContentPage Padding="10">
</ContentPage>
When your ViewModel defines a property of type ICommand, the ViewModel must also contain or reference a class that implements the ICommand interface. This class must contain or reference the Execute and CanExecute methods, and fire the CanExecuteChanged event whenever the CanExecute method might return a different value.
So you could try change like below:
public class AddSaveUnitCommand : ICommand
{
public EditUnitViewModel EditUVM { get; set; }
public event EventHandler CanExecuteChanged;
public AddSaveUnitCommand(EditUnitViewModel euvm)
{
EditUVM = euvm;
}
public bool CanExecute(object parameter)
{
var editted = parameter as Unit6;
if (editted != null )
{
if (!string.IsNullOrEmpty(editted.CourseID) || !string.IsNullOrEmpty(editted.UnitID))
return true;
}
return false;
}
public void Execute(object parameterf)
{
EditUVM.AddSaveUnitAsync();
CanExecuteChanged?.Invoke(this, EventArgs.Empty); //add this line.
}
}
I have a xamarin forms application and would like to save some values that I got from the picker via the web api. The objective is to save this value as well as the other properties in the web api that is linked to the sql server database, but I have issues in how to reference the value selected in the picker through mvvm. I can load the data from the picker but I just don't know how to save these values by referencing the picker in mvvm.
UsuarioModel Class
This is the model class, it has the CodPerfil property which is the foreign key that should be stored in my web api database and must correspond to the value that will be selected in the picker.
public class UsuarioModel
{
public int CodUsuario { get; set; }
public string Nome { get; set; }
public string Senha { get; set; }
public int Telefone { get; set; }
public DateTime DataRegisto { get; set; }
public bool Estado { get; set; }
public int CodPerfil { get; set; }
}
PerfilModel Class
public class PerfilModel
{
public int CodPerfil { get; set; }
public string Titulo { get; set; }
}
Web API Controller to Insert Data
public IHttpActionResult Registo(UsuarioModel usuario)
{
connection();
SqlCommand cmd = new SqlCommand("SpAddNewUser", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Nome", usuario.Nome);
cmd.Parameters.AddWithValue("#Senha", usuario.Senha);
cmd.Parameters.AddWithValue("#Telefone", usuario.Telefone);
cmd.Parameters.AddWithValue("#CodPerfil", usuario.CodPerfil);
conn.Open();
cmd.ExecuteNonQuery();
return Ok();
}
Web API Controller to Get Data for Picker in Xamarin
public IEnumerable<PerfilModel> GetPerfisApp()
{
List<PerfilModel> perfilModels = new List<PerfilModel>();
connection();
SqlCommand cmd = new SqlCommand("SpGetPerfilApp", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
PerfilModel perfil = new PerfilModel();
perfil.CodPerfil = Convert.ToInt32(reader["CodPerfil"]);
perfil.Titulo = reader["Titulo"].ToString();
perfilModels.Add(perfil);
}
conn.Close();
return perfilModels;
}
ViewModel Class
public class AddRegistoUsuarioViewModel : BaseViewModel
{
ApiServices _apiServices = new ApiServices();
string _nome;
public string Nome
{
get
{
return _nome;
}
set
{
if (value != null)
{
_nome = value;
OnPropertyChanged();
}
}
}
string _senha;
public string Senha
{
get
{
return _senha;
}
set
{
if (value != null)
{
_senha = value;
OnPropertyChanged();
}
}
}
int _telefone;
public int Telefone
{
get
{
return _telefone;
}
set
{
_telefone = value;
OnPropertyChanged();
}
}
int _codperfil;
public int CodPerfil
{
get
{
return _codperfil;
}
set
{
_codperfil = value;
OnPropertyChanged();
}
}
public string Message { get; set; }
public ICommand Registar
{
get
{
return new Command(async () =>
{
var usuario = new UsuarioModel
{
Nome = Nome,
Senha = Senha,
Telefone = Telefone,
CodPerfil = SelectedPerfil.CodPerfil
};
await _apiServices.RegistoUsuarioAsync(usuario);
});
}
}
public AddRegistoUsuarioViewModel()
{
GetPerfisApp();
}
public async void GetPerfisApp()
{
using (var client = new HttpClient())
{
var uri = "https://webapiigarbage-ff4.conveyor.cloud/api/Usuario/PerfisApp";
var result = await client.GetStringAsync(uri);
var PerfilList = JsonConvert.DeserializeObject<List<PerfilModel>>(result);
Perfis = new ObservableCollection<PerfilModel>(PerfilList);
}
}
PerfilModel _selectedPerfil;
public PerfilModel SelectedPerfil
{
get
{
return _selectedPerfil;
}
set
{
if (SelectedPerfil != value)
{
_selectedPerfil = value;
OnPropertyChanged();
}
}
}
ObservableCollection<PerfilModel> _perfis;
public ObservableCollection<PerfilModel> Perfis
{
get
{
return _perfis;
}
set
{
_perfis = value;
OnPropertyChanged();
}
}
}
API Service Class
I tried to use this form: CodPerfil = SelectedPerfil.CodPerfil
But I was not successful.
public async Task RegistoUsuarioAsync(UsuarioModel usuario)
{
var client = new HttpClient();
var json = JsonConvert.SerializeObject(usuario);
HttpContent content = new StringContent(json);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync("https://mywebsite/api/Usuario/Registo", content);
}
RegisterPage.xaml.cs
public RegisterPage()
{
InitializeComponent();
BindingContext = new RegistoUsuarioViewModel();
}
RegisterPage.xaml
<Entry Placeholder="Nome de Usuário"
x:Name="NomeEntry" />
<Picker x:Name="PerfilPicker" Title="Selecione o seu Perfil" FontSize="Large" HorizontalOptions="Center"
ItemsSource="{Binding Perfis}"
ItemDisplayBinding="{Binding Titulo}"
SelectedItem="{Binding SelectedPerfil}" />
<Entry Placeholder="Número de Telemóvel"
x:Name="TelefoneEntry"
Keyboard="Telephone"/>
<Entry Placeholder="Senha" x:Name="SenhaEntry" IsPassword="True"/>
<Button Text="Registar"
TextColor="White"
BackgroundColor="#07E3B0"
x:Name="ButtonLogin"
Command="{Binding Registar}"/>
I would be grateful if someone could help me.
thanks for the tips. what happened was that the viewmodel that was being binded in the Register.xaml.cs class was not the one that contained the Register command. I solve the 'problem' by replacing the viewmodel and it worked!
RegisterPage.xaml.cs
public RegisterPage()
{
InitializeComponent();
BindingContext = new AddRegistoUsuarioViewModel();
}
I am trying to make simple app which will provide features to read/write data to database trough an Web API.
I have view model which is bind to view, but it is not working properly after web api get request, even that call was successfully done. I've tried to check value with display alert, value is correct, but it is not presented in view part, exactly in one label. Here is my 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"
x:Class="SOSEUApp.Pages.NotePage"
Title="Dnevnik">
<ContentPage.ToolbarItems>
<ToolbarItem Text="GET" Clicked="ToolbarItem_Clicked"></ToolbarItem>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}"></ActivityIndicator>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Date,StringFormat='Date: {0}'}"></Label>
</StackLayout>
<StackLayout>
</StackLayout>
</StackLayout>
</ContentPage.Content>
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class NotePage : ContentPage
{
NoteViewModel nvm = new NoteViewModel();
public NotePage()
{
InitializeComponent();
BindingContext = nvm;
}
private async void ToolbarItem_Clicked(object sender, EventArgs e)
{
nvm.IsBusy = true;
nvm.Notes = await App.NotesWebApiService.GetAll(nvm.CurrentActiveNote.Route);
nvm.GetLastNote();
nvm.IsBusy = false;
await DisplayAlert("Info", nvm.Date.ToString(), "Close");
}
}
public class NoteViewModel : BaseViewModel
{
IList<Note> notes = new List<Note>();
public IList<Note> Notes
{
get { return notes; }
set { SetProperty(ref notes, value); }
}
private Note currentActiveNote = new Note();
public Note CurrentActiveNote { get { return currentActiveNote; } }
public string Date { get { return currentActiveNote.Date.ToString("dd.MM.yyyy"); } }
public string OrderedNumber
{
get { return currentActiveNote.OrderNumber.ToString(); }
set
{
string v = currentActiveNote.OrderNumber.ToString();
SetProperty(ref v, value);
currentActiveNote.OrderNumber = Convert.ToInt16(v);
}
}
public string Description
{
get { return currentActiveNote.Description; }
set
{
string v = currentActiveNote.Description;
SetProperty(ref v, value);
currentActiveNote.Description = v;
}
}
public void GetLastNote()
{
notes.OrderBy(a => a.Date);
currentActiveNote = notes.Last();
}
}
public class BaseViewModel : DataModel, INotifyPropertyChanged
{
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName]string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Thank you in advance!
just called SetProperty method and passed desired values there. It works
Said as Jason, you need to fire a PropertyChanged event when Date changes.Here is official document for reference.
Generally, usually writed in Set methods.As follow:
private string propertyname;
public string PropertyName
{
set { SetProperty(ref propertyname, value); }
get { return propertyname; }
}
Or write as follow:
public string PropertyName
{
set
{
if (propertyname!= value)
{
propertyname= value;
OnPropertyChanged("PropertyName");
}
}
get
{
return propertyname;
}
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
When data of model change , this will be invoked automatically.