ObservableCollection Class

ObservableCollection is defined in System.Collections.ObjectModel. It implements the INotifyCollectionChanged interface, which is in System.Collections.Specialized. ObservableCollection executes a CollectionChanged event any time any of its data changes. ListView checks for this event to know when it must redraw itself.

Consider the following 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:local="clr-namespace:HelloXamarinForms"
		x:Class="HelloXamarinForms.MainPageXaml">

	<ContentPage.Padding>
		<OnPlatform x:TypeArguments="Thickness" iOS="10, 20, 10, 0" Android="10, 0" />
	</ContentPage.Padding>

	<ListView x:Name="listView" />

</ContentPage>
using System;
using Xamarin.Forms;

namespace HelloXamarinForms
{
	public partial class MainPageXaml : ContentPage
	{
		public MainPageXaml()
		{
			InitializeComponent();

			System.Collections.Generic.List<DateTime> list =
				new System.Collections.Generic.List<DateTime>();

			list.Add(DateTime.Now);

			listView.ItemsSource = list;

			Device.StartTimer(TimeSpan.FromSeconds(1), () =>
			{
				list.Insert(0, DateTime.Now);
				return true;
			});
		}
	}
}

When the previous code is run, the ListView does not update the screen because List does not support the INotifyCollectionChanged interface. In other words, it does not execute a CollectionChanged event.

Run the exact same code using an ObservableCollection instead of a List.

using System;
using Xamarin.Forms;

namespace HelloXamarinForms
{
	public partial class MainPageXaml : ContentPage
	{
		public MainPageXaml()
		{
			InitializeComponent();

			System.Collections.ObjectModel.ObservableCollection<DateTime> list =
				new System.Collections.ObjectModel.ObservableCollection<DateTime>();

			list.Add(DateTime.Now);

			listView.ItemsSource = list;

			Device.StartTimer(TimeSpan.FromSeconds(1), () =>
			{
				list.Insert(0, DateTime.Now);
				return true;
			});
		}
	}
}

Now the screen updates everytime a new item is inserted into the ObservableCollection. ListView and ObservableCollection have a special relationship. This is why ListView has its own article

Triggers

Using the Trigger class, change properties or execute events based on a trigger.

<?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:HelloXamarinForms"
		x:Class="HelloXamarinForms.MainPageXaml">

	<ContentPage.Padding>
		<OnPlatform x:TypeArguments="Thickness" iOS="20" Android="20, 0, 20, 20" />
	</ContentPage.Padding>

	<StackLayout Spacing="20">
		<Entry Placeholder="enter your name" AnchorX="0">
			<Entry.Triggers>
				<Trigger TargetType="Entry" Property="IsFocused" Value="True">
					<Setter Property="Scale" Value="1.25" />
				</Trigger>
			</Entry.Triggers>
		</Entry>
		<Entry Placeholder="enter your email" AnchorX="0">
			<Entry.Triggers>
				<Trigger TargetType="Entry" Property="IsFocused" Value="True">
					<Setter Property="Scale" Value="1.25" />
				</Trigger>
			</Entry.Triggers>
		</Entry>
		<Entry Placeholder="enter your state" AnchorX="0">
			<Entry.Triggers>
				<Trigger TargetType="Entry" Property="IsFocused" Value="True">
					<Setter Property="Scale" Value="1.25" />
				</Trigger>
			</Entry.Triggers>
		</Entry>
	</StackLayout>
	
</ContentPage>

Style also has a Triggers property allowing less 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:local="clr-namespace:HelloXamarinForms"
		x:Class="HelloXamarinForms.MainPageXaml">

	<ContentPage.Padding>
		<OnPlatform x:TypeArguments="Thickness" iOS="20" Android="20, 0, 20, 20" />
	</ContentPage.Padding>

	<ContentPage.Resources>
		<ResourceDictionary>
			<Style TargetType="Entry">
				<Setter Property="AnchorX" Value="0" />
				<Style.Triggers>
					<Trigger TargetType="Entry" Property="IsFocused" Value="True">
						<Setter Property="Scale" Value="1.25" />
					</Trigger>
				</Style.Triggers>
			</Style>
		</ResourceDictionary>
	</ContentPage.Resources>
				
	<StackLayout Spacing="20">
		<Entry Placeholder="enter name" />
		<Entry Placeholder="enter email" />
		<Entry Placeholder="enter state" />
	</StackLayout>
	
</ContentPage>

Here, a class, BounceAction, bounces a Button but be warned because the code in the Clicked event executes before the bounce animation is finished. See this previous page in the tutorial for an example that waits for the animation to finish.

<?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:HelloXamarinForms"
		x:Class="HelloXamarinForms.MainPageXaml">

	<ContentPage.Padding>
		<OnPlatform x:TypeArguments="Thickness" iOS="20" Android="20, 0, 20, 20" />
	</ContentPage.Padding>

	<ContentPage.Resources>
		<ResourceDictionary>
			<Style TargetType="Button">
				<Style.Triggers>
					<EventTrigger Event="Clicked">
						<local:BounceAction />
					</EventTrigger>
				</Style.Triggers>
			</Style>
		</ResourceDictionary>
	</ContentPage.Resources>
	
	<StackLayout>
		<Button Text="Bounce Button" Clicked="OnBounceButtonClick" />
	</StackLayout>

</ContentPage>
// BounceAction.cs
using Xamarin.Forms;

namespace HelloXamarinForms
{
	public class BounceAction : TriggerAction<VisualElement>
	{
		protected override async void Invoke(VisualElement ve)
		{
			await ve.ScaleTo(1.2, 100);
			await ve.ScaleTo(0.9, 125);
			await ve.ScaleTo(1.1, 150);
			await ve.ScaleTo(1, 175);
		}
	}
}
using Xamarin.Forms;

namespace HelloXamarinForms
{
	public partial class MainPageXaml : ContentPage
	{
		public MainPageXaml()
		{
			InitializeComponent();
		}

		void OnBounceButtonClick(object sender, System.EventArgs e)
		{
			DisplayAlert("BounceButton", "You clicked a bouncing button", "OK");
		}
	}
}
<< < [Page 8 of 11] > >>