Reputation: 859
I'm trying to have a ViewModel that updates a counter on a XAML page but can't figure out what I'm doing wrong...
The initial value of itemCount is well displayed but after each increment it is not updated.
Here is the XAML source 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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
xmlns:local="clr-namespace:XamarinFormsTest01"
mc:Ignorable="d"
x:Class="XamarinFormsTest01.MainPage">
<StackLayout>
<Label x:Name="lblMain" Text="{Binding ItemCount}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" >
<Label.BindingContext>
<local:ItemCountViewModel />
</Label.BindingContext>
</Label>
<Button x:Name="BtnStart" Text="start" Pressed="BtnStart_Pressed" />
<Button x:Name="BtnStop" Text="stop" Pressed="BtnStop_Pressed" />
</StackLayout>
</ContentPage>
And the ViewModel source code :
public class ItemCountViewModel : INotifyPropertyChanged
{
private static ItemCountViewModel instance = new ItemCountViewModel();
public static ItemCountViewModel GetInstance()
{
return instance;
}
int itemCount;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public ItemCountViewModel()
{
itemCount = 0;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
itemCount++;
return true;
}
);
}
public int ItemCount
{
set
{
itemCount = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ItemCount"));
}
get
{
return itemCount;
}
}
}
Upvotes: 0
Views: 972
Reputation: 9723
From ItemCount.set
you are raising PropertyChanged
, which is required for the view to update according to the state of the viewmodel. Otherwise the view would have to poll for state changes, which would be a waste of resources, especially on mobile devices where we'd like to avoid draining the battery by overusing the processor.
Anyway, when setting itemCount
directly as you are doing in
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
itemCount++;
return true;
}
ItemCount.set
is never called, hence PropertyChanged
is never raised and the view has got no chance to determine that the viewmodel changed its state. Furthermore I guess that ItemCount
has to be set in the UIs main thread, hence you have to wrap the call to ItemCount.set
by Device.BeginInvokeOnMainThread
(see the documentation)
Change the code to
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
Device.BeginInvokeOnMainThread (() =>
{
ItemCount++;
});
return true;
}
and the view should update.
Upvotes: 2