0% found this document useful (0 votes)
30 views1,851 pages

Xamarin Forms

The document provides a comprehensive guide to Xamarin.Forms, an open-source UI framework for building cross-platform applications for Android, iOS, and Windows using a shared codebase. It covers installation requirements, development guidance, and various features such as XAML, data binding, and platform-specific functionalities. Additionally, it includes sections on Xamarin.Essentials, Shell, and troubleshooting, making it a valuable resource for developers looking to create mobile applications with Xamarin.Forms.

Uploaded by

svetlana20in
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views1,851 pages

Xamarin Forms

The document provides a comprehensive guide to Xamarin.Forms, an open-source UI framework for building cross-platform applications for Android, iOS, and Windows using a shared codebase. It covers installation requirements, development guidance, and various features such as XAML, data binding, and platform-specific functionalities. Additionally, it includes sections on Xamarin.Essentials, Shell, and troubleshooting, making it a valuable resource for developers looking to create mobile applications with Xamarin.Forms.

Uploaded by

svetlana20in
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1851

Contents

Xamarin.Forms
Get Started
What is Xamarin.Forms
Requirements
Installation
Installing Xamarin on Windows
Installing Xamarin Previews (Windows)
Installing Visual Studio for Mac
Installing Xamarin Previews (Mac)
Xamarin Firewall Configuration Instructions
Uninstalling Xamarin
First App
Quickstarts
File > New
Multipage
Database
Styling
Deep dive
Tutorials
Stack Layout
Label
Button
Text entry
Text editor
Images
Grid Layout
Lists
Pop-ups
App lifecycle
Local database
Web services
Learn about Xamarin
.NET developers
Java developers
Objective-C developers
Azure
Development guidance
XAML
Overview
XAML Basics
Part 1. Get Started with XAML
Part 2. Essential XAML Syntax
Part 3. XAML Markup Extensions
Part 4. Data Binding Basics
Part 5. From Data Bindings to MVVM
XAML Controls
XAML Compilation
XAML Markup Extensions
Consuming XAML Markup Extensions
Creating XAML Markup Extensions
Tooling
XAML Hot Reload
XAML Toolbox
XAML Previewer
Design-time data
Custom controls
Namespaces
XAML Namespaces
XAML Custom Namespace Schemas
XAML Namespace Recommended Prefixes
Additional Capabilities
Bindable Properties
Attached Properties
Resource Dictionaries
Passing Arguments
Field Modifiers
Loading XAML at Runtime
Application Fundamentals
Overview
Accessibility
Automation Properties
Keyboard Accessibility
App Class
App Lifecycle
Application Indexing and Deep Linking
Behaviors
Introduction
Attached Behaviors
Xamarin.Forms Behaviors
Reusable Behaviors
EffectBehavior
EventToCommandBehavior
Custom Renderers
Introduction
Renderer Base Classes and Native Controls
Customizing an Entry
Customizing a ContentPage
Customizing a Map
Customizing a Map Pin
Highlighting a Circular Area on a Map
Customizing a ListView
Customizing a ViewCell
Customizing a WebView
Implementing a View
Implementing a Video Player
Creating the Platform Video Players
Playing a Web Video
Binding Video Sources to the Player
Loading Application Resource Videos
Accessing the Device's Video Library
Custom Video Transport Controls
Custom Video Positioning
Data Binding
Basic Bindings
Binding Mode
String Formatting
Binding Path
Binding Value Converters
Relative Bindings
Binding Fallbacks
The Command Interface
Compiled Bindings
DependencyService
Introduction
Registration and Resolution
Picking from the Photo Library
Effects
Introduction
Effect Creation
Passing Parameters
Parameters as CLR Properties
Parameters as Attached Properties
Invoking Events
Reusable RoundEffect
Gestures
Tap
Pinch
Pan
Swipe
Local Notifications
Localization
String and Image Localization
Right-to-Left Localization
MessagingCenter
Navigation
Hierarchical Navigation
TabbedPage
CarouselPage
MasterDetailPage
Modal Pages
Shell
Introduction
Create a Shell application
Flyout
Tabs
Page configuration
Navigation
Search
Lifecycle
Custom Renderers
Templates
Overview
Control Templates
Data Templates
Introduction
Data Template Creation
Data Template Selection
Triggers
User Interface
Overview
Controls reference
Overview
Pages
Layouts
Views
Cells
Common properties, methods, and events
Third-party controls
Present data
BoxView
Image
Label
Map
Overview
Initialization and Configuration
Map Control
Position and Distance
Pins
Polygons and Polylines
Geocoding
Launch the Native Map App
WebView
Initiate commands
Button
ImageButton
RefreshView
SearchBar
SwipeView
Set values
CheckBox
DatePicker
Slider
Stepper
Switch
TimePicker
Edit text
Editor
Entry
Indicate activity
ActivityIndicator
ProgressBar
Display collections
CarouselView
Introduction
Data
Layout
Interaction
EmptyView
Scrolling
CollectionView
Introduction
Data
Layout
Selection
EmptyView
Scrolling
Grouping
IndicatorView
ListView
Data Sources
Cell Appearance
List Appearance
Interactivity
Performance
Picker
Setting a Picker's ItemsSource Property
Adding Data to a Picker's Items Collection
TableView
Additional controls
MenuItem
ToolbarItem
Concepts
Animation
Simple Animations
Easing Functions
Custom Animations
Colors
DataPages
Get Started
Controls Reference
Display pop-ups
Fonts
Graphics with SkiaSharp
Splash screen
Styles
Styling Xamarin.Forms Apps using XAML Styles
Introduction
Explicit Styles
Implicit Styles
Global Styles
Style Inheritance
Dynamic Styles
Device Styles
Style Classes
Styling Xamarin.Forms Apps using Cascading Style Sheets (CSS)
Theming
Visual
Material Visual
Create a Visual Renderer
Visual state manager
Layouts
Overview
Choose a Layout
Core layouts
AbsoluteLayout
FlexLayout
Grid
RelativeLayout
StackLayout
Additional layouts
ContentView
Frame
ScrollView
Concepts
Bindable Layouts
Custom Layouts
Device Orientation
LayoutOptions
Layout Compression
Margin and Padding
Tablet & Desktop
Platform Features
Overview
Android
Overview
AppCompat & Material Design
Button Padding and Shadows
Entry Input Method Editor Options
ImageButton Drop Shadows
ListView Fast Scrolling
NavigationPage Bar Height
Page Lifecycle Events
Soft Keyboard Input Mode
SwipeView Swipe Transition Mode
TabbedPage Page Swiping
TabbedPage Page Transition Animations
TabbedPage Toolbar Placement and Color
ViewCell Context Actions
VisualElement Elevation
VisualElement Legacy Color Mode
WebView Mixed Content
WebView Zoom
iOS
Overview
Accessibility Scaling for Named Font Sizes
Cell Background Color
Entry Cursor Color
Entry Font Size
Formatting
Modal Page Presentation Style
Large Page Titles
ListView Group Header Style
ListView Row Animations
ListView Separator Style
Main Thread Control Updates
NavigationPage Bar Separator
NavigationPage Bar Text Color Mode
NavigationPage Bar Translucency
Page Home Indicator Visibility
Page Status Bar Visibility
Picker Item Selection
Safe Area Layout Guide
ScrollView Content Touches
Simultaneous Pan Gesture Recognition
Slider Thumb Tap
SwipeView Swipe Transition Mode
VisualElement Blur
VisualElement Drop Shadows
VisualElement Legacy Color Mode
Windows
Overview
InputView Reading Order
ListView SelectionMode
MasterDetailPage Navigation Bar
Page Toolbar Placement
Platform Setup
RefreshView Pull Direction
SearchBar Spell Check
TabbedPage Icons
VisualElement Access Keys
VisualElement Legacy Color Mode
WebView JavaScript Alerts
Create Platform-Specifics
Device Class
Native Forms
Native Views
Native Views in XAML
Native Views in C#
Sign In with Apple
Setup for iOS
Setup for other platforms
Use Sign In with Apple
Other Platforms
GTK#
Mac
Tizen
WPF
Xamarin.Essentials
Get Started
Platform & Feature Support
Accelerometer
App Information
Barometer
Battery
Clipboard
Color Converters
Compass
Connectivity
Detect Shake
Device Display Information
Device Information
Email
File System Helpers
Flashlight
Geocoding
Geolocation
Gyroscope
Launcher
Magnetometer
Main Thread
Maps
Open Browser
Orientation Sensor
Phone Dialer
Platform Extensions(Size, Rect, Point)
Preferences
Secure Storage
Share
SMS
Text-to-Speech
Unit Converters
Version Tracking
Vibrate
Xamarin.Essentials release notes
Troubleshooting
Data & Azure Cloud Services
Overview
Local data storage
Overview
File Handling
Local Databases
Azure Services
Azure services overview
Azure Cosmos DB Document Database
Azure Notification Hubs
Azure Storage
Azure Search
Azure Functions
Azure SignalR Service
Azure Cognitive Services
Cognitive services overview
Introduction
Speech Recognition
Spell Check
Text Translation
Perceived Emotion Recognition
Web Services
Web services overview
Introduction
ASMX
WCF
REST
Authentication
Authentication overview
REST
OAuth
Azure Active Directory B2C
Azure Cosmos DB Authentication
Deployment & Testing
Overview
Improve Performance
Automate Testing with Visual Studio App Center
Publish iOS apps
Publish Android apps
Publish UWP apps
Publish Mac apps
Advanced Concepts and Internals
Overview
Controls Class Hierarchy
Dependency Resolution
Fast Renderers
Source Link
Troubleshooting
Frequently Asked Questions
Can I update the Xamarin.Forms default template to a newer NuGet package?
Why doesn't the Visual Studio XAML designer work for Xamarin.Forms XAML
files?
Android build error: The LinkAssemblies task failed unexpectedly
Why does my Xamarin.Forms.Maps Android project fail with COMPILETODALVIK :
UNEXPECTED TOP-LEVEL ERROR?
Release notes
Samples
Creating Mobile Apps with Xamarin.Forms Book
Enterprise Application Patterns eBook
SkiaSharp Graphics in Xamarin.Forms
What is Xamarin.Forms?
2 minutes to read • Edit Online

Xamarin.Forms is an open-source UI framework. Xamarin.Forms allows developers to build Android, iOS, and
Windows applications from a single shared codebase.
Xamarin.Forms allows developers to create user interfaces in XAML with code-behind in C#. These interfaces are
rendered as performant native controls on each platform.

Who Xamarin.Forms is for


Xamarin.Forms is for developers with the following goals:
Share UI layout and design across platforms.
Share code, test and business logic across platforms.
Write cross-platform apps in C# with Visual Studio.

How Xamarin.Forms works

Xamarin.Forms provides a consistent API for creating UI elements across platforms. This API can be implemented
in either XAML or C# and supports databinding for patterns such as Model-View -ViewModel (MVVM ).
At runtime, Xamarin.Forms utilizes platform renderers to convert the cross-platform UI elements into native
controls on Android, iOS and UWP. The allows developers to get native look, feel and performance while realizing
the benefits of code sharing across platforms.
Xamarin.Forms applications typically consist of a shared .NET Standard library and individual platform projects.
The shared library contains the XAML or C# views and any business logic such as services, models or other code.
The platform projects contain any platform-specific logic or packages the application requires.
Xamarin.Forms uses Xamarin to run .NET applications natively across platforms. For more information about
Xamarin, see What is Xamarin?.

Additional tools
Xamarin.Forms has a large ecosystem of NuGet packages that add diverse functionality to applications. This
section describes a few commonly-used NuGet packages.
Xamarin.Essentials
Xamarin.Essentials is a library that provides cross-platform APIs for native device features. Like Xamarin itself,
Xamarin.Essentials is an abstraction that simplifies the process of accessing native utilities. Some examples of
utilities provided by Xamarin.Essentials include:
Device info
File system
Accelerometer
Phone dialer
Text-to-speech
Screen lock
For more information, see Xamarin.Essentials.
Shell
Xamarin.Forms Shell reduces the complexity of mobile application development by providing the fundamental
features that most applications require. Some examples of features provided by Shell include:
Common navigation experience
URI-based navigation scheme
Integrated search handler
For more information, see Xamarin.Forms Shell
Platform-specifics
Xamarin.Forms provides a common API that renders native controls across platforms, but a specific platform may
have functionality that doesn't exist on other platforms. For example, the Android platform has native functionality
for Fast Scrolling in a ListView but iOS does not. Xamarin.Forms platform-specifics allow you to utilize
functionality that is only available on a specific platform without creating custom renderers or effects.
Xamarin.Forms includes pre-built solutions for a variety of platform-specific functionality. For more information,
see:
Xamarin.Forms platform-specifics
Android platform-specifics
iOS platform-specifics
Windows platform-specifics
Material Visual
Xamarin.Forms Material Visual is used to apply Material Design rules to Xamarin.Forms applications.
Xamarin.Forms Material Visual utilizes the Visual property to selectively apply custom renderers to the UI,
resulting in an application with a consistent look and feel across iOS and Android.
For more information, see Xamarin.Forms Material Visual

Related links
Get started with Xamarin.Forms
Xamarin.Essentials
Xamarin.Forms Shell
Xamarin.Forms Material Visual
Xamarin.Forms Requirements
2 minutes to read • Edit Online

Platform and development system requirements for Xamarin.Forms.


Refer to the Installation article for an overview of installation and setup practices that apply across platforms.

Target platforms
Xamarin.Forms applications can be written for the following operating systems:
iOS 9 or higher
Android 4.4 (API 19) or higher (more details)
Windows 10 Universal Windows Platform (more details)
However, Android 5.0 (API 21) is recommended as the minimum API. This ensures full compatibility with all the
Android support libraries, while still targeting the majority of Android devices.
It is assumed that developers have familiarity with .NET Standard.
Additional platform support
The status of these platforms is available on the Xamarin.Forms GitHub:
Samsung Tizen
macOS
GTK#
WPF
Android
You should have the latest Android SDK Tools and Android API platform installed. You can update to the latest
versions using the Android SDK Manager.
Additionally, the target/compile version for Android projects must be set to Use latest installed platform. However
the minimum version can be set to API 19 so you can continue to support devices that use Android 4.4 and newer.
These values are set in the Project Options:
Visual Studio
Visual Studio for Mac
Project Options > Application > Application Properties

Development system requirements


Xamarin.Forms apps can be developed on macOS and Windows. However, Windows and Visual Studio are
required to produce Windows versions of the app.
Mac System requirements
You can use Visual Studio for Mac to develop Xamarin.Forms apps on macOS High Sierra (10.13) or newer. To
develop iOS apps, we recommend using the latest version of Xcode, iOS, and macOS. For specific version
requirements, refer to the latest Xamarin.iOS release notes.

NOTE
Windows apps cannot be developed on macOS.

Windows system requirements


Xamarin.Forms apps for iOS and Android can be built on any Windows installation that supports Xamarin
development. For full support of the current platform features, use the latest version of Visual Studio.
A networked Mac is required for iOS development using the latest version of Xcode and the minimum version of
macOS specified by Apple.
Universal Windows Platform (UWP)
Developing Xamarin.Forms apps for UWP requires:
Windows 10 (latest version recommended, Fall Creators Update minimum)
Visual Studio 2019 recommended
Windows 10 SDK
You can add a Universal Windows Platform (UWP ) App to an existing Xamarin.Forms solution at any time.

Deprecated platforms
These platforms are not supported when using Xamarin.Forms 3.0 or newer:
Windows 8.1 / Windows Phone 8.1 WinRT
Windows Phone 8 Silverlight
Installing Xamarin
2 minutes to read • Edit Online

How to set up Visual Studio and Xamarin to start building mobile apps with .NET.

Installing Xamarin on Windows

Step-by-step instructions
Xamarin can be installed as part of a new Visual Studio 2019 installation, with the following steps:
1. Download Visual Studio 2019 Community, Visual Studio Professional, or Visual Studio Enterprise from the
Visual Studio page (download links are provided at the bottom).
2. Double-click the downloaded package to start installation.
3. Select the Mobile development with .NET workload from the installation screen:

4. When you are ready to begin Visual Studio 2019 installation, click the Install button in the lower right-
hand corner:

Use the progress bars to monitor the installation:


5. When Visual Studio 2019 installation has completed, click the Launch button to start Visual Studio:

Adding Xamarin to Visual Studio 2019


If Visual Studio 2019 is already installed, add Xamarin by re-running the Visual Studio 2019 installer to modify
workloads (see Modify Visual Studio for details). Next, follow the steps listed above to install Xamarin.
For more information about downloading and installing Visual Studio 2019, see Install Visual Studio 2019.

Installing Xamarin on Windows

Step-by-step instructions
Xamarin can be installed as part of a new Visual Studio 2017 installation, with the following steps:
1. Download Visual Studio 2017 Community, Visual Studio Professional, or Visual Studio Enterprise from the
Visual Studio page (download links are provided at the bottom).
2. Double-click the downloaded package to start installation.
3. Select the Mobile development with .NET workload from the installation screen:

4. While Mobile development with .NET is selected, have a look at the Installation details panel on the
right. Here, you can deselect mobile development options that you do not want to install.
5. When you are ready to begin Visual Studio 2017 installation, click the Install button in the lower right-
hand corner:

Depending on which edition of Visual Studio 2017 you are installing, the installation process can take a
long time to complete. You can use the progress bars to monitor the installation:

6. When Visual Studio 2017 installation has completed, click the Launch button to start Visual Studio:

Adding Xamarin to Visual Studio 2017


If Visual Studio 2017 is already installed, add Xamarin by re-running the Visual Studio 2017 installer to modify
workloads (see Modify Visual Studio for details). Next, follow the steps listed above to install Xamarin.
For more information about downloading and installing Visual Studio 2017, see Install Visual Studio 2017.
Installing Xamarin on macOS

Step-by-step instructions
In addition to this video, there is a step-by-step installation guide that covers Visual Studio for Mac and Xamarin.

Related Links
Uninstalling Xamarin
Xamarin Firewall Configuration Instructions
Installing Xamarin in Visual Studio 2019
2 minutes to read • Edit Online

Check the system requirements before you begin.

Installation
Xamarin can be installed as part of a new Visual Studio 2019 installation, with the following steps:
1. Download Visual Studio 2019 Community, Visual Studio Professional, or Visual Studio Enterprise from the
Visual Studio page (download links are provided at the bottom).
2. Double-click the downloaded package to start installation.
3. Select the Mobile development with .NET workload from the installation screen:

4. When you are ready to begin Visual Studio 2019 installation, click the Install button in the lower right-hand
corner:

Use the progress bars to monitor the installation:

5. When Visual Studio 2019 installation has completed, click the Launch button to start Visual Studio:
Adding Xamarin to Visual Studio 2019
If Visual Studio 2019 is already installed, add Xamarin by re-running the Visual Studio 2019 installer to modify
workloads (see Modify Visual Studio for details). Next, follow the steps listed above to install Xamarin.
For more information about downloading and installing Visual Studio 2019, see Install Visual Studio 2019.
In Visual Studio 2019, verify that Xamarin is installed by clicking the Help menu. If Xamarin is installed, you should
see a Xamarin menu item as shown in this screenshot:

You can also click Help > About Microsoft Visual Studio and scroll through the list of installed products to see if
Xamarin is installed:

For more information about locating version information, see Where can I find my version information and logs?
Next steps
Installing Xamarin in Visual Studio 2019 allows you to start writing code for your apps, but does require additional
setup for building and deploying your apps to simulator, emulator, and device. Visit the following guides to
complete your installation and start building cross platform apps.
iOS
For more detailed information, see the Installing Xamarin.iOS on Windows guide.
1. Install Visual Studio for Mac
2. Connect Visual Studio to your Mac build host
3. iOS Developer Setup - Required to run your application on device
4. Remoted iOS Simulator
5. Introduction to Xamarin.iOS for Visual Studio
Android
For more detailed information, see the Installing Xamarin.Android on Windows guide.
1. Xamarin.Android Configuration
2. Using the Xamarin Android SDK Manager
3. Android SDK Emulator
4. Set Up Device for Development
Installing Xamarin Preview on Windows
2 minutes to read • Edit Online

Visual Studio 2019 and Visual Studio 2017 do not support alpha, beta, and stable channels in the same way as
earlier versions. Instead, there are just two options:
Release – equivalent to the Stable channel in Visual Studio for Mac
Preview – equivalent to the Alpha and Beta channels in Visual Studio for Mac

TIP
To try out pre-release features, you should download the Visual Studio Preview installer, which will offer the option to install
Preview versions of Visual Studio side-by-Side with the stable (Release) version. More information on What's new in Visual
Studio 2019 can be found in the release notes.

The Preview version of Visual Studio may include corresponding Preview versions of Xamarin functionality,
including:
Xamarin.Forms
Xamarin.iOS
Xamarin.Android
Xamarin Profiler
Xamarin Inspector
Xamarin Remote iOS Simulator
The Preview Installer screenshot below shows both Preview and Release options (notice the grey version
numbers: version 15.0 is release and version 15.1 is a Preview ):
During the installation process, an Installation Nickname can be applied to the side-by-side installation (so they
can be distinguished in the Start menu), as shown below:

Uninstalling Visual Studio 2019 Preview


The Visual Studio Installer should also be used to un-install preview versions of Visual Studio 2019. Read the
uninstalling Xamarin guide for more information.
Xamarin firewall configuration instructions
2 minutes to read • Edit Online

A list of hosts that you need to allow in your firewall to allow Xamarin’s platform to work for your company.
In order for Xamarin products to install and work properly, certain endpoints must be accessible to download the
required tools and updates for your software. If you or your company have strict firewall settings, you may
experience issues with installation, licensing, components, and more. This document outlines some of the known
endpoints that need to be allowed in your firewall in order for Xamarin to work. This list does not include the
endpoints required for any third-party tools included in the download. If you are still experiencing trouble after
going through this list, refer to the Apple or Android installation troubleshooting guides.

Endpoints to allow
Xamarin installer
The following known addresses will need to be added in order for the software to install properly when using the
latest release of the Xamarin installer:
xamarin.com (installer manifests)
dl.xamarin.com (Package download location)
dl.google.com (to download the Android SDK)
download.oracle.com (JDK)
visualstudio.com (Setup packages download location)
go.microsoft.com (Setup URL resolution)
aka.ms (Setup URL resolution)
If you are using a Mac and are encountering Xamarin.Android install issues, please ensure that macOS is able to
download Java.
NuGet (including Xamarin.Forms)
The following addresses will need to be added to access NuGet (Xamarin.Forms is packaged as a NuGet):
www.nuget.org (to access NuGet)
globalcdn.nuget.org (NuGet downloads)
dl-ssl.google.com (Google components for Android and Xamarin.Forms)
Software updates
The following addresses will need to be added to ensure that software updates can download properly:
software.xamarin.com (updater service)
download.visualstudio.microsoft.com
dl.xamarin.com

Xamarin Mac Agent


To connect Visual Studio to a Mac build host using the Xamarin Mac Agent requires the SSH port to be open. By
default this is Port 22.
Uninstall Xamarin
7 minutes to read • Edit Online

This guide explains how to remove Xamarin from macOS or from Visual Studio on Windows.
If it is necessary to reinstall Xamarin using the Universal Installer, it is always recommended that the computer is
rebooted first.

Uninstalling Xamarin on macOS


This guide can be used to uninstall each product individually by navigating to the relevant section. The entire
Xamarin toolset, which includes the listed products, can be uninstalled by following this guide the whole way
through:
Mono
Xamarin.Android
Xamarin.iOS
Xamarin.Mac
Workbooks
Xamarin Profiler
Installer

TIP
We have provided an uninstall script for you to use when removing Xamarin from your macOS machine. For more
information on using the script, see the Using the Uninstall Script section in this guide.

Uninstalling Visual Studio for Mac


The first step in uninstalling Xamarin from a Mac is to locate Visual Studio.app in the /Applications directory
and drag it to the Trash Can. Alternatively, right-click and select Move to Trash as illustrated in the following
image:
Deleting this app bundle removes Visual Studio for Mac, although there may be other files relating to Xamarin still
on a file system.
To remove all traces of Visual Studio for Mac, run the following commands in Terminal:

sudo rm -rf "/Applications/Visual Studio.app"


rm -rf ~/Library/Caches/VisualStudio
rm -rf ~/Library/Preferences/VisualStudio
rm -rf ~/Library/Preferences/Visual\ Studio
rm -rf ~/Library/Logs/VisualStudio
rm -rf ~/Library/VisualStudio
rm -rf ~/Library/Preferences/Xamarin/
rm -rf ~/Library/Developer/Xamarin
rm -rf ~/Library/Application\ Support/VisualStudio
rm -rf ~/Library/Application\ Support/VisualStudio/7.0/LocalInstall/Addins/

NOTE
For information on uninstalling Visual Studio for Mac, refer to the Uninstall guide on docs.microsoft.com

Uninstall Mono SDK (MDK )


Mono is an open-source implementation of the .NET Framework and is used by all Xamarin Products—
Xamarin.iOS, Xamarin.Android, and Xamarin.Mac to allow development of these platforms in C#.

WARNING
There are other applications outside of Xamarin which also use Mono, such as Unity. Be sure that there are no other
dependencies on Mono before uninstalling it.

To remove the Mono Framework, run the following commands in Terminal:

sudo rm -rf /Library/Frameworks/Mono.framework


sudo pkgutil --forget com.xamarin.mono-MDK.pkg
sudo rm /etc/paths.d/mono-commands

Uninstall Xamarin.Android
There are a number of items that are required when using Xamarin.Android, such as the Android SDK and Java
SDK, which need to be removed when uninstalling Xamarin.Android. This section will guide you through
uninstalling all the necessary parts.
To remove Xamarin.Android, run the following commands in Terminal:

sudo rm -rf /Developer/MonoDroid


rm -rf ~/Library/MonoAndroid
sudo pkgutil --forget com.xamarin.android.pkg
sudo rm -rf /Library/Frameworks/Xamarin.Android.framework

Uninstall Android SDK and Java SDK


The Android SDK is required for development of Android applications. To completely remove all parts of the
Android SDK, locate the file at ~/Library/Developer/Xamarin/ and move it to Trash.
The Java SDK (JDK) does not need to be uninstalled, as it is already pre packaged as part of Mac OS X.
Uninstall Android AVD
WARNING
There are other applications outside of Visual Studio for Mac that also use Android AVD and these additional android
components, such as Android Studio. Removing this directory may cause projects to break in Android Studio.

To remove any Android AVDs and additional Android components, use the following command:

rm -rf ~/.android

To remove only the Android AVDs, use the following command:

rm -rf ~/.android/avd

Uninstall Xamarin.iOS
Xamarin.iOS allows iOS application development using C# or F#. To uninstall Xamarin.iOS from a machine, follow
the steps below:
To remove all Xamarin.iOS files, use the following commands in Terminal :

rm -rf ~/Library/MonoTouch
sudo rm -rf /Library/Frameworks/Xamarin.iOS.framework
sudo rm -rf /Developer/MonoTouch
sudo pkgutil --forget com.xamarin.monotouch.pkg
sudo pkgutil --forget com.xamarin.xamarin-ios-build-host.pkg
sudo pkgutil --forget com.xamarin.xamarin.ios.pkg

Uninstall Xamarin.Mac
Xamarin.Mac can be removed from your machine by using the following two commands to eradicate the product
and license from your Mac respectively:

sudo rm -rf /Library/Frameworks/Xamarin.Mac.framework


rm -rf ~/Library/Xamarin.Mac

Uninstall Workbooks
To remove Xamarin Workbooks version 1.2.2 and above, use the following commands in Terminal:

sudo /Library/Frameworks/Xamarin.Interactive.framework/Versions/Current/uninstall

For earlier versions, see the Workbooks uninstall guide.


Uninstall the Xamarin Profiler
To remove the Xamarin Profiler, use the following commands in Terminal:

sudo rm -rf "/Applications/Xamarin Profiler.app"

Uninstall the Xamarin Installer


To remove all traces of the Xamarin Universal Installer, use the following commands:
rm -rf ~/Library/Caches/XamarinInstaller/
rm -rf ~/Library/Caches/VisualStudioInstaller/
rm -rf ~/Library/Logs/XamarinInstaller/
rm -rf ~/Library/Logs/VisualStudioInstaller/
rm -rf ~/Library/Preferences/Xamarin/
rm -rf "~/Library/Preferences/Visual Studio/"

Using the Uninstall Script

TIP
Before executing any script you download, please read through the commands to understand what changes are being made
to your computer.

This uninstall script allows you to uninstall Visual Studio for Mac and its associated Xamarin components in one
go.
The script contains most of the commands that are found in the article. There are two main omissions from the
script and are not included due to possible external dependencies (other apps may be using Mono or the Android
tools):
Uninstalling Mono
Uninstalling Android AVD
To run the script:
1. Right-click on this link to uninstall-vsmac.sh and save/download the file to your Mac.
2. Open Terminal and change the working directory to where the script was downloaded:

cd /location/of/file

3. Make the script executable and the run it with sudo:

chmod +x ./uninstall-vsmac.sh
sudo ./uninstall-vsmac.sh

4. Delete the uninstall script.


Visual Studio for Mac and Xamarin tools should now be uninstalled from your computer.

Uninstalling Xamarin on Windows


Xamarin has been supported on these IDEs:
Visual Studio 2019 and Visual Studio 2017
Visual Studio 2015
Visual Studio 2013 [Unsupported]
Xamarin Studio [Unsupported]
Visual Studio 2019 and Visual Studio 2017
Xamarin is uninstalled from Visual Studio 2019 and Visual Studio 2017 using the installer app:
1. Use the Start menu to open the Visual Studio Installer.
2. Press the Modify button for the instance you wish to change.
3. In the Workloads tab, de-select the Mobile Development with .NET option (in the Mobile & Gaming
section).

4. Click the Modify button in the bottom right of the window.


5. The installer will remove the de-selected components (Visual Studio 2017 must be closed before the
installer can make any changes).

Individual Xamarin components (such as the Profiler or Workbooks) can be uninstalled by switching to the
Individual Components tab in step 3, and unchecking specific components:

To uninstall Visual Studio 2017 completely, choose Uninstall from the three-bar menu next to the Launch button.
IMPORTANT
If you have two (or more) instances of Visual Studio installed side-by-side (SxS) – such as a Release and a Preview version –
uninstalling one instance might remove some Xamarin functionality from the other Visual Studio instance(s), including:
Xamarin Profiler
Xamarin Workbooks/Inspector
Xamarin Remote iOS Simulator
Apple Bonjour SDK
Under certain conditions, uninstalling one of the SxS instances can result in the incorrect removal of these features. This may
degrade the performance of the Xamarin Platform on the Visual Studio instance(s) that remain on the system after the
uninstallation of the SxS instance.
This is resolved by running the Repair option in the Visual Studio installer, which will re-install the missing components.

Uninstalling older and unsupported products


Visual Studio 2015 and earlier
To uninstall Visual Studio 2015 completely, use the support answer on visualstudio.com.
Xamarin can be uninstalled from a Windows machine through Control Panel. Navigate to Programs and
Features or Programs > Uninstall a Program as illustrated below:

From the Control Panel, uninstall any of the following that are present:
Xamarin
Xamarin for Windows
Xamarin.Android
Xamarin.iOS
Xamarin for Visual Studio
In Explorer, delete any remaining files from the Xamarin Visual Studio extension folders (all versions, including
both Program Files and Program Files (x86)):

C:\Program Files*\Microsoft Visual Studio 1*.0\Common7\IDE\Extensions\Xamarin

Delete Visual Studio's MEF component cache directory, which should be located in the following location:

%LOCALAPPDATA%\Microsoft\VisualStudio\1*.0\ComponentModelCache

Check in the VirtualStore directory to see if Windows might have stored any overlay files for the
Extensions\Xamarin or ComponentModelCache directories there:

%LOCALAPPDATA%\VirtualStore

Open the registry editor (regedit) and look for the following key:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDlls

Find and delete any entries that match this pattern:

C:\Program Files*\Microsoft Visual Studio 1*.0\Common7\IDE\Extensions\Xamarin

Look for this key:

HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\1*.0\ExtensionManager\PendingDeletions

Delete any entries that look like they might be related to Xamarin. For example, anything containing the terms
mono or xamarin .

Open an administrator cmd.exe command prompt, and then run the devenv /setup and
devenv /updateconfiguration commands for each installed version of Visual Studio. For example, for Visual Studio
2015:

"%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" /setup


"%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" /updateconfiguration

Uninstall Xamarin Studio on Windows


Xamarin Studio is uninstalled from a Windows machine through Control Panel. Navigate to Programs and
Features or Programs > Uninstall a Program
To uninstall Xamarin Studio, find Xamarin Studio 5.x.x in the list of programs and click the Uninstall button.
Uninstall Xamarin Studio on Mac
The first step in uninstalling Xamarin Studio from a Mac is to locate Xamarin Studio.app in the /Applications
directory and drag it to the Trash Can. Alternatively, right-click and select Move to Trash as illustrated below:
Deleting this app bundle will remove Xamarin Studio, however, there are other files relating to Xamarin still on a
file system.
To remove all traces of Xamarin Studio, the following commands should be run in Terminal:

sudo rm -rf "/Applications/Xamarin Studio.app"


rm -rf ~/Library/Caches/XamarinStudio-*
rm -rf ~/Library/Preferences/XamarinStudio-*
rm -rf ~/Library/Logs/XamarinStudio-*
rm -rf ~/Library/XamarinStudio-*

Summary
This article provided instruction on uninstalling Xamarin completely from a Mac through the use of Terminal
commands. It also provided instruction on uninstalling Xamarin from a Windows machine through the Programs
and Features option (for Visual Studio 2015 and earlier), and using the Visual Studio Installer for Visual Studio
2017.

Related Links
Uninstall Script (sample)
Build your first Xamarin.Forms App
3 minutes to read • Edit Online

Watch this video and follow along to create your first mobile app with Xamarin.Forms.

Step-by-step instructions for Windows


Download the sample
Follow these steps along with the video above:
1. Choose File > New > Project... or press the Create new project... button:

2. Search for "Xamarin" or choose Mobile from the Project type menu. Select the Mobile App
(Xamarin.Forms) project type:
3. Choose a project name – the example uses "AwesomeApp":

4. Click on the Blank project type and ensure Android and iOS are selected:

5. Wait until the NuGet packages are restored (a "Restore completed" message will appear in the status bar).
6. New Visual Studio 2019 installations won't have an Android emulator configured. Click the dropdown
arrow on the Debug button and choose Create Android Emulator to launch the emulator creation screen:
7. In the emulator creation screen, use the default settings and click the Create button:

8. Creating an emulator will return you to the Device Manager window. Click the Start button to launch the
new emulator:

9. Visual Studio 2019 should now show the name of the new emulator on the Debug button:

10. Click the Debug button to build and deploy the application to the Android emulator:

Customize the application


The application can be customized to add interactive functionality. Perform the following steps to add user
interaction to the application:
1. Edit MainPage.xaml, adding this XAML before the end of the </StackLayout> :

<Button Text="Click Me" Clicked="Button_Clicked" />

2. Edit MainPage.xaml.cs, adding this code to the end of the class:

int count = 0;
void Button_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}

3. Debug the app on Android:

NOTE
The sample application includes the additional interactive functionality that is not covered in the video.

Build an iOS app in Visual Studio 2019


It's possible to build and debug the iOS app from Visual Studio with a networked Mac computer. Refer to the setup
instructions for more information.
This video covers the process of building and testing an iOS app using Visual Studio 2019 on Windows:
Step-by-step instructions for Windows
Download the sample
Follow these steps along with the video above:
1. Choose File > New > Project... or press the Create new project... button, then select Visual C# > Cross-
Platform > Mobile App (Xamarin.Forms):

2. Ensure Android and iOS are selected, with .NET Standard code sharing:

3. Wait until the NuGet packages are restored (a "Restore completed" message will appear in the status bar).
4. Launch Android emulator by pressing the debug button (or the Debug > Start Debugging menu item).
5. Edit MainPage.xaml, adding this XAML before the end of the </StackLayout> :

<Button Text="Click Me" Clicked="Button_Clicked" />

6. Edit MainPage.xaml.cs, adding this code to the end of the class:


int count = 0;
void Button_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}

7. Debug the app on Android:

TIP
It is possible to build and debug the iOS app from Visual Studio with a networked Mac computer. Refer to the setup
instructions for more information.

Step-by-step instructions for Mac


Download the sample
Follow these steps along with the video above:
1. Choose File > New Solution... or press the New Project... button, then select Multiplatform > App >
Blank Forms App:
2. Ensure Android and iOS are selected, with .NET Standard code sharing:

3. Restore NuGet packages, by right-clicking on the solution:

4. Launch Android emulator by pressing the debug button (or Run > Start Debugging).
5. Edit MainPage.xaml, adding this XAML before the end of the </StackLayout> :

<Button Text="Click Me" Clicked="Handle_Clicked" />

6. Edit MainPage.xaml.cs, adding this code to the end of the class:

int count = 0;
void Handle_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}

7. Debug the app on Android:


8. Right-click to set iOS to the Startup Project:

9. Debug the app on iOS:


You can download the completed code from the samples gallery or view it on GitHub.

Next Steps
Single Page Quickstart – Build a more functional app.
Xamarin.Forms Samples – Download and run code examples and sample apps.
Creating Mobile Apps ebook – In-depth chapters that teach Xamarin.Forms development, available as a PDF
and including hundreds of additional samples.
Xamarin.Forms quickstarts
2 minutes to read • Edit Online

Learn how to create mobile applications with Xamarin.Forms.

Create a single page Xamarin.Forms application


Learn how to create a single page cross-platform Xamarin.Forms application, which enables you to enter a note
and persist it to device storage.

Perform navigation in a multi-page Xamarin.Forms application


Learn how to turn the single page application, capable of storing a single note, into a multi-page application,
capable of storing multiple notes.

Store data in a local SQLite.NET database


Learn how to store data in a local SQLite.NET database.

Style a cross-platform Xamarin.Forms application


Learn how to style a cross-platform Xamarin.Forms application with XAML styles.

Quickstart deep dive


Read about the fundamentals of application development using Xamarin.Forms, with a focus on the application
developed throughout the quickstarts.
Create a Single Page Xamarin.Forms Application
12 minutes to read • Edit Online

Download the sample


In this quickstart, you will learn how to:
Create a cross-platform Xamarin.Forms application.
Define the user interface for a page using eXtensible Application Markup Language (XAML ).
Interact with XAML user interface elements from code.
The quickstart walks through how to create a cross-platform Xamarin.Forms application, which enables you to
enter a note and persist it to device storage. The final application is shown below:

Prerequisites
Visual Studio 2019 (latest release), with the Mobile development with .NET workload installed.
Knowledge of C#.
(optional) A paired Mac to build the application on iOS.

For more information about these prerequisites, see Installing Xamarin. For information about connecting Visual
Studio 2019 to a Mac build host, see Pair to Mac for Xamarin.iOS development.

Get started with Visual Studio 2019


1. Launch Visual Studio 2019, and in the start window click Create a new project to create a new project:
2. In the Create a new project window, select Mobile in the Project type drop down, select the Mobile
App (Xamarin.Forms) template, and click the Next button:

3. In the Configure your new project window, set the Project name to Notes, choose a suitable location
for the project, and click the Create button:
IMPORTANT
The C# and XAML snippets in this quickstart requires that the solution is named Notes. Using a different name will
result in build errors when you copy code from this quickstart into the solution.

4. In the New Cross Platform App dialog, click Blank App, and click the OK button:

For more information about the .NET Standard library that gets created, see Anatomy of a Xamarin.Forms
application in the Xamarin.Forms Quickstart Deep Dive.
5. In Solution Explorer, in the Notes project, double-click MainPage.xaml to open it:
6. In MainPage.xaml, remove all of the template code and replace it with 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"
x:Class="Notes.MainPage">
<StackLayout Margin="10,35,10,10">
<Label Text="Notes"
HorizontalOptions="Center"
FontAttributes="Bold" />
<Editor x:Name="editor"
Placeholder="Enter your note"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

This code declaratively defines the user interface for the page, which consists of a Label to display text, an
Editor for text input, and two Button instances that direct the application to save or delete a file. The two
Button instances are horizontally laid out in a Grid , with the Label , Editor , and Grid being vertically
laid out in a StackLayout . For more information about creating the user interface, see User interface in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to MainPage.xaml by pressing CTRL+S, and close the file.
7. In Solution Explorer, in the Notes project, expand MainPage.xaml and double-click MainPage.xaml.cs
to open it:
8. In MainPage.xaml.cs, remove all of the template code and replace it with the following code:

using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class MainPage : ContentPage
{
string _fileName =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "notes.txt");

public MainPage()
{
InitializeComponent();

if (File.Exists(_fileName))
{
editor.Text = File.ReadAllText(_fileName);
}
}

void OnSaveButtonClicked(object sender, EventArgs e)


{
File.WriteAllText(_fileName, editor.Text);
}

void OnDeleteButtonClicked(object sender, EventArgs e)


{
if (File.Exists(_fileName))
{
File.Delete(_fileName);
}
editor.Text = string.Empty;
}
}
}
This code defines a _fileName field, which references a file named notes.txt that will store note data in
the local application data folder for the application. When the page constructor is executed the file is read, if
it exists, and displayed in the Editor . When the Save Button is pressed the OnSaveButtonClicked event
handler is executed, which saves the content of the Editor to the file. When the Delete Button is pressed
the OnDeleteButtonClicked event handler is executed, which deletes the file, provided that it exists, and
removes any text from the Editor . For more information about user interaction, see Responding to user
interaction in the Xamarin.Forms Quickstart Deep Dive.
Save the changes to MainPage.xaml.cs by pressing CTRL+S, and close the file.
Building the quickstart
1. In Visual Studio, select the Build > Build Solution menu item (or press F6). The solution will build and a
success message will appear in the Visual Studio status bar:

If there are errors, repeat the previous steps and correct any mistakes until the solution builds successfully.
2. In the Visual Studio toolbar, press the Start button (the triangular button that resembles a Play button) to
launch the application in your chosen Android emulator:

Enter a note and press the Save button.


For more information about how the application is launched on each platform, see Launching the
application on each platform in the Xamarin.Forms Quickstart Deep Dive.
NOTE
The following steps should only be carried out if you have a paired Mac that meets the system requirements for
Xamarin.Forms development.

3. In the Visual Studio toolbar, right-click on the Notes.iOS project, and select Set as StartUp Project.

4. In the Visual Studio toolbar, press the Start button (the triangular button that resembles a Play button) to
launch the application in your chosen iOS remote simulator:

Enter a note and press the Save button.


For more information about how the application is launched on each platform, see Launching the
application on each platform in the Xamarin.Forms Quickstart Deep Dive.
Prerequisites
Visual Studio 2017, with the Mobile development with .NET workload installed.
Knowledge of C#.
(optional) A paired Mac to build the application on iOS.

For more information about these prerequisites, see Installing Xamarin. For information about connecting Visual
Studio 2019 to a Mac build host, see Pair to Mac for Xamarin.iOS development.

Get started with Visual Studio 2017


1. Launch Visual Studio 2017, and on the start page click Create new project... to create a new project:

2. In the New Project dialog, click Cross-Platform, select the Mobile App (Xamarin.Forms) template, set
the Name to Notes, choose a suitable location for the project and click the OK button:

IMPORTANT
The C# and XAML snippets in this quickstart requires that the solution is named Notes. Using a different name will
result in build errors when you copy code from this quickstart into the solution.

3. In the New Cross Platform App dialog, click Blank App, select .NET Standard as the Code Sharing
Strategy, and click the OK button:
For more information about the .NET Standard library that gets created, see Anatomy of a Xamarin.Forms
application in the Xamarin.Forms Quickstart Deep Dive.
4. In Solution Explorer, in the Notes project, double-click MainPage.xaml to open it:

5. In MainPage.xaml, remove all of the template code and replace it with 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"
x:Class="Notes.MainPage">
<StackLayout Margin="10,35,10,10">
<Label Text="Notes"
HorizontalOptions="Center"
FontAttributes="Bold" />
<Editor x:Name="editor"
Placeholder="Enter your note"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

This code declaratively defines the user interface for the page, which consists of a Label to display text, an
Editor for text input, and two Button instances that direct the application to save or delete a file. The two
Button instances are horizontally laid out in a Grid , with the Label , Editor , and Grid being vertically
laid out in a StackLayout . For more information about creating the user interface, see User interface in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to MainPage.xaml by pressing CTRL+S, and close the file.
6. In Solution Explorer, in the Notes project, expand MainPage.xaml and double-click MainPage.xaml.cs
to open it:
7. In MainPage.xaml.cs, remove all of the template code and replace it with the following code:
using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class MainPage : ContentPage
{
string _fileName =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "notes.txt");

public MainPage()
{
InitializeComponent();

if (File.Exists(_fileName))
{
editor.Text = File.ReadAllText(_fileName);
}
}

void OnSaveButtonClicked(object sender, EventArgs e)


{
File.WriteAllText(_fileName, editor.Text);
}

void OnDeleteButtonClicked(object sender, EventArgs e)


{
if (File.Exists(_fileName))
{
File.Delete(_fileName);
}
editor.Text = string.Empty;
}
}
}

This code defines a _fileName field, which references a file named notes.txt that will store note data in
the local application data folder for the application. When the page constructor is executed the file is read, if
it exists, and displayed in the Editor . When the Save Button is pressed the OnSaveButtonClicked event
handler is executed, which saves the content of the Editor to the file. When the Delete Button is pressed
the OnDeleteButtonClicked event handler is executed, which deletes the file, provided that it exists, and
removes any text from the Editor . For more information about user interaction, see Responding to user
interaction in the Xamarin.Forms Quickstart Deep Dive.
Save the changes to MainPage.xaml.cs by pressing CTRL+S, and close the file.
Building the quickstart
1. In Visual Studio, select the Build > Build Solution menu item (or press F6). The solution will build and a
success message will appear in the Visual Studio status bar:
If there are errors, repeat the previous steps and correct any mistakes until the solution builds successfully.
2. In the Visual Studio toolbar, press the Start button (the triangular button that resembles a Play button) to
launch the application in your chosen Android emulator:

Enter a note and press the Save button.


For more information about how the application is launched on each platform, see Launching the
application on each platform in the Xamarin.Forms Quickstart Deep Dive.

NOTE
The following steps should only be carried out if you have a paired Mac that meets the system requirements for
Xamarin.Forms development.

3. In the Visual Studio toolbar, right-click on the Notes.iOS project, and select Set as StartUp Project.
4. In the Visual Studio toolbar, press the Start button (the triangular button that resembles a Play button) to
launch the application in your chosen iOS remote simulator:

Enter a note and press the Save button.


For more information about how the application is launched on each platform, see Launching the
application on each platform in the Xamarin.Forms Quickstart Deep Dive.
Prerequisites
Visual Studio for Mac (latest release), with iOS and Android platform support installed.
Xcode (latest release).
Knowledge of C#.
For more information about these prerequisites, see Installing Xamarin.

Get started with Visual Studio for Mac


1. Launch Visual Studio for Mac, and in the start window click New to create a new project:
2. In the Choose a template for your new project dialog, click Multiplatform > App, select the Blank
Forms App template, and click the Next button:

3. In the Configure your Blank Forms app dialog, name the new app Notes, ensure that the Use .NET
Standard radio button is selected, and click the Next button:
4. In the Configure your new Blank Forms app dialog, leave the Solution and Project names set to Notes,
choose a suitable location for the project, and click the Create button to create the project:

IMPORTANT
The C# and XAML snippets in this quickstart requires that the solution and project are both named Notes. Using a
different name will result in build errors when you copy code from this quickstart into the project.
For more information about the .NET Standard library that gets created, see Anatomy of a Xamarin.Forms
application in the Xamarin.Forms Quickstart Deep Dive.
5. In the Solution Pad, in the Notes project, double-click MainPage.xaml to open it:

6. In MainPage.xaml, remove all of the template code and replace it with 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"
x:Class="Notes.MainPage">
<StackLayout Margin="10,35,10,10">
<Label Text="Notes"
HorizontalOptions="Center"
FontAttributes="Bold" />
<Editor x:Name="editor"
Placeholder="Enter your note"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

This code declaratively defines the user interface for the page, which consists of a Label to display text, an
Editor for text input, and two Button instances that direct the application to save or delete a file. The two
Button instances are horizontally laid out in a Grid , with the Label , Editor , and Grid being vertically
laid out in a StackLayout . For more information about creating the user interface, see User interface in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to MainPage.xaml by choosing File > Save (or by pressing ⌘ + S ), and close the file.
7. In the Solution Pad, in the Notes project, expand MainPage.xaml and double-click MainPage.xaml.cs
to open it:
8. In MainPage.xaml.cs, remove all of the template code and replace it with the following code:

using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class MainPage : ContentPage
{
string _fileName =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "notes.txt");

public MainPage()
{
InitializeComponent();

if (File.Exists(_fileName))
{
editor.Text = File.ReadAllText(_fileName);
}
}

void OnSaveButtonClicked(object sender, EventArgs e)


{
File.WriteAllText(_fileName, editor.Text);
}

void OnDeleteButtonClicked(object sender, EventArgs e)


{
if (File.Exists(_fileName))
{
File.Delete(_fileName);
}
editor.Text = string.Empty;
}
}
}

This code defines a _fileName field, which references a file named notes.txt that will store note data in
the local application data folder for the application. When the page constructor is executed the file is read, if
it exists, and displayed in the Editor . When the Save Button is pressed the OnSaveButtonClicked event
handler is executed, which saves the content of the Editor to the file. When the Delete Button is pressed
the OnDeleteButtonClicked event handler is executed, which deletes the file, provided that it exists, and
removes any text from the Editor . For more information about user interaction, see Responding to user
interaction in the Xamarin.Forms Quickstart Deep Dive.
Save the changes to MainPage.xaml.cs by choosing File > Save (or by pressing ⌘ + S ), and close the
file.
Building the quickstart
1. In Visual Studio for Mac, select the Build > Build All menu item (or press ⌘ + B ). The projects will build
and a success message will appear in the Visual Studio for Mac toolbar.

If there are errors, repeat the previous steps and correct any mistakes until the projects build successfully.
2. In the Solution Pad, select the Notes.iOS project, right-click, and select Set As Startup Project:

3. In the Visual Studio for Mac toolbar, press the Start button (the triangular button that resembles a Play
button) to launch the application inside your chosen iOS Simulator:

Enter a note and press the Save button.


For more information about how the application is launched on each platform, see Launching the
application on each platform in the Xamarin.Forms Quickstart Deep Dive.
4. In the Solution Pad, select the Notes.Droid project, right-click, and select Set As Startup Project:
5. In the Visual Studio for Mac toolbar, press the Start button (the triangular button that resembles a Play
button) to launch the application inside your chosen Android emulator:

Enter a note and press the Save button.


For more information about how the application is launched on each platform, see Launching the
application on each platform in the Xamarin.Forms Quickstart Deep Dive.

Next steps
In this quickstart, you learned how to:
Create a cross-platform Xamarin.Forms application.
Define the user interface for a page using eXtensible Application Markup Language (XAML ).
Interact with XAML user interface elements from code.
To turn this single page application into a multi-page application, continue to the next quickstart.
Next

Related links
Notes (sample)
Xamarin.Forms Quickstart Deep Dive
Perform Navigation in a Multi-Page Xamarin.Forms
Application
14 minutes to read • Edit Online

Download the sample


In this quickstart, you will learn how to:
Add additional pages to a Xamarin.Forms solution.
Perform navigation between pages.
Use data binding to synchronize data between user interface elements and their data source.
The quickstart walks through how to turn a single page cross-platform Xamarin.Forms application, capable of
storing a single note, into a multi-page application, capable of storing multiple notes. The final application is
shown below:

Prerequisites
You should successfully complete the previous quickstart before attempting this quickstart. Alternatively,
download the previous quickstart sample and use it as the starting point for this quickstart.

Update the app with Visual Studio


1. Launch Visual Studio. In the start window, click the Notes solution in the recent projects/solutions list, or
click Open a project or solution, and in the Open Project/Solution dialog select the solution file for the
Notes project:
2. In Solution Explorer, right-click on the Notes project and select Add > New Folder:

3. In Solution Explorer, name the new folder Models:


4. In Solution Explorer, select the Models folder, right-click, and select Add > New Item...:

5. In the Add New Item dialog, select Visual C# Items > Class, name the new file Note, and click the Add
button:

This will add a class named Note to the Models folder of the Notes project.
6. In Note.cs, remove all of the template code and replace it with the following code:
using System;

namespace Notes.Models
{
public class Note
{
public string Filename { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}

This class defines a Note model that will store data about each note in the application.
Save the changes to Note.cs by pressing CTRL+S, and close the file.
7. In Solution Explorer, right-click on the Notes project and select Add > New Item... In the Add New
Item dialog, select Visual C# Items > Xamarin.Forms > Content Page, name the new file
NoteEntryPage, and click the Add button:

This will add a new page named NoteEntryPage to the root folder of the project. This page will be the
second page in the application.
8. In NoteEntryPage.xaml, remove all of the template code and replace it with 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"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<StackLayout Margin="20">
<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

This code declaratively defines the user interface for the page, which consists of an Editor for text input,
and two Button instances that direct the application to save or delete a file. The two Button instances are
horizontally laid out in a Grid , with the Editor and Grid being vertically laid out in a StackLayout . In
addition, the Editor uses data binding to bind to the Text property of the Note model. For more
information about data binding, see Data binding in the Xamarin.Forms Quickstart Deep Dive.
Save the changes to NoteEntryPage.xaml by pressing CTRL+S, and close the file.
9. In NoteEntryPage.xaml.cs, remove all of the template code and replace it with the following code:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
public partial class NoteEntryPage : ContentPage
{
public NoteEntryPage()
{
InitializeComponent();
}

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;

if (string.IsNullOrWhiteSpace(note.Filename))
{
// Save
var filename = Path.Combine(App.FolderPath, $"{Path.GetRandomFileName()}.notes.txt");
File.WriteAllText(filename, note.Text);
}
else
{
// Update
File.WriteAllText(note.Filename, note.Text);
}

await Navigation.PopAsync();
}

async void OnDeleteButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;

if (File.Exists(note.Filename))
{
File.Delete(note.Filename);
}

await Navigation.PopAsync();
}
}
}

This code stores a Note instance, which represents a single note, in the BindingContext of the page. When
the Save Button is pressed the OnSaveButtonClicked event handler is executed, which either saves the
content of the Editor to a new file with a randomly generated filename, or to an existing file if a note is
being updated. In both cases, the file is stored in the local application data folder for the application. Then
the method navigates back to the previous page. When the Delete Button is pressed the
OnDeleteButtonClicked event handler is executed, which deletes the file, provided that it exists, and
navigates back to the previous page. For more information about navigation, see Navigation in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to NoteEntryPage.xaml.cs by pressing CTRL+S, and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.
10. In Solution Explorer, right-click on the Notes project and select Add > New Item... In the Add New
Item dialog, select Visual C# Items > Xamarin.Forms > Content Page, name the new file NotesPage,
and click the Add button.
This will add a page named NotesPage to the root folder of the project. This page will be the root page of
the application.
11. In NotesPage.xaml, remove all of the template code and replace it with 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"
x:Class="Notes.NotesPage"
Title="Notes">
<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNoteAddedClicked" />
</ContentPage.ToolbarItems>
<ListView x:Name="listView"
Margin="20"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

This code declaratively defines the user interface for the page, which consists of a ListView and a
ToolbarItem . The ListView uses data binding to display any notes that are retrieved by the application, and
selecting a note will navigate to the NoteEntryPage where the note can be modified. Alternatively, a new
note can be created by pressing the ToolbarItem . For more information about data binding, see Data
binding in the Xamarin.Forms Quickstart Deep Dive.
Save the changes to NotesPage.xaml by pressing CTRL+S, and close the file.
12. In NotesPage.xaml.cs, remove all of the template code and replace it with the following code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
public partial class NotesPage : ContentPage
{
public NotesPage()
{
InitializeComponent();
}

protected override void OnAppearing()


{
base.OnAppearing();

var notes = new List<Note>();

var files = Directory.EnumerateFiles(App.FolderPath, "*.notes.txt");


foreach (var filename in files)
{
notes.Add(new Note
{
Filename = filename,
Text = File.ReadAllText(filename),
Date = File.GetCreationTime(filename)
});
}

listView.ItemsSource = notes
.OrderBy(d => d.Date)
.ToList();
}

async void OnNoteAddedClicked(object sender, EventArgs e)


{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = new Note()
});
}

async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)


{
if (e.SelectedItem != null)
{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = e.SelectedItem as Note
});
}
}
}
}

This code defines the functionality for the NotesPage . When the page appears, the OnAppearing method is
executed, which populates the ListView with any notes that have been retrieved from the local application
data folder. When the ToolbarItem is pressed the OnNoteAddedClicked event handler is executed. This
method navigates to the NoteEntryPage , setting the BindingContext of the NoteEntryPage to a new Note
instance. When an item in the ListView is selected the OnListViewItemSelected event handler is executed.
This method navigates to the NoteEntryPage , setting the BindingContext of the NoteEntryPage to the
selected Note instance. For more information about navigation, see Navigation in the Xamarin.Forms
Quickstart Deep Dive.
Save the changes to NotesPage.xaml.cs by pressing CTRL+S, and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

13. In Solution Explorer, double-click App.xaml.cs to open it. Then replace the existing code with the
following code:

using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class App : Application
{
public static string FolderPath { get; private set; }

public App()
{
InitializeComponent();
FolderPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
MainPage = new NavigationPage(new NotesPage());
}
// ...
}
}

This code adds a namespace declaration for the System.IO namespace, and adds a declaration for a static
FolderPath property of type string . The FolderPath property is used to store the path on the device
where note data will be stored. In addition, the code initializes the FolderPath property in the App
constructor, and initializes the MainPage property to be a NavigationPage that hosts an instance of
NotesPage . For more information about navigation, see Navigation in the Xamarin.Forms Quickstart Deep
Dive.
Save the changes to App.xaml.cs by pressing CTRL+S, and close the file.
14. In Solution Explorer, in the Notes project, right-click MainPage.xaml, and select Delete. In the dialog
that appears press the OK button to remove the file from your hard disk.
This removes a page that's no longer used.
15. Build and run the project on each platform. For more information, see Building the quickstart.
On the NotesPage press the + button to navigate to the NoteEntryPage and enter a note. After saving
the note the application will navigate back to the NotesPage.
Enter a number of notes, of varying length, to observe the application behavior.

Update the app with Visual Studio for Mac


1. Launch Visual Studio for Mac. In the start window click Open, and in the dialog select the solution file for
the Notes project:
2. In the Solution Pad, select the Notes project, right-click, and select Add > New Folder:

3. In the Solution Pad, name the new folder Models:

4. In the Solution Pad, select the Models folder, right-click, and select Add > New File...:
5. In the New File dialog, select General > Empty Class, name the new file Note, and click the New button:

This will add a class named Note to the Models folder of the Notes project.
6. In Note.cs, remove all of the template code and replace it with the following code:

using System;

namespace Notes.Models
{
public class Note
{
public string Filename { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}

This class defines a Note model that will store data about each note in the application.
Save the changes to Note.cs by choosing File > Save (or by pressing ⌘ + S ), and close the file.
7. In the Solution Pad, select the Notes project, right-click, and select Add > New File.... In the New File
dialog, select Forms > Forms ContentPage XAML, name the new file NoteEntryPage, and click the
New button:
This will add a new page named NoteEntryPage to the root folder of the project. This page will be the
second page in the application.
8. In NoteEntryPage.xaml, remove all of the template code and replace it with 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"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<StackLayout Margin="20">
<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

This code declaratively defines the user interface for the page, which consists of an Editor for text input,
and two Button instances that direct the application to save or delete a file. The two Button instances are
horizontally laid out in a Grid , with the Editor and Grid being vertically laid out in a StackLayout . In
addition, the Editor uses data binding to bind to the Text property of the Note model. For more
information about data binding, see Data binding in the Xamarin.Forms Quickstart Deep Dive.
Save the changes to NoteEntryPage.xaml by choosing File > Save (or by pressing ⌘ + S ), and close the
file.
9. In NoteEntryPage.xaml.cs, remove all of the template code and replace it with the following code:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
public partial class NoteEntryPage : ContentPage
{
public NoteEntryPage()
{
InitializeComponent();
}

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;

if (string.IsNullOrWhiteSpace(note.Filename))
{
// Save
var filename = Path.Combine(App.FolderPath, $"{Path.GetRandomFileName()}.notes.txt");
File.WriteAllText(filename, note.Text);
}
else
{
// Update
File.WriteAllText(note.Filename, note.Text);
}

await Navigation.PopAsync();
}

async void OnDeleteButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;

if (File.Exists(note.Filename))
{
File.Delete(note.Filename);
}

await Navigation.PopAsync();
}
}
}

This code stores a Note instance, which represents a single note, in the BindingContext of the page. When
the Save Button is pressed the OnSaveButtonClicked event handler is executed, which either saves the
content of the Editor to a new file with a randomly generated filename, or to an existing file if a note is
being updated. In both cases, the file is stored in the local application data folder for the application. Then
the method navigates back to the previous page. When the Delete Button is pressed the
OnDeleteButtonClicked event handler is executed, which deletes the file, provided that it exists, and
navigates back to the previous page. For more information about navigation, see Navigation in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to NoteEntryPage.xaml.cs by choosing File > Save (or by pressing ⌘ + S ), and close
the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.
10. In the Solution Pad, select the Notes project, right-click, and select Add > New File.... In the New File
dialog, select Forms > Forms ContentPage XAML, name the new file NotesPage, and click the New
button.
This will add a page named NotesPage to the root folder of the project. This page will be the root page of
the application.
11. In NotesPage.xaml, remove all of the template code and replace it with 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"
x:Class="Notes.NotesPage"
Title="Notes">
<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNoteAddedClicked" />
</ContentPage.ToolbarItems>
<ListView x:Name="listView"
Margin="20"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

This code declaratively defines the user interface for the page, which consists of a ListView and a
ToolbarItem . The ListView uses data binding to display any notes that are retrieved by the application, and
selecting a note will navigate to the NoteEntryPage where the note can be modified. Alternatively, a new
note can be created by pressing the ToolbarItem . For more information about data binding, see Data
binding in the Xamarin.Forms Quickstart Deep Dive.
Save the changes to NotesPage.xaml by choosing File > Save (or by pressing ⌘ + S ), and close the file.
12. In NotesPage.xaml.cs, remove all of the template code and replace it with the following code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
public partial class NotesPage : ContentPage
{
public NotesPage()
{
InitializeComponent();
}

protected override void OnAppearing()


{
base.OnAppearing();

var notes = new List<Note>();

var files = Directory.EnumerateFiles(App.FolderPath, "*.notes.txt");


foreach (var filename in files)
{
notes.Add(new Note
{
Filename = filename,
Text = File.ReadAllText(filename),
Date = File.GetCreationTime(filename)
});
}

listView.ItemsSource = notes
.OrderBy(d => d.Date)
.ToList();
}

async void OnNoteAddedClicked(object sender, EventArgs e)


{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = new Note()
});
}

async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)


{
if (e.SelectedItem != null)
{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = e.SelectedItem as Note
});
}
}
}
}

This code defines the functionality for the NotesPage . When the page appears, the OnAppearing method is
executed, which populates the ListView with any notes that have been retrieved from the local application
data folder. When the ToolbarItem is pressed the OnNoteAddedClicked event handler is executed. This
method navigates to the NoteEntryPage , setting the BindingContext of the NoteEntryPage to a new Note
instance. When an item in the ListView is selected the OnListViewItemSelected event handler is executed.
This method navigates to the NoteEntryPage , setting the BindingContext of the NoteEntryPage to the
selected Note instance. For more information about navigation, see Navigation in the Xamarin.Forms
Quickstart Deep Dive.
Save the changes to NotesPage.xaml.cs by choosing File > Save (or by pressing ⌘ + S ), and close the
file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

13. In the Solution Pad, double-click App.xaml.cs to open it. Then replace the existing code with the
following code:

using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class App : Application
{
public static string FolderPath { get; private set; }

public App()
{
InitializeComponent();
FolderPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
MainPage = new NavigationPage(new NotesPage());
}
// ...
}
}

This code adds a namespace declaration for the System.IO namespace, and adds a declaration for a static
FolderPath property of type string . The FolderPath property is used to store the path on the device
where note data will be stored. In addition, the code initializes the FolderPath property in the App
constructor, and initializes the MainPage property to be a NavigationPage that hosts an instance of
NotesPage . For more information about navigation, see Navigation in the Xamarin.Forms Quickstart Deep
Dive.
Save the changes to App.xaml.cs by choosing File > Save (or by pressing ⌘ + S ), and close the file.
14. In the Solution Pad, in the Notes project, right-click MainPage.xaml, and select Remove. In the dialog
that appears press the Delete button to remove the file from your hard disk.
This removes a page that's no longer used.
15. Build and run the project on each platform. For more information, see Building the quickstart.
On the NotesPage press the + button to navigate to the NoteEntryPage and enter a note. After saving
the note the application will navigate back to the NotesPage.
Enter a number of notes, of varying length, to observe the application behavior.

Next steps
In this quickstart, you learned how to:
Add additional pages to a Xamarin.Forms solution.
Perform navigation between pages.
Use data binding to synchronize data between user interface elements and their data source.
To modify the application so that it stores its data in a local SQLite.NET database, continue to the next quickstart.
Next

Related links
Notes (sample)
Xamarin.Forms Quickstart Deep Dive
Store Data in a Local SQLite.NET Database
10 minutes to read • Edit Online

Download the sample


In this quickstart, you will learn how to:
Use the NuGet Package Manager to add a NuGet package to a project.
Store data locally in a SQLite.NET database.
The quickstart walks through how to store data in a local SQLite.NET database. The final application is shown
below:

Prerequisites
You should successfully complete the previous quickstart before attempting this quickstart. Alternatively,
download the previous quickstart sample and use it as the starting point for this quickstart.

Update the app with Visual Studio


1. Launch Visual Studio and open the Notes solution.
2. In Solution Explorer, select the Notes project, right-click and select Manage NuGet Packages...:
3. In the NuGet Package Manager, select the Browse tab, search for the sqlite-net-pcl NuGet package,
select it, and click the Install button to add it to the project:

NOTE
There are a number of NuGet packages with similar names. The correct package has these attributes:
Author(s): Frank A. Krueger
Id: sqlite-net-pcl
NuGet link: sqlite-net-pcl
Despite the package name, this NuGet package can be used in .NET Standard projects.

This package will be used to incorporate database operations into the application.
4. In Solution Explorer, in the Notes project, open Note.cs in the Models folder and replace the existing
code with the following code:
using System;
using SQLite;

namespace Notes.Models
{
public class Note
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}

This class defines a Note model that will store data about each note in the application. The ID property is
marked with PrimaryKey and AutoIncrement attributes to ensure that each Note instance in the
SQLite.NET database will have a unique id provided by SQLite.NET.
Save the changes to Note.cs by pressing CTRL+S, and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

5. In Solution Explorer, add a new folder named Data to the Notes project.
6. In Solution Explorer, in the Notes project, add a new class named NoteDatabase to the Data folder.
7. In NoteDatabase.cs, replace the existing code with the following code:
using System.Collections.Generic;
using System.Threading.Tasks;
using SQLite;
using Notes.Models;

namespace Notes.Data
{
public class NoteDatabase
{
readonly SQLiteAsyncConnection _database;

public NoteDatabase(string dbPath)


{
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<Note>().Wait();
}

public Task<List<Note>> GetNotesAsync()


{
return _database.Table<Note>().ToListAsync();
}

public Task<Note> GetNoteAsync(int id)


{
return _database.Table<Note>()
.Where(i => i.ID == id)
.FirstOrDefaultAsync();
}

public Task<int> SaveNoteAsync(Note note)


{
if (note.ID != 0)
{
return _database.UpdateAsync(note);
}
else
{
return _database.InsertAsync(note);
}
}

public Task<int> DeleteNoteAsync(Note note)


{
return _database.DeleteAsync(note);
}
}
}

This class contains code to create the database, read data from it, write data to it, and delete data from it.
The code uses asynchronous SQLite.NET APIs that move database operations to background threads. In
addition, the NoteDatabase constructor takes the path of the database file as an argument. This path will be
provided by the App class in the next step.
Save the changes to NoteDatabase.cs by pressing CTRL+S, and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

8. In Solution Explorer, in the Notes project, double-click App.xaml.cs to open it. Then replace the existing
code with the following code:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Data;

namespace Notes
{
public partial class App : Application
{
static NoteDatabase database;

public static NoteDatabase Database


{
get
{
if (database == null)
{
database = new
NoteDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Notes.db3"));
}
return database;
}
}

public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}

protected override void OnStart()


{
// Handle when your app starts
}

protected override void OnSleep()


{
// Handle when your app sleeps
}

protected override void OnResume()


{
// Handle when your app resumes
}
}
}

This code defines a Database property that creates a new NoteDatabase instance as a singleton, passing in
the filename of the database as the argument to the NoteDatabase constructor. The advantage of exposing
the database as a singleton is that a single database connection is created that's kept open while the
application runs, therefore avoiding the expense of opening and closing the database file each time a
database operation is performed.
Save the changes to App.xaml.cs by pressing CTRL+S, and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

9. In Solution Explorer, in the Notes project, double-click NotesPage.xaml.cs to open it. Then replace the
OnAppearing method with the following code:
protected override async void OnAppearing()
{
base.OnAppearing();

listView.ItemsSource = await App.Database.GetNotesAsync();


}

This code populates the ListView with any notes stored in the database.
Save the changes to NotesPage.xaml.cs by pressing CTRL+S, and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

10. In Solution Explorer, double-click NoteEntryPage.xaml.cs to open it. Then replace the
OnSaveButtonClicked and OnDeleteButtonClicked methods with the following code:

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
note.Date = DateTime.UtcNow;
await App.Database.SaveNoteAsync(note);
await Navigation.PopAsync();
}

async void OnDeleteButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
await App.Database.DeleteNoteAsync(note);
await Navigation.PopAsync();
}

The NoteEntryPage stores a Note instance, which represents a single note, in the BindingContext of the
page. When the OnSaveButtonClicked event handler is executed, the Note instance is saved to the database
and the application navigates back to the previous page. When the OnDeleteButtonClicked event handler is
executed, the Note instance is deleted from the database and the application navigates back to the previous
page.
Save the changes to NoteEntryPage.xaml.cs by pressing CTRL+S, and close the file.
11. Build and run the project on each platform. For more information, see Building the quickstart.
On the NotesPage press the + button to navigate to the NoteEntryPage and enter a note. After saving
the note the application will navigate back to the NotesPage.
Enter a number of notes, of varying length, to observe the application behavior.

Update the app with Visual Studio for Mac


1. Launch Visual Studio for Mac and open the Notes project.
2. In the Solution Pad, select the Notes project, right-click and select Add > Add NuGet Packages...:
3. In the Add Packages window, search for the sqlite-net-pcl NuGet package, select it, and click the Add
Package button to add it to the project:

NOTE
There are a number of NuGet packages with similar names. The correct package has these attributes:
Author: Frank A. Krueger
Id: sqlite-net-pcl
NuGet link: sqlite-net-pcl
Despite the package name, this NuGet package can be used in .NET Standard projects.

This package will be used to incorporate database operations into the application.
4. In the Solution Pad, in the Notes project, open Note.cs in the Models folder and replace the existing
code with the following code:
using System;
using SQLite;

namespace Notes.Models
{
public class Note
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}

This class defines a Note model that will store data about each note in the application. The ID property is
marked with PrimaryKey and AutoIncrement attributes to ensure that each Note instance in the
SQLite.NET database will have a unique id provided by SQLite.NET.
Save the changes to Note.cs by choosing File > Save (or by pressing ⌘ + S ), and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

5. In the Solution Pad, add a new folder named Data to the Notes project.
6. In the Solution Pad, in the Notes project, add a new class named NoteDatabase to the Data folder.
7. In NoteDatabase.cs, replace the existing code with the following code:
using System.Collections.Generic;
using System.Threading.Tasks;
using SQLite;
using Notes.Models;

namespace Notes.Data
{
public class NoteDatabase
{
readonly SQLiteAsyncConnection _database;

public NoteDatabase(string dbPath)


{
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<Note>().Wait();
}

public Task<List<Note>> GetNotesAsync()


{
return _database.Table<Note>().ToListAsync();
}

public Task<Note> GetNoteAsync(int id)


{
return _database.Table<Note>()
.Where(i => i.ID == id)
.FirstOrDefaultAsync();
}

public Task<int> SaveNoteAsync(Note note)


{
if (note.ID != 0)
{
return _database.UpdateAsync(note);
}
else
{
return _database.InsertAsync(note);
}
}

public Task<int> DeleteNoteAsync(Note note)


{
return _database.DeleteAsync(note);
}
}
}

This class contains code to create the database, read data from it, write data to it, and delete data from it.
The code uses asynchronous SQLite.NET APIs that move database operations to background threads. In
addition, the NoteDatabase constructor takes the path of the database file as an argument. This path will be
provided by the App class in the next step.
Save the changes to NoteDatabase.cs by choosing File > Save (or by pressing ⌘ + S ), and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

8. In the Solution Pad, in the Notes project, double-click App.xaml.cs to open it. Then replace the existing
code with the following code:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Data;

namespace Notes
{
public partial class App : Application
{
static NoteDatabase database;

public static NoteDatabase Database


{
get
{
if (database == null)
{
database = new
NoteDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Notes.db3"));
}
return database;
}
}

public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}

protected override void OnStart()


{
// Handle when your app starts
}

protected override void OnSleep()


{
// Handle when your app sleeps
}

protected override void OnResume()


{
// Handle when your app resumes
}
}
}

This code defines a Database property that creates a new NoteDatabase instance as a singleton, passing in
the filename of the database as the argument to the NoteDatabase constructor. The advantage of exposing
the database as a singleton is that a single database connection is created that's kept open while the
application runs, therefore avoiding the expense of opening and closing the database file each time a
database operation is performed.
Save the changes to App.xaml.cs by choosing File > Save (or by pressing ⌘ + S ), and close the file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

9. In the Solution Pad, in the Notes project, double-click NotesPage.xaml.cs to open it. Then replace the
OnAppearing method with the following code:
protected override async void OnAppearing()
{
base.OnAppearing();

listView.ItemsSource = await App.Database.GetNotesAsync();


}

This code populates the ListView with any notes stored in the database.
Save the changes to NotesPage.xaml.cs by choosing File > Save (or by pressing ⌘ + S ), and close the
file.

WARNING
Attempting to build the application at this point will result in errors that will be fixed in subsequent steps.

10. In the Solution Pad, double-click NoteEntryPage.xaml.cs to open it. Then replace the
OnSaveButtonClicked and OnDeleteButtonClicked methods with the following code:

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
note.Date = DateTime.UtcNow;
await App.Database.SaveNoteAsync(note);
await Navigation.PopAsync();
}

async void OnDeleteButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
await App.Database.DeleteNoteAsync(note);
await Navigation.PopAsync();
}

The NoteEntryPage stores a Note instance, which represents a single note, in the BindingContext of the
page. When the OnSaveButtonClicked event handler is executed, the Note instance is saved to the database
and the application navigates back to the previous page. When the OnDeleteButtonClicked event handler is
executed, the Note instance is deleted from the database and the application navigates back to the previous
page.
Save the changes to NoteEntryPage.xaml.cs by choosing File > Save (or by pressing ⌘ + S ), and close
the file.
11. Build and run the project on each platform. For more information, see Building the quickstart.
On the NotesPage press the + button to navigate to the NoteEntryPage and enter a note. After saving
the note the application will navigate back to the NotesPage.
Enter a number of notes, of varying length, to observe the application behavior.

Next steps
In this quickstart, you learned how to:
Use the NuGet Package Manager to add a NuGet package to a project.
Store data locally in a SQLite.NET database.
To style the application with XAML styles, continue to the next quickstart.
Next

Related links
Notes (sample)
Xamarin.Forms Quickstart Deep Dive
Style a Cross-Platform Xamarin.Forms Application
5 minutes to read • Edit Online

Download the sample


In this quickstart, you will learn how to:
Style a Xamarin.Forms application using XAML styles.
The quickstart walks through how to style a cross-platform Xamarin.Forms application with XAML styles. The final
application is shown below:

Prerequisites
You should successfully complete the previous quickstart before attempting this quickstart. Alternatively,
download the previous quickstart sample and use it as the starting point for this quickstart.

Update the app with Visual Studio


1. Launch Visual Studio and open the Notes solution.
2. In Solution Explorer, in the Notes project, double-click App.xaml to open it. Then replace the existing
code with the following code:
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.App">
<Application.Resources>

<Thickness x:Key="PageMargin">20</Thickness>

<!-- Colors -->


<Color x:Key="AppBackgroundColor">WhiteSmoke</Color>
<Color x:Key="iOSNavigationBarColor">WhiteSmoke</Color>
<Color x:Key="AndroidNavigationBarColor">#2196F3</Color>
<Color x:Key="iOSNavigationBarTextColor">Black</Color>
<Color x:Key="AndroidNavigationBarTextColor">White</Color>

<!-- Implicit styles -->


<Style TargetType="{x:Type NavigationPage}">
<Setter Property="BarBackgroundColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarColor},
Android={StaticResource AndroidNavigationBarColor}}" />
<Setter Property="BarTextColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarTextColor},
Android={StaticResource AndroidNavigationBarTextColor}}" />
</Style>

<Style TargetType="{x:Type ContentPage}"


ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>

</Application.Resources>
</Application>

This code defines a Thickness value, a series of Color values, and implicit styles for the NavigationPage
and ContentPage . Note that these styles, which are in the application-level ResourceDictionary , can be
consumed throughout the application. For more information about XAML styling, see Styling in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to App.xaml by pressing CTRL+S, and close the file.
3. In Solution Explorer, in the Notes project, double-click NotesPage.xaml to open it. Then replace the
existing code with 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"
x:Class="Notes.NotesPage"
Title="Notes">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type ListView}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>
</ContentPage.Resources>

<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNoteAddedClicked" />
</ContentPage.ToolbarItems>

<ListView x:Name="listView"
Margin="{StaticResource PageMargin}"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

</ContentPage>

This code adds an implicit style for the ListView to the page-level ResourceDictionary , and sets the
ListView.Margin property to a value defined in the application-level ResourceDictionary . Note that the
ListView implicit style was added to the page-level ResourceDictionary , because it is only consumed by
the NotesPage . For more information about XAML styling, see Styling in the Xamarin.Forms Quickstart
Deep Dive.
Save the changes to NotesPage.xaml by pressing CTRL+S, and close the file.
4. In Solution Explorer, in the Notes project, double-click NoteEntryPage.xaml to open it. Then replace
the existing code with 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"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type Editor}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>

<Style TargetType="Button"
ApplyToDerivedTypes="True"
CanCascade="True">
<Setter Property="FontSize" Value="Medium" />
<Setter Property="BackgroundColor" Value="LightGray" />
<Setter Property="TextColor" Value="Black" />
<Setter Property="CornerRadius" Value="5" />
</Style>
</ContentPage.Resources>

<StackLayout Margin="{StaticResource PageMargin}">


<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked" />
</Grid>
</StackLayout>

</ContentPage>

This code adds implicit styles for the Editor and Button views to the page-level ResourceDictionary , and
sets the StackLayout.Margin property to a value defined in the application-level ResourceDictionary . Note
that the Editor and Button implicit styles were added to the page-level ResourceDictionary , because they
are only consumed by the NoteEntryPage . For more information about XAML styling, see Styling in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to NoteEntryPage.xaml by pressing CTRL+S, and close the file.
5. Build and run the project on each platform. For more information, see Building the quickstart.
On the NotesPage press the + button to navigate to the NoteEntryPage and enter a note. On each page,
observe how the styling has changed from the previous quickstart.

Update the app with Visual Studio for Mac


1. Launch Visual Studio for Mac and open the Notes project.
2. In the Solution Pad, in the Notes project, double-click App.xaml to open it. Then replace the existing code
with the following code:
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.App">
<Application.Resources>

<Thickness x:Key="PageMargin">20</Thickness>

<!-- Colors -->


<Color x:Key="AppBackgroundColor">WhiteSmoke</Color>
<Color x:Key="iOSNavigationBarColor">WhiteSmoke</Color>
<Color x:Key="AndroidNavigationBarColor">#2196F3</Color>
<Color x:Key="iOSNavigationBarTextColor">Black</Color>
<Color x:Key="AndroidNavigationBarTextColor">White</Color>

<!-- Implicit styles -->


<Style TargetType="{x:Type NavigationPage}">
<Setter Property="BarBackgroundColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarColor},
Android={StaticResource AndroidNavigationBarColor}}" />
<Setter Property="BarTextColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarTextColor},
Android={StaticResource AndroidNavigationBarTextColor}}" />
</Style>

<Style TargetType="{x:Type ContentPage}"


ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>

</Application.Resources>
</Application>

This code defines a Thickness value, a series of Color values, and implicit styles for the NavigationPage
and ContentPage . Note that these styles, which are in the application-level ResourceDictionary , can be
consumed throughout the application. For more information about XAML styling, see Styling in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to App.xaml by choosing File > Save (or by pressing ⌘ + S ), and close the file.
3. In the Solution Pad, in the Notes project, double-click NotesPage.xaml to open it. Then replace the
existing code with 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"
x:Class="Notes.NotesPage"
Title="Notes">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type ListView}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>
</ContentPage.Resources>

<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNoteAddedClicked" />
</ContentPage.ToolbarItems>

<ListView x:Name="listView"
Margin="{StaticResource PageMargin}"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

</ContentPage>

This code adds an implicit style for the ListView to the page-level ResourceDictionary , and sets the
ListView.Margin property to a value defined in the application-level ResourceDictionary . Note that the
ListView implicit style was added to the page-level ResourceDictionary , because it is only consumed by
the NotesPage . For more information about XAML styling, see Styling in the Xamarin.Forms Quickstart
Deep Dive.
Save the changes to NotesPage.xaml by choosing File > Save (or by pressing ⌘ + S ), and close the file.
4. In the Solution Pad, in the Notes project, double-click NoteEntryPage.xaml to open it. Then replace the
existing code with 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"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type Editor}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>

<Style TargetType="Button"
ApplyToDerivedTypes="True"
CanCascade="True">
<Setter Property="FontSize" Value="Medium" />
<Setter Property="BackgroundColor" Value="LightGray" />
<Setter Property="TextColor" Value="Black" />
<Setter Property="CornerRadius" Value="5" />
</Style>
</ContentPage.Resources>

<StackLayout Margin="{StaticResource PageMargin}">


<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked" />
</Grid>
</StackLayout>

</ContentPage>

This code adds implicit styles for the Editor and Button views to the page-level ResourceDictionary , and
sets the StackLayout.Margin property to a value defined in the application-level ResourceDictionary . Note
that the Editor and Button implicit styles were added to the page-level ResourceDictionary , because they
are only consumed by the NoteEntryPage . For more information about XAML styling, see Styling in the
Xamarin.Forms Quickstart Deep Dive.
Save the changes to NoteEntryPage.xaml by choosing File > Save (or by pressing ⌘ + S ), and close the
file.
5. Build and run the project on each platform. For more information, see Building the quickstart.
On the NotesPage press the + button to navigate to the NoteEntryPage and enter a note. On each page,
observe how the styling has changed from the previous quickstart.

Next steps
In this quickstart, you learned how to:
Style a Xamarin.Forms application using XAML styles.
To learn more about the fundamentals of application development using Xamarin.Forms, continue to the
quickstart deep dive.
Next

Related links
Notes (sample)
Xamarin.Forms Quickstart Deep Dive
Xamarin.Forms Quickstart Deep Dive
17 minutes to read • Edit Online

In the Xamarin.Forms Quickstart, the Notes application was built. This article reviews what has been built
to gain an understanding of the fundamentals of how Xamarin.Forms applications work.

Introduction to Visual Studio


Visual Studio organizes code into Solutions and Projects. A solution is a container that can hold one or
more projects. A project can be an application, a supporting library, a test application, and more. The
Notes application consists of one solution containing four projects, as shown in the following screenshot:

The projects are:


Notes – This project is the .NET Standard library project that holds all of the shared code and shared
UI.
Notes.Android – This project holds Android-specific code and is the entry point for the Android
application.
Notes.iOS – This project holds iOS -specific code and is the entry point for the iOS application.
Notes.UWP – This project holds Universal Windows Platform (UWP ) specific code and is the entry
point for the UWP application.

Anatomy of a Xamarin.Forms application


The following screenshot shows the contents of the Notes .NET Standard library project in Visual Studio:
The project has a Dependencies node that contains NuGet and SDK nodes:
NuGet – the Xamarin.Forms and sqlite-net-pcl NuGet packages that have been added to the project.
SDK – the NETStandard.Library metapackage that references the complete set of NuGet packages
that define .NET Standard.

Introduction to Visual Studio for Mac


Visual Studio for Mac follows the Visual Studio practice of organizing code into Solutions and Projects. A
solution is a container that can hold one or more projects. A project can be an application, a supporting
library, a test application, and more. The Notes application consists of one solution containing three
projects, as shown in the following screenshot:

The projects are:


Notes – This project is the .NET Standard library project that holds all of the shared code and shared
UI.
Notes.Android – This project holds Android-specific code and is the entry point for Android
applications.
Notes.iOS – This project holds iOS specific-code and is the entry point for iOS applications.

Anatomy of a Xamarin.Forms application


The following screenshot shows the contents of the Notes .NET Standard library project in Visual Studio
for Mac:
The project has a Dependencies node that contains NuGet and SDK nodes:
NuGet – the Xamarin.Forms and sqlite-net-pcl NuGet packages that have been added to the project.
SDK – the NETStandard.Library metapackage that references the complete set of NuGet packages
that define .NET Standard.
The project also consists of a number of files:
Data\NoteDatabase.cs – This class contains code to create the database, read data from it, write
data to it, and delete data from it.
Models\Note.cs – This class defines a Note model whose instances store data about each note in
the application.
App.xaml – The XAML markup for the App class, which defines a resource dictionary for the
application.
App.xaml.cs – The code-behind for the App class, which is responsible for instantiating the first page
that will be displayed by the application on each platform, and for handling application lifecycle
events.
AssemblyInfo.cs – This file contains an application attribute about the project, that is applied at the
assembly level.
NotesPage.xaml – The XAML markup for the NotesPage class, which defines the UI for the page
shown when the application launches.
NotesPage.xaml.cs – The code-behind for the NotesPage class, which contains the business logic
that is executed when the user interacts with the page.
NoteEntryPage.xaml – The XAML markup for the NoteEntryPage class, which defines the UI for the
page shown when the user enters a note.
NoteEntryPage.xaml.cs – The code-behind for the NoteEntryPage class, which contains the business
logic that is executed when the user interacts with the page.
For more information about the anatomy of a Xamarin.iOS application, see Anatomy of a Xamarin.iOS
Application. For more information about the anatomy of a Xamarin.Android application, see Anatomy of
a Xamarin.Android Application.

Architecture and application fundamentals


A Xamarin.Forms application is architected in the same way as a traditional cross-platform application.
Shared code is typically placed in a .NET Standard library, and platform-specific applications consume the
shared code. The following diagram shows an overview of this relationship for the Notes application:

To maximize the reuse of startup code, Xamarin.Forms applications have a single class named App that
is responsible for instantiating the first page that will be displayed by the application on each platform, as
shown in the following code example:
using Xamarin.Forms;

namespace Notes
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
...
}
}

This code sets the MainPage property of the App class to a NavigationPage instance whose content is a
NotesPage instance.

In addition, the AssemblyInfo.cs file contains a single application attribute, that is applied at the
assembly level:

using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

The XamlCompilation attribute turns on the XAML compiler, so that XAML is compiled directly into
intermediate language. For more information, see XAML Compilation.

Launching the application on each platform


iOS
To launch the initial Xamarin.Forms page in iOS, the Notes.iOS project defines the AppDelegate class that
inherits from the FormsApplicationDelegate class:

namespace Notes.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}
}

The FinishedLaunching override initializes the Xamarin.Forms framework by calling the Init method.
This causes the iOS -specific implementation of Xamarin.Forms to be loaded in the application before the
root view controller is set by the call to the LoadApplication method.
Android
To launch the initial Xamarin.Forms page in Android, the Notes.Android project includes code that
creates an Activity with the MainLauncher attribute, with the activity inheriting from the
FormsAppCompatActivity class:
namespace Notes.Droid
{
[Activity(Label = "Notes",
Icon = "@mipmap/icon",
Theme = "@style/MainTheme",
MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;

base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
}

The OnCreate override initializes the Xamarin.Forms framework by calling the Init method. This causes
the Android-specific implementation of Xamarin.Forms to be loaded in the application before the
Xamarin.Forms application is loaded.
Universal Windows Platform
In Universal Windows Platform (UWP ) applications, the Init method that initializes the Xamarin.Forms
framework is invoked from the App class:

Xamarin.Forms.Forms.Init (e);

if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
...
}

This causes the UWP -specific implementation of Xamarin.Forms to be loaded in the application. The
initial Xamarin.Forms page is launched by the MainPage class:

namespace Notes.UWP
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
this.LoadApplication(new Notes.App());
}
}
}

The Xamarin.Forms application is loaded with the LoadApplication method.

NOTE
Universal Windows Platform apps can be built with Xamarin.Forms, but only using Visual Studio on Windows.

User interface
There are four main control groups used to create the user interface of a Xamarin.Forms application:
1. Pages – Xamarin.Forms pages represent cross-platform mobile application screens. The Notes
application uses the ContentPage class to display single screens. For more information about pages,
see Xamarin.Forms Pages.
2. Views – Xamarin.Forms views are the controls displayed on the user interface, such as labels, buttons,
and text entry boxes. The finished Notes application uses the ListView , Editor , and Button views.
For more information about views, see Xamarin.Forms Views.
3. Layouts – Xamarin.Forms layouts are containers used to compose views into logical structures. The
Notes application uses the StackLayout class to arrange views in a vertical stack, and the Grid class
to arrange buttons horizontally. For more information about layouts, see Xamarin.Forms Layouts.
4. Cells – Xamarin.Forms cells are specialized elements used for items in a list, and describe how each
item in a list should be drawn. The Notes application uses the TextCell to display two items for each
row in the list. For more information about cells, see Xamarin.Forms Cells.
At runtime, each control will be mapped to its native equivalent, which is what will be rendered.
Layout
The Notes application uses the StackLayout to simplify cross-platform application development by
automatically arranging views on the screen regardless of the screen size. Each child element is
positioned one after the other, either horizontally or vertically in the order they were added. How much
space the StackLayout will use depends on how the HorizontalOptions and VerticalOptions properties
are set, but by default the StackLayout will try to use the entire screen.
The following XAML code shows an example of using a StackLayout to layout the NoteEntryPage :

<?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="Notes.NoteEntryPage"
Title="Note Entry">
...
<StackLayout Margin="{StaticResource PageMargin}">
<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
...
</Grid>
</StackLayout>
</ContentPage>

By default the StackLayout assumes a vertical orientation. However, it can be changed to a horizontal
orientation by setting the StackLayout.Orientation property to the StackOrientation.Horizontal
enumeration member.

NOTE
The size of views can be set through the HeightRequest and WidthRequest properties.

For more information about the StackLayout class, see StackLayout.


Responding to user interaction
An object defined in XAML can fire an event that is handled in the code-behind file. The following code
example shows the OnSaveButtonClicked method in the code-behind for the NoteEntryPage class, which
is executed in response to the Clicked event firing on the Save button.

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
note.Date = DateTime.UtcNow;
await App.Database.SaveNoteAsync(note);
await Navigation.PopAsync();
}

The OnSaveButtonClicked method saves the note in the database, and navigates back to the previous
page.

NOTE
The code-behind file for a XAML class can access an object defined in XAML using the name assigned to it with
the x:Name attribute. The value assigned to this attribute has the same rules as C# variables, in that it must
begin with a letter or underscore and contain no embedded spaces.

The wiring of the save button to the OnSaveButtonClicked method occurs in the XAML markup for the
NoteEntryPage class:

<Button Text="Save"
Clicked="OnSaveButtonClicked" />

Lists
The ListView is responsible for displaying a collection of items vertically in a list. Each item in the
ListView will be contained in a single cell.

The following code example shows the ListView from the NotesPage :

<ListView x:Name="listView"
Margin="{StaticResource PageMargin}"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

The layout of each row in the ListView is defined within the ListView.ItemTemplate element, and uses
data binding to display any notes that are retrieved by the application. The ListView.ItemsSource
property is set to the data source, in NotesPage.xaml.cs :

protected override async void OnAppearing()


{
base.OnAppearing();

listView.ItemsSource = await App.Database.GetNotesAsync();


}

This code populates the ListView with any notes stored in the database.
When a row is selected in the ListView , the ItemSelected event fires. An event handler, named
OnListViewItemSelected , is executed when the event fires:

async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)


{
if (e.SelectedItem != null)
{
...
}
}

The ItemSelected event can access the object that was associated with the cell through the
e.SelectedItem property.
For more information about the ListView class, see ListView.

Navigation
Xamarin.Forms provides a number of different page navigation experiences, depending upon the Page
type being used. For ContentPage instances navigation can be hierarchical, or modal. For information
about modal navigation, see Xamarin.Forms Modal Pages.

NOTE
The CarouselPage , MasterDetailPage and TabbedPage classes provide alternative navigation experiences. For
more information, see Navigation.

In hierarchical navigation, the NavigationPage class is used to navigate through a stack of ContentPage
objects, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO )
stack of Page objects. To move from one page to another, an application will push a new page onto the
navigation stack, where it will become the active page. To return back to the previous page, the
application will pop the current page from the navigation stack, and the new topmost page becomes the
active page.
The NavigationPage class will also add a navigation bar to the top of the page that displays a title and a
platform-appropriate Back button that will return to the previous page.
The first page added to a navigation stack is referred to as the root page of the application, and the
following code example shows how this is accomplished in the Notes application:

public App ()
{
...
MainPage = new NavigationPage (new NotesPage ());
}

All ContentPage instances have a Navigation property that exposes methods to modify the page stack.
These methods should only be invoked if the application includes a NavigationPage . To navigate to the
NoteEntryPage , it is necessary to invoke the PushAsync method as demonstrated in the code example
below:

await Navigation.PushAsync(new NoteEntryPage());

This causes the new NoteEntryPage object to be pushed onto the navigation stack, where it becomes the
active page.
The active page can be popped from the navigation stack by pressing the Back button on the device,
regardless of whether this is a physical button on the device or an on-screen button. To programmatically
return back to the original page, the NoteEntryPage object must invoke the PopAsync method, as
demonstrated in the code example below:

await Navigation.PopAsync();

For more information about hierarchical navigation, see Hierarchical Navigation.

Data binding
Data binding is used to simplify how a Xamarin.Forms application displays and interacts with its data. It
establishes a connection between the user interface and the underlying application. The BindableObject
class contains much of the infrastructure to support data binding.
Data binding connects two objects, called the source and the target. The source object provides the data.
The target object will consume (and often display) data from the source object. For example, an Editor
(target object) will commonly bind its Text property to a public string property in a source object. The
following diagram illustrates the binding relationship:

The main benefit of data binding is that you no longer have to worry about synchronizing data between
your views and data source. Changes in the source object are automatically pushed to the target object
behind-the-scenes by the binding framework, and changes in the target object can be optionally pushed
back to the source object.
Establishing data binding is a two-step process:
The BindingContext property of the target object must be set to the source.
A binding must be established between the target and the source. In XAML, this is achieved by using
the Binding markup extension.

In the Notes application, the binding target is the Editor that displays a note, while the Note instance
set as the BindingContext of NoteEntryPage is the binding source.
The BindingContext of the NoteEntryPage is set during page navigation, as shown in the following code
example:
async void OnNoteAddedClicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = new Note()
});
}

async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)


{
if (e.SelectedItem != null)
{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = e.SelectedItem as Note
});
}
}

In the OnNoteAddedClicked method, which is executed when a new note is added to the application, the
BindingContext of NoteEntryPage is set to a new Note instance. In the OnListViewItemSelected method,
which is executed when an existing note is selected in the ListView , the BindingContext of the
NoteEntryPage is set to the selected Note instance, which is accessed through the e.SelectedItem
property.

IMPORTANT
While the BindingContext property of each target object can be individually set, this isn’t necessary.
BindingContext is a special property that’s inherited by all its children. Therefore, when the BindingContext
on the ContentPage is set to a Note instance, all of the children of the ContentPage have the same
BindingContext , and can bind to public properties of the Note object.

The Editor in NoteEntryPage then binds to the Text property of the Note object:

<Editor Placeholder="Enter your note"


Text="{Binding Text}"
... />

A binding between the Editor.Text property and the Text property of the source object is established.
Changes made in the Editor will automatically be propagated to the Note object. Similarly, if changes
are made to the Note.Text property, the Xamarin.Forms binding engine will also update the contents of
the Editor . This is known as a two -way binding.
For more information about data binding, see Xamarin.Forms Data Binding.

Styling
Xamarin.Forms applications often contain multiple visual elements that have an identical appearance.
Setting the appearance of each visual element can be repetitive and error prone. Instead, styles can be
created that define the appearance, and then applied to the required visual elements.
The Style class groups a collection of property values into one object that can then be applied to
multiple visual element instances. Styles are stored in a ResourceDictionary , either at the application
level, the page level, or the view level. Choosing where to define a Style impacts where it can be used:
Style instances defined at the application level can be applied throughout the application.
Style instances defined at the page level can be applied to the page and to its children.
Style instances defined at the view level can be applied to the view and to its children.

IMPORTANT
Any styles that are used throughout the application are stored in the application's resource dictionary to avoid
duplication. However, XAML that's specific to a page shouldn't be included in the application's resource dictionary,
as the resources will then be parsed at application startup instead of when required by a page.

Each Style instance contains a collection of one or more Setter objects, with each Setter having a
Property and a Value . The Property is the name of the bindable property of the element the style is
applied to, and the Value is the value that is applied to the property. The following code example shows
a style from NoteEntryPage :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type Editor}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>
...
</ContentPage.Resources>
...
</ContentPage>

This style is applied to any Editor instances on the page.


When creating a Style , the TargetType property is always required.

NOTE
Styling a Xamarin.Forms application is traditionally accomplished by using XAML styles. However, Xamarin.Forms
also supports styling visual elements using Cascading Style Sheets (CSS). For more information, see Styling
Xamarin.Forms apps using Cascading Style Sheets (CSS).

For more information about XAML styles, see Styling Xamarin.Forms Apps using XAML Styles.
Providing platform-specific styles
The OnPlatform markup extensions allow you to customize UI appearance on a per-platform basis:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.App">
<Application.Resources>
...
<Color x:Key="iOSNavigationBarColor">WhiteSmoke</Color>
<Color x:Key="AndroidNavigationBarColor">#2196F3</Color>
<Color x:Key="iOSNavigationBarTextColor">Black</Color>
<Color x:Key="AndroidNavigationBarTextColor">White</Color>

<Style TargetType="{x:Type NavigationPage}">


<Setter Property="BarBackgroundColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarColor},
Android={StaticResource AndroidNavigationBarColor}}" />
<Setter Property="BarTextColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarTextColor},
Android={StaticResource AndroidNavigationBarTextColor}}" />
</Style>
...
</Application.Resources>
</Application>

This sets different Color values for the BarBackgroundColor and


Style BarTextColor properties of
NavigationPage , depending on the platform being used.

For more information about XAML markup extensions, see XAML Markup Extensions. For information
about the OnPlatform markup extension, see OnPlatform Markup Extension.

Testing and deployment


Visual Studio for Mac and Visual Studio both provide many options for testing and deploying an
application. Debugging applications is a common part of the application development lifecycle and helps
to diagnose code issues. For more information, see Set a Breakpoint, Step Through Code, and Output
Information to the Log Window.
Simulators are a good place to start deploying and testing an application, and feature useful functionality
for testing applications. However, users will not consume the final application in a simulator, so
applications should be tested on real devices early and often. For more information about iOS device
provisioning, see Device Provisioning. For more information about Android device provisioning, see Set
Up Device for Development.

Next steps
This deep dive has examined the fundamentals of application development using Xamarin.Forms.
Suggested next steps include reading about the following functionality:
There are four main control groups used to create the user interface of a Xamarin.Forms application.
For more information, see Controls Reference.
Data binding is a technique for linking properties of two objects so that changes in one property are
automatically reflected in the other property. For more information, see Data Binding.
Xamarin.Forms provides a number of different page navigation experiences, depending upon the
page type being used. For more information, see Navigation.
Styles help to reduce repetitive markup, and allow an applications appearance to be more easily
changed. For more information, see Styling Xamarin.Forms Apps.
XAML markup extensions extend the power and flexibility of XAML by allowing element attributes to
be set from sources other than literal text strings. For more information, see XAML Markup
Extensions.
Data templates provide the ability to define the presentation of data on supported views. For more
information, see Data Templates.
Each page, layout, and view is rendered differently on each platform using a Renderer class that in
turn creates a native control, arranges it on the screen, and adds the behavior specified in the shared
code. Developers can implement their own custom Renderer classes to customize the appearance
and/or behavior of a control. For more information, see Custom Renderers.
Effects also allow the native controls on each platform to be customized. Effects are created in
platform-specific projects by subclassing the PlatformEffect class, and are consumed by attaching
them to an appropriate Xamarin.Forms control. For more information, see Effects.
Shared code can access native functionality through the DependencyService class. For more
information, see Accessing Native Features with DependencyService.
Alternatively, Creating Mobile Apps with Xamarin.Forms, a book by Charles Petzold, is a good place to
learn more about Xamarin.Forms. The book is available as a PDF or in a variety of ebook formats.

Related links
eXtensible Application Markup Language (XAML )
Data Binding
Controls Reference
XAML Markup Extensions
Xamarin.Forms Samples
Getting Started Samples
Xamarin.Forms API reference
Free Self-Guided Learning (video)

Related video

Find more Xamarin videos on Channel 9 and YouTube.


Cross-Platform for Desktop Developers
2 minutes to read • Edit Online

This section contains information to help WPF and Windows Forms developers to learn mobile app development
with Xamarin, by cross-referencing their existing knowledge and experience to mobile idioms, and providing
examples of porting desktop apps to mobile.

App Lifecycle Comparison


Understanding the differences between WPF and Xamarin.Forms app startup and background states.

UI Controls Comparison
Quick reference to find equivalent controls in Windows Forms, WPF, and Xamarin.Forms, including additional
guidance on the differences between WPF and Xamarin.Forms.

Porting Guidance
Using the Portability Analyzer to help migrate desktop application code (excluding the user interface) to
Xamarin.Forms.

Samples
Reference samples demonstrating enterprise application architecture and porting code from WPF to
Xamarin.Forms.

Learn More
Xamarin for Java developers
24 minutes to read • Edit Online

If you are a Java developer, you are well on your way to leveraging your skills and existing code on the Xamarin
platform while reaping the code reuse benefits of C#. You will find that C# syntax is very similar to Java syntax, and
that both languages provide very similar features. In addition, you'll discover features unique to C# that will make
your development life easier.

Overview
This article provides an introduction to C# programming for Java developers, focusing primarily on the C#
language features that you will encounter while developing Xamarin.Android applications. Also, this article explains
how these features differ from their Java counterparts, and it introduces important C# features (relevant to
Xamarin.Android) that are not available in Java. Links to additional reference material are included, so you can use
this article as a "jumping off" point for further study of C# and .NET.
If you are familiar with Java, you will feel instantly at home with the syntax of C#. C# syntax is very similar to Java
syntax – C# is a "curly brace" language like Java, C, and C++. In many ways, C# syntax reads like a superset of Java
syntax, but with a few renamed and added keywords.
Many key characteristics of Java can be found in C#:
Class-based object-oriented programming
Strong typing
Support for interfaces
Generics
Garbage collection
Runtime compilation
Both Java and C# are compiled to an intermediate language that is run in a managed execution environment. Both
C# and Java are statically-typed, and both languages treat strings as immutable types. Both languages use a single-
rooted class hierarchy. Like Java, C# supports only single inheritance and does not allow for global methods. In
both languages, objects are created on the heap using the new keyword, and objects are garbage-collected when
they are no longer used. Both languages provide formal exception handling support with try / catch semantics.
Both provide thread management and synchronization support.
However, there are many differences between Java and C#. For example:
Java (as used on Android) does not support implicitly-typed local variables (C# supports the var keyword).
In Java, you can pass parameters only by value, while in C# you can pass by reference as well as by value.
(C# provides the ref and out keywords for passing parameters by reference; there is no equivalent to
these in Java).
Java does not support preprocessor directives like #define .
Java does not support unsigned integer types, while C# provides unsigned integer types such as ulong ,
uint , ushort and byte .

Java does not support operator overloading; in C# you can overload operators and conversions.
In a Java switch statement, code can fall through into the next switch section, but in C# the end of every
switch section must terminate the switch (the end of each section must close with a break statement).

In Java, you specify the exceptions thrown by a method with the throws keyword, but C# has no concept of
checked exceptions – the throws keyword is not supported in C#.
C# supports Language-Integrated Query (LINQ ), which lets you use the reserved words from , select , and
where to write queries against collections in a way that is similar to database queries.

Of course, there are many more differences between C# and Java than can be covered in this article. Also, both
Java and C# continue to evolve (for example, Java 8, which is not yet in the Android toolchain, supports C#-style
lambda expressions) so these differences will change over time. Only the most important differences currently
encountered by Java developers new to Xamarin.Android are outlined here.
Going from Java to C# Development provides an introduction to the fundamental differences between C#
and Java.
Object-Oriented Programming Features outlines the most important object-oriented feature differences
between the two languages.
Keyword Differences provides a table of useful keyword equivalents, C#-only keywords, and links to C#
keyword definitions.
C# brings many key features to Xamarin.Android that are not currently readily available to Java developers on
Android. These features can help you to write better code in less time:
Properties – With C#'s property system, you can access member variables safely and directly without having
to write setter and getter methods.
Lambda Expressions – In C# you can use anonymous methods (also called lambdas) to express your
functionality more succinctly and more efficiently. You can avoid the overhead of having to write one-time-
use objects, and you can pass local state to a method without having to add parameters.
Event Handling – C# provides language-level support for event-driven programming, where an object can
register to be notified when an event of interest occurs. The event keyword defines a multicast broadcast
mechanism that a publisher class can use to notify event subscribers.
Asynchronous Programming – The asynchronous programming features of C# ( async / await ) keep apps
responsive. The language-level support of this feature makes async programming easy to implement and
less error-prone.
Finally, Xamarin allows you to leverage existing Java assets via a technology known as binding. You can call your
existing Java code, frameworks, and libraries from C# by making use of Xamarin's automatic binding generators.
To do this, you simply create a static library in Java and expose it to C# via a binding.

NOTE
Android programming uses a specific version of the Java language that supports all Java 7 features and a subset of Java 8.
Some features mentioned on this page (such as the var keyword in C#) are available in newer versions of Java (e.g. var in
Java 10), but are still not available to Android developers.

Going from Java to C# development


The following sections outline the basic "getting started" differences between C# and Java; a later section describes
the object-oriented differences between these languages.
Libraries vs. assemblies
Java typically packages related classes in .jar files. In C# and .NET, however, reusable bits of precompiled code are
packaged into assemblies, which are typically packaged as .dll files. An assembly is a unit of deployment for
C#/.NET code, and each assembly is typically associated with a C# project. Assemblies contain intermediate code
(IL ) that is just-in-time compiled at runtime.
For more information about assemblies, see the Assemblies and the Global Assembly Cache topic.
Packages vs. namespaces
C# uses the namespace keyword to group related types together; this is similar to Java's package keyword.
Typically, a Xamarin.Android app will reside in a namespace created for that app. For example, the following C#
code declares the WeatherApp namespace wrapper for a weather-reporting app:

namespace WeatherApp
{
...

Importing types
When you make use of types defined in external namespaces, you import these types with a using statement
(which is very similar to the Java import statement). In Java, you might import a single type with a statement like
the following:

import javax.swing.JButton

You might import an entire Java package with a statement like this:

import javax.swing.*

The C# using statement works in a very similar way, but it allows you to import an entire package without
specifying a wildcard. For example, you will often see a series of using statements at the beginning of
Xamarin.Android source files, as seen in this example:

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Net;
using System.IO;
using System.Json;
using System.Threading.Tasks;

These statements import functionality from the System , Android.App , Android.Content , etc. namespaces.
Generics
Both Java and C# support generics, which are placeholders that let you plug in different types at compile time.
However, generics work slightly differently in C#. In Java, type erasure makes type information available only at
compile time, but not at run time. By contrast, the .NET common language runtime (CLR ) provides explicit support
for generic types, which means that C# has access to type information at runtime. In day-to-day Xamarin.Android
development, the importance of this distinction is not often apparent, but if you are using reflection, you will
depend on this feature to access type information at run time.
In Xamarin.Android, you will often see the generic method FindViewById used to get a reference to a layout
control. This method accepts a generic type parameter that specifies the type of control to look up. For example:

TextView label = FindViewById<TextView> (Resource.Id.Label);

In this code example, FindViewById gets a reference to the TextView control that is defined in the layout as Label,
then returns it as a TextView type.
For more information about generics, see the Generics topic. Note that there are some limitations in
Xamarin.Android support for generic C# classes; for more information, see Limitations.

Object-oriented programming features


Both Java and C# use very similar object-oriented programming idioms:
All classes are ultimately derived from a single root object – all Java objects derive from java.lang.Object ,
while all C# objects derive from System.Object .
Instances of classes are reference types.
When you access the properties and methods of an instance, you use the " . " operator.
All class instances are created on the heap via the new operator.
Because both languages use garbage collection, there is no way to explicitly release unused objects (i.e.,
there is not a delete keyword as there is in C++).
You can extend classes through inheritance, and both languages only allow a single base class per type.
You can define interfaces, and a class can inherit from (i.e., implement) multiple interface definitions.
However, there are also some important differences:
Java has two powerful features that C# does not support: anonymous classes and inner classes. (However,
C# does allow nesting of class definitions – C#'s nested classes are like Java's static nested classes.)
C# supports C -style structure types ( struct ) while Java does not.
In C#, you can implement a class definition in separate source files by using the partial keyword.
C# interfaces cannot declare fields.
C# uses C++-style destructor syntax to express finalizers. The syntax is different from Java's finalize
method, but the semantics are nearly the same. (Note that in C#, destructors automatically call the base-
class destructor – in contrast to Java where an explicit call to super.finalize is used.)
Class inheritance
To extend a class in Java, you use the extends keyword. To extend a class in C#, you use a colon ( : ) to indicate
derivation. For example, in Xamarin.Android apps, you will often see class derivations that resemble the following
code fragment:

public class MainActivity : Activity


{
...

In this example, MainActivity inherits from the Activity class.


To declare support for an interface in Java, you use the implements keyword. However, in C#, you simply add
interface names to the list of classes to inherit from, as shown in this code fragment:

public class SensorsActivity : Activity, ISensorEventListener


{
...

In this example, SensorsActivityinherits from Activity and implements the functionality declared in the
ISensorEventListener interface. Note that the list of interfaces must come after the base class (or you will get a
compile-time error). By convention, C# interface names are prepended with an upper-case "I"; this makes it
possible to determine which classes are interfaces without requiring an implements keyword.
When you want to prevent a class from being further subclassed in C#, you precede the class name with sealed –
in Java, you precede the class name with final .
For more about C# class definitions, see the Classes and Inheritance topics.
Properties
In Java, mutator methods (setters) and inspector methods (getters) are often used to control how changes are
made to class members while hiding and protecting these members from outside code. For example, the Android
TextView class provides getText and setText methods. C# provides a similar but more direct mechanism known
as properties. Users of a C# class can access a property in the same way as they would access a field, but each
access actually results in a method call that is transparent to the caller. This "under the covers" method can
implement side effects such as setting other values, performing conversions, or changing object state.
Properties are often used for accessing and modifying UI (user interface) object members. For example:

int width = rulerView.MeasuredWidth;


int height = rulerView.MeasuredHeight;
...
rulerView.DrawingCacheEnabled = true;

In this example, width and height values are read from the rulerView object by accessing its MeasuredWidth and
MeasuredHeight properties. When these properties are read, values from their associated (but hidden) field values
are fetched behind the scenes and returned to the caller. The rulerView object may store width and height values
in one unit of measurement (say, pixels) and convert these values on-the-fly to a different unit of measurement
(say, millimeters) when the MeasuredWidth and MeasuredHeight properties are accessed.
The rulerView object also has a property called DrawingCacheEnabled – the example code sets this property to
true to enable the drawing cache in rulerView . Behind the scenes, an associated hidden field is updated with the
new value, and possibly other aspects of rulerView state are modified. For example, when DrawingCacheEnabled is
set to false , rulerView may also erase any drawing cache information already accumulated in the object.
Access to properties can be read/write, read-only, or write-only. Also, you can use different access modifiers for
reading and writing. For example, you can define a property that has public read access but private write access.
For more information about C# properties, see the Properties topic.
Calling base class methods
To call a base-class constructor in C#, you use a colon ( : ) followed by the base keyword and an initializer list; this
base constructor call is placed immediately after the derived constructor parameter list. The base-class constructor
is called on entry to the derived constructor; the compiler inserts the call to the base constructor at the start of the
method body. The following code fragment illustrates a base constructor called from a derived constructor in a
Xamarin.Android app:
public class PictureLayout : ViewGroup
{
...
public PictureLayout (Context context)
: base (context)
{
...
}
...
}

In this example, the PictureLayout class is derived from the ViewGroup class. The PictureLayout constructor
shown in this example accepts a context argument and passes it to the ViewGroup constructor via the
base(context) call.

To call a base-class method in C#, use the base keyword. For example, Xamarin.Android apps often make calls to
base methods as shown here:

public class MainActivity : Activity


{
...
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);

In this case, the OnCreate method defined by the derived class ( MainActivity ) calls the OnCreate method of the
base class ( Activity ).
Access modifiers
Java and C# both support the public , private , and protected access modifiers. However, C# supports two
additional access modifiers:
internal – The class member is accessible only within the current assembly.
protected internal – The class member is accessible within the defining assembly, the defining class, and
derived classes (derived classes both inside and outside the assembly have access).
For more information about C# access modifiers, see the Access Modifiers topic.
Virtual and override methods
Both Java and C# support polymorphism, the ability to treat related objects in the same manner. In both languages,
you can use a base-class reference to refer to a derived-class object, and the methods of a derived class can
override the methods of its base classes. Both languages have the concept of a virtual method, a method in a base
class that is designed to be replaced by a method in a derived class. Like Java, C# supports abstract classes and
methods.
However, there are some differences between Java and C# in how you declare virtual methods and override them:
In C#, methods are non-virtual by default. Parent classes must explicitly label which methods are to be
overridden by using the virtual keyword. By contrast, all methods in Java are virtual methods by default.
To prevent a method from being overridden in C#, you simply leave off the virtual keyword. By contrast,
Java uses the final keyword to mark a method with "override is not allowed."
C# derived classes must use the override keyword to explicitly indicate that a virtual base-class method is
being overridden.
For more information about C#'s support for polymorphism, see the Polymorphism topic.

Lambda expressions
C# makes it possible to create closures: inline, anonymous methods that can access the state of the method in
which they are enclosed. Using lambda expressions, you can write fewer lines of code to implement the same
functionality that you might have implemented in Java with many more lines of code.
Lambda expressions make it possible for you to skip the extra ceremony involved in creating a one-time-use class
or anonymous class as you would in Java – instead, you can just write the business logic of your method code
inline. Also, because lambdas have access to the variables in the surrounding method, you don't have to create a
long parameter list to pass state to your method code.
In C#, lambda expressions are created with the => operator as shown here:

(arg1, arg2, ...) => {


// implementation code
};

In Xamarin.Android, lambda expressions are often used for defining event handlers. For example:

button.Click += (sender, args) => {


clickCount += 1; // access variable in surrounding code
button.Text = string.Format ("Clicked {0} times.", clickCount);
};

In this example, the lambda expression code (the code within the curly braces) increments a click count and updates
the button text to display the click count. This lambda expression is registered with the button object as a click
event handler to be called whenever the button is tapped. (Event handlers are explained in more detail below.) In
this simple example, the sender and args parameters are not used by the lambda expression code, but they are
required in the lambda expression to meet the method signature requirements for event registration. Under the
hood, the C# compiler translates the lambda expression into an anonymous method that is called whenever button
click events take place.
For more information about C# and lambda expressions, see the Lambda Expressions topic.

Event handling
An event is a way for an object to notify registered subscribers when something interesting happens to that object.
Unlike in Java, where a subscriber typically implements a Listener interface that contains a callback method, C#
provides language-level support for event handling through delegates. A delegate is like an object-oriented type-
safe function pointer – it encapsulates an object reference and a method token. If a client object wants to subscribe
to an event, it creates a delegate and passes the delegate to the notifying object. When the event occurs, the
notifying object invokes the method represented by the delegate object, notifying the subscribing client object of
the event. In C#, event handlers are essentially nothing more than methods that are invoked through delegates.
For more information about delegates, see the Delegates topic.
In C#, events are multicast; that is, more than one listener can be notified when an event takes place. This difference
is observed when you consider the syntactical differences between Java and C# event registration. In Java you call
SetXXXListener to register for event notifications; in C# you use the += operator to register for event notifications
by "adding" your delegate to the list of event listeners. In Java, you call SetXXXListener to unregister, while in C#
you use the -= to "subtract" your delegate from the list of listeners.
In Xamarin.Android, events are often used for notifying objects when a user does something to a UI control.
Normally, a UI control will have members that are defined using the event keyword; you attach your delegates to
these members to subscribe to events from that UI control.
To subscribe to an event:
1. Create a delegate object that refers to the method that you want to be invoked when the event occurs.
2. Use the += operator to attach your delegate to the event you are subscribing to.

The following example defines a delegate (with an explicit use of the delegate keyword) to subscribe to button
clicks. This button-click handler starts a new activity:

startActivityButton.Click += delegate {
Intent intent = new Intent (this, typeof (MyActivity));
StartActivity (intent);
};

However, you also can use a lambda expression to register for events, skipping the delegate keyword altogether.
For example:

startActivityButton.Click += (sender, e) => {


Intent intent = new Intent (this, typeof (MyActivity));
StartActivity (intent);
};

In this example, the startActivityButton object has an event that expects a delegate with a certain method
signature: one that accepts sender and event arguments and returns void. However, because we don't want to go to
the trouble to explicitly define such a delegate or its method, we declare the signature of the method with
(sender, e) and use a lambda expression to implement the body of the event handler. Note that we have to
declare this parameter list even though we aren't using the sender and e parameters.
It is important to remember that you can unsubscribe a delegate (via the -= operator), but you cannot
unsubscribe a lambda expression – attempting to do so can cause memory leaks. Use the lambda form of event
registration only when your handler will not unsubscribe from the event.
Typically, lambda expressions are used to declare event handlers in Xamarin.Android code. This shorthand way to
declare event handlers may seem cryptic at first, but it saves an enormous amount of time when you are writing
and reading code. With increasing familiarity, you become accustomed to recognizing this pattern (which occurs
frequently in Xamarin.Android code), and you spend more time thinking about the business logic of your
application and less time wading through syntactical overhead.

Asynchronous programming
Asynchronous programming is a way to improve the overall responsiveness of your application. Asynchronous
programming features make it possible for the rest of your app code to continue running while some part of your
app is blocked by a lengthy operation. Accessing the web, processing images, and reading/writing files are
examples of operations that can cause an entire app to appear to freeze up if it is not written asynchronously.
C# includes language-level support for asynchronous programming via the async and await keywords. These
language features make it very easy to write code that performs long-running tasks without blocking the main
thread of your application. Briefly, you use the async keyword on a method to indicate that the code in the method
is to run asynchronously and not block the caller's thread. You use the await keyword when you call methods that
are marked with async . The compiler interprets the await as the point where your method execution is to be
moved to a background thread (a task is returned to the caller). When this task completes, execution of the code
resumes on the caller's thread at the await point in your code, returning the results of the async call. By
convention, methods that run asynchronously have Async suffixed to their names.
In Xamarin.Android applications, async and await are typically used to free up the UI thread so that it can
respond to user input (such as the tapping of a Cancel button) while a long-running operation takes place in a
background task.
In the following example, a button click event handler causes an asynchronous operation to download an image
from the web:

downloadButton.Click += downloadAsync;
...
async void downloadAsync(object sender, System.EventArgs e)
{
webClient = new WebClient ();
var url = new Uri ("http://photojournal.jpl.nasa.gov/jpeg/PIA15416.jpg");
byte[] bytes = null;

bytes = await webClient.DownloadDataTaskAsync(url);

// display the downloaded image ...

In this example, when the user clicks the downloadButton control, the downloadAsync event handler creates a
WebClient object and a Uri object to fetch an image from the specifed URL. Next, it calls the WebClient object's
DownloadDataTaskAsync method with this URL to retrieve the image.

Notice that the method declaration of downloadAsync is prefaced by the async keyword to indicate that it will run
asynchronously and return a task. Also note that the call to DownloadDataTaskAsync is preceded by the await
keyword. The app moves the execution of the event handler (starting at the point where await appears) to a
background thread until DownloadDataTaskAsync completes and returns. Meanwhile, the app's UI thread can still
respond to user input and fire event handlers for the other controls. When DownloadDataTaskAsync completes
(which may take several seconds), execution resumes where the bytes variable is set to the result of the call to
DownloadDataTaskAsync , and the remainder of the event handler code displays the downloaded image on the caller's
(UI) thread.
For an introduction to async / await in C#, see the Asynchronous Programming with Async and Await topic. For
more information about Xamarin support of asynchronous programming features, see Async Support Overview.

Keyword differences
Many language keywords used in Java are also used in C#. There are also a number of Java keywords that have an
equivalent but differently-named counterpart in C#, as listed in this table:

JAVA C# DESCRIPTION

boolean bool Used for declaring the boolean values


true and false.

extends : Precedes the class and interfaces to


inherit from.

implements : Precedes the class and interfaces to


inherit from.

import using Imports types from a namespace, also


used for creating a namespace alias.
JAVA C# DESCRIPTION

final sealed Prevents class derivation; prevents


methods and properties from being
overridden in derived classes.

instanceof is Evaluates whether an object is


compatible with a given type.

native extern Declares a method that is implemented


externally.

package namespace Declares a scope for a related set of


objects.

T... params T Specifies a method parameter that takes


a variable number of arguments.

super base Used to access members of the parent


class from within a derived class.

synchronized lock Wraps a critical section of code with lock


acquisition and release.

Also, there are many keywords that are unique to C# and have no counterpart in the Java used on Android.
Xamarin.Android code often makes use of the following C# keywords (this table is useful to refer to when you are
reading through Xamarin.Android sample code):

C# DESCRIPTION

as Performs conversions between compatible reference types or


nullable types.

async Specifies that a method or lambda expression is asynchronous.

await Suspends the execution of a method until a task completes.

byte Unsigned 8-bit integer type.

delegate Used to encapsulate a method or anonymous method.

enum Declares an enumeration, a set of named constants.

event Declares an event in a publisher class.

fixed Prevents a variable from being relocated.

get Defines an accessor method that retrieves the value of a


property.

in Enables a parameter to accept a less derived type in a generic


interface.

object An alias for the Object type in the .NET framework.


C# DESCRIPTION

out Parameter modifier or generic type parameter declaration.

override Extends or modifies the implementation of an inherited


member.

partial Declares a definition to be split into multiple files, or splits a


method definition from its implementation.

readonly Declares that a class member can be assigned only at


declaration time or by the class constructor.

ref Causes an argument to be passed by reference rather than by


value.

set Defines an accessor method that sets the value of a property.

string Alias for the String type in the .NET framework.

struct A value type that encapsulates a group of related variables.

typeof Obtains the type of an object.

var Declares an implicitly-typed local variable.

value References the value that client code wants to assign to a


property.

virtual Allows a method to be overridden in a derived class.

Interoperating with existing java code


If you have existing Java functionality that you do not want to convert to C#, you can reuse your existing Java
libraries in Xamarin.Android applications via two techniques:
Create a Java Bindings Library – Using this approach, you use Xamarin tools to generate C# wrappers
around Java types. These wrappers are called bindings. As a result, your Xamarin.Android application can
use your .jar file by calling into these wrappers.
Java Native Interface – The Java Native Interface (JNI) is a framework that makes it possible for C# apps
to call or be called by Java code.
For more information about these techniques, see Java Integration Overview.

Further reading
The MSDN C# Programming Guide is a great way to get started in learning the C# programming language, and
you can use the C# Reference to look up particular C# language features.
In the same way that Java knowledge is at least as much about familiarity with the Java class libraries as knowing
the Java language, practical knowledge of C# requires some familiarity with the .NET framework. Microsoft's
Moving to C# and the .NET Framework, for Java Developers learning packet is a good way to learn more about the
.NET framework from a Java perspective (while gaining a deeper understanding of C#).
When you are ready to tackle your first Xamarin.Android project in C#, our Hello, Android series can help you build
your first Xamarin.Android application and further advance your understanding of the fundamentals of Android
application development with Xamarin.

Summary
This article provided an introduction to the Xamarin.Android C# programming environment from a Java
developer's perspective. It pointed out the similarities between C# and Java while explaining their practical
differences. It introduced assemblies and namespaces, explained how to import external types, and provided an
overview of the differences in access modifiers, generics, class derivation, calling base-class methods, method
overriding, and event handling. It introduced C# features that are not available in Java, such as properties, async /
await asynchronous programming, lambdas, C# delegates, and the C# event handling system. It included tables
of important C# keywords, explained how to interoperate with existing Java libraries, and provided links to related
documentation for further study.

Related links
Java Integration Overview
C# Programming Guide
C# Reference
Moving to C# and the .NET Framework, for Java Developers
Xamarin for Objective-C Developers
2 minutes to read • Edit Online

Xamarin offers a path for developers targeting iOS to move their non-user interface code to platform agnostic C#
so that it can be used anywhere C# is available, including Android via Xamarin.Android and the various flavors of
Windows. However, just because you use C# with Xamarin doesn't mean you can't leverage existing skills and
Objective-C code. In fact, knowing Objective-C makes you a better Xamarin.iOS developer because Xamarin
exposes all the native iOS and OS X platform APIs you know and love, such as UIKit, Core Animation, Core
Foundation and Core Graphics to name a few. At the same time, you get the power of the C# language, including
features like LINQ and Generics, as well as rich .NET base class libraries to use in your native applications.
Additionally, Xamarin allows you to leverage existing Objective-C assets via a technology know as bindings. You
simply create a static library in Objective-C and expose it to C# via a binding, as illustrated in the following
diagram:

This doesn't need to be limited to non-UI code. Bindings can expose user interface code developed in Objective-C
as well.

Transitioning from Objective-C


You'll find a plethora of information on our documentation site to help ease the transition to Xamarin, showing
how to integrate C# code with what you already know. Some highlights to get you started include:
C# Primer for Objective-C Developers - A short primer for Objective-C developers looking to move to Xamarin
and the C# language.
Walkthrough: Binding an Objective-C Library - A step-by-step walkthrough for reusing existing Objective-C
code in a Xamarin.iOS application.

Binding Objective-C
Once you have a grasp of how C# compares to Objective-C and have worked through the binding walkthrough
above, you'll be in good shape for transitioning to the Xamarin platform. As a follow up, more detailed information
on Xamarin.iOS binding technologies, including a comprehensive binding reference is available in the Binding
Objective-C section.

Cross-Platform Development
Finally, after moving to Xamarin.iOS, you'll want to check out the cross-platform guidance we have, including case
studies of reference applications we have developed, along with best practices for creating reusable, cross-platform
code contained in the Building Cross-Platform Applications section.
Xamarin.Forms XAML Basics
2 minutes to read • Edit Online

Download the sample


The eXtensible Application Markup Language (XAML ) is an XML -based language created by Microsoft as an
alternative to programming code for instantiating and initializing objects, and organizing those objects in parent-
child hierarchies. XAML has been adapted to several technologies within the .NET framework, but it has found its
greatest utility in defining the layout of user interfaces within the Windows Presentation Foundation (WPF ),
Silverlight, the Windows Runtime, and the Universal Windows Platform (UWP ).
XAML allows developers to define user interfaces in Xamarin.Forms applications using markup rather than code.
XAML is never required in a Xamarin.Forms program, but it is often more succinct and more visually coherent
than equivalent code, and potentially toolable. XAML is well suited for use with the popular MVVM (Model-View -
ViewModel) application architecture: XAML defines the View that is linked to ViewModel code through XAML -
based data bindings.
Within a XAML file, the Xamarin.Forms developer can define user interfaces using all the Xamarin.Forms views,
layouts, and pages, as well as custom classes. The XAML file can be either compiled or embedded in the
executable. Either way, the XAML information is parsed at build time to locate named objects, and again at runtime
to instantiate and initialize objects, and to establish links between these objects and programming code.
XAML has several advantages over equivalent code:
XAML is often more succinct and readable than equivalent code.
The parent-child hierarchy inherent in XML allows XAML to mimic with greater visual clarity the parent-child
hierarchy of user-interface objects.
XAML can be easily hand-written by programmers, but also lends itself to be toolable and generated by visual
design tools.
There are also disadvantages, mostly related to limitations that are intrinsic to markup languages:
XAML cannot contain code. All event handlers must be defined in a code file.
XAML cannot contain loops for repetitive processing. (However, several Xamarin.Forms visual objects—most
notably ListView —can generate multiple children based on the objects in its ItemsSource collection.)
XAML cannot contain conditional processing (However, a data-binding can reference a code-based binding
converter that effectively allows some conditional processing.)
XAML generally cannot instantiate classes that do not define a parameterless constructor. (However, there is
sometimes a way around this restriction.)
XAML generally cannot call methods. (Again, this restriction can sometimes be overcome.)
There is not yet a visual designer for generating XAML in Xamarin.Forms applications. All XAML must be hand-
written, but there is a XAML Previewer. Programmers new to XAML might want to frequently build and run their
applications, particularly after anything that might not be correct. Even developers with lots of experience in XAML
know that experimentation is rewarding.
XAML is basically XML, but XAML has some unique syntax features. The most important are:
Property elements
Attached properties
Markup extensions
These features are not XML extensions. XAML is entirely legal XML. But these XAML syntax features use XML in
unique ways. They are discussed in detail in the articles below, which conclude with an introduction to using XAML
for implementing MVVM.

Requirements
This article assumes a working familiarity with Xamarin.Forms. This article also assumes some familiarity with
XML, including understanding the use of XML namespace declarations, and the terms element, tag, and attribute.
When you're familiar with Xamarin.Forms and XML, start reading Part 1. Getting Started with XAML.

Related links
XamlSamples
Creating Mobile Apps book
Xamarin.Forms Samples

Related video
Find more Xamarin videos on Channel 9 and YouTube.
Part 1. Getting Started with XAML
15 minutes to read • Edit Online

Download the sample


In a Xamarin.Forms application, XAML is mostly used to define the visual contents of a page and works together
with a C# code-behind file.
The code-behind file provides code support for the markup. Together, these two files contribute to a new class
definition that includes child views and property initialization. Within the XAML file, classes and properties are
referenced with XML elements and attributes, and links between the markup and code are established.

Creating the Solution


To begin editing your first XAML file, use Visual Studio or Visual Studio for Mac to create a new Xamarin.Forms
solution. (Select the tab below corresponding to your environment.)
Visual Studio
Visual Studio for Mac
In Windows, launch Visual Studio 2019, and in the start window click Create a new project to create a new
project:

In the Create a new project window, select Mobile in the Project type drop down, select the Mobile App
(Xamarin.Forms) template, and click the Next button:
In the Configure your new project window, set the Project name to XamlSamples (or whatever your prefer),
and click the Create button.
In the New Cross Platform App dialog, click Blank, and click the OK button:

Four projects are created in the solution: the XamlSamples .NET Standard library, XamlSamples.Android,
XamlSamples.iOS, and the Universal Windows Platform solution, XamlSamples.UWP.
After creating the XamlSamples solution, you might want to test your development environment by selecting the
various platform projects as the solution startup project, and building and deploying the simple application
created by the project template on either phone emulators or real devices.
Unless you need to write platform-specific code, the shared XamlSamples .NET Standard library project is where
you’ll be spending virtually all of your programming time. These articles will not venture outside of that project.
Anatomy of a XAML File
Within the XamlSamples .NET Standard library are a pair of files with the following names:
App.xaml, the XAML file; and
App.xaml.cs, a C# code-behind file associated with the XAML file.
You'll need to click the arrow next to App.xaml to see the code-behind file.
Both App.xaml and App.xaml.cs contribute to a class named App that derives from Application . Most other
classes with XAML files contribute to a class that derives from ContentPage ; those files use XAML to define the
visual contents of an entire page. This is true of the other two files in the XamlSamples project:
MainPage.xaml, the XAML file; and
MainPage.xaml.cs, the C# code-behind file.
The MainPage.xaml file looks like this (although the formatting might be a little different):

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.MainPage">

<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin Forms!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>

</ContentPage>

The two XML namespace ( xmlns ) declarations refer to URIs, the first seemingly on Xamarin’s web site and the
second on Microsoft’s. Don’t bother checking what those URIs point to. There’s nothing there. They are simply
URIs owned by Xamarin and Microsoft, and they basically function as version identifiers.
The first XML namespace declaration means that tags defined within the XAML file with no prefix refer to classes
in Xamarin.Forms, for example ContentPage . The second namespace declaration defines a prefix of x . This is
used for several elements and attributes that are intrinsic to XAML itself and which are supported by other
implementations of XAML. However, these elements and attributes are slightly different depending on the year
embedded in the URI. Xamarin.Forms supports the 2009 XAML specification, but not all of it.
The local namespace declaration allows you to access other classes from the .NET Standard library project.
At the end of that first tag, the x prefix is used for an attribute named Class . Because the use of this x prefix is
virtually universal for the XAML namespace, XAML attributes such as Class are almost always referred to as
x:Class .

The x:Class attribute specifies a fully qualified .NET class name: the MainPage class in the XamlSamples
namespace. This means that this XAML file defines a new class named MainPage in the XamlSamples namespace
that derives from ContentPage —the tag in which the x:Class attribute appears.
The x:Class attribute can only appear in the root element of a XAML file to define a derived C# class. This is the
only new class defined in the XAML file. Everything else that appears in the XAML file is instead simply
instantiated from existing classes and initialized.
The MainPage.xaml.cs file looks like this (aside from unused using directives):
using Xamarin.Forms;

namespace XamlSamples
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
}

The MainPage class derives from ContentPage , but notice the partial class definition. This suggests that there
should be another partial class definition for MainPage , but where is it? And what is that InitializeComponent
method?
When Visual Studio builds the project, it parses the XAML file to generate a C# code file. If you look in the
XamlSamples\XamlSamples\obj\Debug directory, you’ll find a file named
XamlSamples.MainPage.xaml.g.cs. The ‘g’ stands for generated. This is the other partial class definition of
MainPage that contains the definition of the InitializeComponent method called from the MainPage constructor.
These two partial MainPage class definitions can then be compiled together. Depending on whether the XAML is
compiled or not, either the XAML file or a binary form of the XAML file is embedded in the executable.
At runtime, code in the particular platform project calls a LoadApplication method, passing to it a new instance of
the App class in the .NET Standard library. The App class constructor instantiates MainPage . The constructor of
that class calls InitializeComponent , which then calls the LoadFromXaml method that extracts the XAML file (or its
compiled binary) from the .NET Standard library. LoadFromXaml initializes all the objects defined in the XAML file,
connects them all together in parent-child relationships, attaches event handlers defined in code to events set in
the XAML file, and sets the resultant tree of objects as the content of the page.
Although you normally don’t need to spend much time with generated code files, sometimes runtime exceptions
are raised on code in the generated files, so you should be familiar with them.
When you compile and run this program, the Label element appears in the center of the page as the XAML
suggests:

For more interesting visuals, all you need is more interesting XAML.
Adding New XAML Pages
Visual Studio
Visual Studio for Mac
To add other XAML -based ContentPage classes to your project, select the XamlSamples .NET Standard library
project, right-click, and select Add > New Item.... In the Add New Item dialog, select Visual C# Items >
Xamarin.Forms > Content Page (not Content Page (C#), which creates a code-only page, or Content View,
which is not a page). Give the page a name, for example, HelloXamlPage:

Two files are added to the project, HelloXamlPage.xaml and the code-behind file HelloXamlPage.xaml.cs.

Setting Page Content


Edit the HelloXamlPage.xaml file so that the only tags are those for ContentPage and ContentPage.Content :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.HelloXamlPage">
<ContentPage.Content>

</ContentPage.Content>
</ContentPage>

The ContentPage.Content tags are part of the unique syntax of XAML. At first, they might appear to be invalid
XML, but they are legal. The period is not a special character in XML.
The ContentPage.Content tags are called property element tags. Content is a property of ContentPage , and is
generally set to a single view or a layout with child views. Normally properties become attributes in XAML, but it
would be hard to set a Content attribute to a complex object. For that reason, the property is expressed as an
XML element consisting of the class name and the property name separated by a period. Now the Content
property can be set between the ContentPage.Content tags, like this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.HelloXamlPage"
Title="Hello XAML Page">
<ContentPage.Content>

<Label Text="Hello, XAML!"


VerticalOptions="Center"
HorizontalTextAlignment="Center"
Rotation="-15"
IsVisible="true"
FontSize="Large"
FontAttributes="Bold"
TextColor="Blue" />

</ContentPage.Content>
</ContentPage>

Also notice that a Title attribute has been set on the root tag.
At this time, the relationship between classes, properties, and XML should be evident: A Xamarin.Forms class
(such as ContentPage or Label ) appears in the XAML file as an XML element. Properties of that class—including
Title on ContentPage and seven properties of Label —usually appear as XML attributes.

Many shortcuts exist to set the values of these properties. Some properties are basic data types: For example, the
Title and Text properties are of type String , Rotation is of type Double , and IsVisible (which is true by
default and is set here only for illustration) is of type Boolean .
The HorizontalTextAlignment property is of type TextAlignment , which is an enumeration. For a property of any
enumeration type, all you need supply is a member name.
For properties of more complex types, however, converters are used for parsing the XAML. These are classes in
Xamarin.Forms that derive from TypeConverter . Many are public classes but some are not. For this particular
XAML file, several of these classes play a role behind the scenes:
LayoutOptionsConverter for the VerticalOptions property
FontSizeConverter for the FontSize property
ColorTypeConverter for the TextColor property

These converters govern the allowable syntax of the property settings.


The ThicknessTypeConverter can handle one, two, or four numbers separated by commas. If one number is
supplied, it applies to all four sides. With two numbers, the first is left and right padding, and the second is top and
bottom. Four numbers are in the order left, top, right, and bottom.
The LayoutOptionsConverter can convert the names of public static fields of the LayoutOptions structure to values
of type LayoutOptions .
The FontSizeConverter can handle a NamedSize member or a numeric font size.
The ColorTypeConverter accepts the names of public static fields of the Color structure or hexadecimal RGB
values, with or without an alpha channel, preceded by a number sign (#). Here’s the syntax without an alpha
channel:
TextColor="#rrggbb"

Each of the little letters is a hexadecimal digit. Here is how an alpha channel is included:
TextColor="#aarrggbb">
For the alpha channel, keep in mind that FF is fully opaque and 00 is fully transparent.
Two other formats allow you to specify only a single hexadecimal digit for each channel:
TextColor="#rgb" TextColor="#argb"

In these cases, the digit is repeated to form the value. For example, #CF3 is the RGB color CC -FF -33.

Page Navigation
When you run the XamlSamples program, the MainPage is displayed. To see the new HelloXamlPage you can
either set that as the new startup page in the App.xaml.cs file, or navigate to the new page from MainPage .
To implement navigation, first change code in the App.xaml.cs constructor so that a NavigationPage object is
created:

public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}

In the MainPage.xaml.cs constructor, you can create a simple Button and use the event handler to navigate to
HelloXamlPage :

public MainPage()
{
InitializeComponent();

Button button = new Button


{
Text = "Navigate!",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};

button.Clicked += async (sender, args) =>


{
await Navigation.PushAsync(new HelloXamlPage());
};

Content = button;
}

Setting the Content property of the page replaces the setting of the Content property in the XAML file. When
you compile and deploy the new version of this program, a button appears on the screen. Pressing it navigates to
HelloXamlPage . Here’s the resultant page on iPhone, Android, and UWP:
You can navigate back to MainPage using the < Back button on iOS, using the left arrow at the top of the page or
at the bottom of the phone on Android, or using the left arrow at the top of the page on Windows 10.
Feel free to experiment with the XAML for different ways to render the Label . If you need to embed any Unicode
characters into the text, you can use the standard XML syntax. For example, to put the greeting in smart quotes,
use:
<Label Text="&#x201C;Hello, XAML!&#x201D;" … />

Here’s what it looks like:

XAML and Code Interactions


The HelloXamlPage sample contains only a single Label on the page, but this is very unusual. Most
ContentPage derivatives set the Content property to a layout of some sort, such as a StackLayout . The Children
property of the StackLayout is defined to be of type IList<View> but it’s actually an object of type
ElementCollection<View> , and that collection can be populated with multiple views or other layouts. In XAML,
these parent-child relationships are established with normal XML hierarchy. Here’s a XAML file for a new page
named XamlPlusCodePage:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<StackLayout>
<Slider VerticalOptions="CenterAndExpand" />

<Label Text="A simple Label"


Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Button Text="Click Me!"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

This XAML file is syntactically complete, and here’s what it looks like:

However, you are likely to consider this program to be functionally deficient. Perhaps the Slider is supposed to
cause the Label to display the current value, and the Button is probably intended to do something within the
program.
As you’ll see in Part 4. Data Binding Basics, the job of displaying a Slider value using a Label can be handled
entirely in XAML with a data binding. But it is useful to see the code solution first. Even so, handling the Button
click definitely requires code. This means that the code-behind file for XamlPlusCodePage must contain handlers for
the ValueChanged event of the Slider and the Clicked event of the Button . Let’s add them:
namespace XamlSamples
{
public partial class XamlPlusCodePage
{
public XamlPlusCodePage()
{
InitializeComponent();
}

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)


{

void OnButtonClicked(object sender, EventArgs args)


{

}
}
}

These event handlers do not need to be public.


Back in the XAML file, the Slider and Button tags need to include attributes for the ValueChanged and Clicked
events that reference these handlers:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<StackLayout>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />

<Label Text="A simple Label"


Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Button Text="Click Me!"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout>
</ContentPage>

Notice that assigning a handler to an event has the same syntax as assigning a value to a property.
If the handler for the ValueChanged event of the Slider will be using the Label to display the current value, the
handler needs to reference that object from code. The Label needs a name, which is specified with the x:Name
attribute.

<Label x:Name="valueLabel"
Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

The x prefix of the x:Name attribute indicates that this attribute is intrinsic to XAML.
The name you assign to the x:Name attribute has the same rules as C# variable names. For example, it must begin
with a letter or underscore and contain no embedded spaces.
Now the ValueChanged event handler can set the Label to display the new Slider value. The new value is
available from the event arguments:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)


{
valueLabel.Text = args.NewValue.ToString("F3");
}

Or, the handler could obtain the Slider object that is generating this event from the sender argument and
obtain the Value property from that:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)


{
valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}

When you first run the program, the Label doesn’t display the Slider value because the ValueChanged event
hasn’t yet fired. But any manipulation of the Slider causes the value to be displayed:

Now for the Button . Let’s simulate a response to a Clicked event by displaying an alert with the Text of the
button. The event handler can safely cast the sender argument to a Button and then access its properties:

async void OnButtonClicked(object sender, EventArgs args)


{
Button button = (Button)sender;
await DisplayAlert("Clicked!",
"The button labeled '" + button.Text + "' has been clicked",
"OK");
}

The method is defined as async because the DisplayAlert method is asynchronous and should be prefaced with
the await operator, which returns when the method completes. Because this method obtains the Button firing
the event from the sender argument, the same handler could be used for multiple buttons.
You’ve seen that an object defined in XAML can fire an event that is handled in the code-behind file, and that the
code-behind file can access an object defined in XAML using the name assigned to it with the x:Name attribute.
These are the two fundamental ways that code and XAML interact.
Some additional insights into how XAML works can be gleaned by examining the newly generated
XamlPlusCode.xaml.g.cs file, which now includes any name assigned to any x:Name attribute as a private field.
Here's a simplified version of that file:

public partial class XamlPlusCodePage : ContentPage {

private Label valueLabel;

private void InitializeComponent() {


this.LoadFromXaml(typeof(XamlPlusCodePage));
valueLabel = this.FindByName<Label>("valueLabel");
}
}

The declaration of this field allows the variable to be freely used anywhere within the XamlPlusCodePage partial
class file under your jurisdiction. At runtime, the field is assigned after the XAML has been parsed. This means that
the valueLabel field is null when the XamlPlusCodePage constructor begins but valid after InitializeComponent
is called.
After InitializeComponent returns control back to the constructor, the visuals of the page have been constructed
just as if they had been instantiated and initialized in code. The XAML file no longer plays any role in the class. You
can manipulate these objects on the page in any way that you want, for example, by adding views to the
StackLayout , or setting the Content property of the page to something else entirely. You can “walk the tree” by
examining the Content property of the page and the items in the Children collections of layouts. You can set
properties on views accessed in this way, or assign event handlers to them dynamically.
Feel free. It’s your page, and XAML is only a tool to build its content.

Summary
With this introduction, you’ve seen how a XAML file and code file contribute to a class definition, and how the
XAML and code files interact. But XAML also has its own unique syntactical features that allow it to be used in a
very flexible manner. You can begin exploring these in Part 2. Essential XAML Syntax.

Related Links
XamlSamples
Part 2. Essential XAML Syntax
Part 3. XAML Markup Extensions
Part 4. Data Binding Basics
Part 5. From Data Binding to MVVM
Part 2. Essential XAML Syntax
10 minutes to read • Edit Online

Download the sample


XAML is mostly designed for instantiating and initializing objects. But often, properties must be set to complex
objects that cannot easily be represented as XML strings, and sometimes properties defined by one class must be
set on a child class. These two needs require the essential XAML syntax features of property elements and attached
properties.

Property Elements
In XAML, properties of classes are normally set as XML attributes:

<Label Text="Hello, XAML!"


VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large"
TextColor="Aqua" />

However, there is an alternative way to set a property in XAML. To try this alternative with TextColor , first delete
the existing TextColor setting:

<Label Text="Hello, XAML!"


VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large" />

Open up the empty-element Label tag by separating it into start and end tags:

<Label Text="Hello, XAML!"


VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">

</Label>

Within these tags, add start and end tags that consist of the class name and a property name separated by a
period:

<Label Text="Hello, XAML!"


VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>

</Label.TextColor>
</Label>

Set the property value as content of these new tags, like this:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>

These two ways to specify the TextColor property are functionally equivalent, but don't use the two ways for the
same property because that would effectively be setting the property twice, and might be ambiguous.
With this new syntax, some handy terminology can be introduced:
Label is an object element. It is a Xamarin.Forms object expressed as an XML element.
Text , VerticalOptions , FontAttributes and FontSize are property attributes. They are Xamarin.Forms
properties expressed as XML attributes.
In that final snippet, TextColor has become a property element. It is a Xamarin.Forms property but it is now an
XML element.
The definition of property elements might at first seem to be a violation of XML syntax, but it’s not. The period has
no special meaning in XML. To an XML decoder, Label.TextColor is simply a normal child element.
In XAML, however, this syntax is very special. One of the rules for property elements is that nothing else can
appear in the Label.TextColor tag. The value of the property is always defined as content between the property-
element start and end tags.
You can use property-element syntax on more than one property:

<Label Text="Hello, XAML!"


VerticalOptions="Center">
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>

Or you can use property-element syntax for all the properties:


<Label>
<Label.Text>
Hello, XAML!
</Label.Text>
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
<Label.VerticalOptions>
Center
</Label.VerticalOptions>
</Label>

At first, property-element syntax might seem like an unnecessary long-winded replacement for something
comparatively quite simple, and in these examples that is certainly the case.
However, property-element syntax becomes essential when the value of a property is too complex to be expressed
as a simple string. Within the property-element tags you can instantiate another object and set its properties. For
example, you can explicitly set a property such as VerticalOptions to a LayoutOptions value with property
settings:

<Label>
...
<Label.VerticalOptions>
<LayoutOptions Alignment="Center" />
</Label.VerticalOptions>
</Label>

Another example: The Grid has two properties named RowDefinitions and ColumnDefinitions . These two
properties are of type RowDefinitionCollection and ColumnDefinitionCollection , which are collections of
RowDefinition and ColumnDefinition objects. You need to use property element syntax to set these collections.

Here’s the beginning of the XAML file for a GridDemoPage class, showing the property element tags for the
RowDefinitions and ColumnDefinitions collections:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">
<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>
...
</Grid>
</ContentPage>

Notice the abbreviated syntax for defining auto-sized cells, cells of pixel widths and heights, and star settings.
Attached Properties
You've just seen that the Grid requires property elements for the RowDefinitions and ColumnDefinitions
collections to define the rows and columns. However, there must also be some way for the programmer to
indicate the row and column where each child of the Grid resides.
Within the tag for each child of the Grid you specify the row and column of that child using the following
attributes:
Grid.Row
Grid.Column

The default values of these attributes are 0. You can also indicate if a child spans more than one row or column
with these attributes:
Grid.RowSpan
Grid.ColumnSpan

These two attributes have default values of 1.


Here’s the complete GridDemoPage.xaml file:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">

<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>

<Label Text="Autosized cell"


Grid.Row="0" Grid.Column="0"
TextColor="White"
BackgroundColor="Blue" />

<BoxView Color="Silver"
HeightRequest="0"
Grid.Row="0" Grid.Column="1" />

<BoxView Color="Teal"
Grid.Row="1" Grid.Column="0" />

<Label Text="Leftover space"


Grid.Row="1" Grid.Column="1"
TextColor="Purple"
BackgroundColor="Aqua"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />

<Label Text="Span two rows (or more if you want)"


Grid.Row="0" Grid.Column="2" Grid.RowSpan="2"
TextColor="Yellow"
BackgroundColor="Blue"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />

<Label Text="Span two columns"


Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
TextColor="Blue"
BackgroundColor="Yellow"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />

<Label Text="Fixed 100x100"


Grid.Row="2" Grid.Column="2"
TextColor="Aqua"
BackgroundColor="Red"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />

</Grid>
</ContentPage>

The Grid.Row and Grid.Column settings of 0 are not required but are generally included for purposes of clarity.
Here’s what it looks like:
Judging solely from the syntax, these Grid.Row , Grid.Column , Grid.RowSpan , and Grid.ColumnSpan attributes
appear to be static fields or properties of Grid , but interestingly enough, Grid does not define anything named
Row , Column , RowSpan , or ColumnSpan .

Instead, Griddefines four bindable properties named RowProperty , ColumnProperty , RowSpanProperty , and
ColumnSpanProperty . These are special types of bindable properties known as attached properties. They are
defined by the Grid class but set on children of the Grid .
When you wish to use these attached properties in code, the Grid class provides static methods named SetRow ,
GetColumn , and so forth. But in XAML, these attached properties are set as attributes in the children of the Grid
using simple properties names.
Attached properties are always recognizable in XAML files as attributes containing both a class and a property
name separated by a period. They are called attached properties because they are defined by one class (in this
case, Grid ) but attached to other objects (in this case, children of the Grid ). During layout, the Grid can
interrogate the values of these attached properties to know where to place each child.
The AbsoluteLayout class defines two attached properties named LayoutBounds and LayoutFlags . Here’s a
checkerboard pattern realized using the proportional positioning and sizing features of AbsoluteLayout :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.AbsoluteDemoPage"
Title="Absolute Demo Page">

<AbsoluteLayout BackgroundColor="#FF8080">
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

</AbsoluteLayout>
</ContentPage>

And here it is:


For something like this, you might question the wisdom of using XAML. Certainly, the repetition and regularity of
the LayoutBounds rectangle suggests that it might be better realized in code.
That’s certainly a legitimate concern, and there’s no problem with balancing the use of code and markup when
defining your user interfaces. It’s easy to define some of the visuals in XAML and then use the constructor of the
code-behind file to add some more visuals that might be better generated in loops.

Content Properties
In the previous examples, the StackLayout , Grid , and AbsoluteLayout objects are set to the Content property of
the ContentPage , and the children of these layouts are actually items in the Children collection. Yet these Content
and Children properties are nowhere in the XAML file.
You can certainly include the Content and Children properties as property elements, such as in the
XamlPlusCode sample:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<ContentPage.Content>
<StackLayout>
<StackLayout.Children>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />

<Label x:Name="valueLabel"
Text="A simple Label"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Button Text="Click Me!"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout.Children>
</StackLayout>
</ContentPage.Content>
</ContentPage>

The real question is: Why are these property elements not required in the XAML file?
Elements defined in Xamarin.Forms for use in XAML are allowed to have one property flagged in the
ContentProperty attribute on the class. If you look up the ContentPage class in the online Xamarin.Forms
documentation, you’ll see this attribute:

[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage

This means that the Content property-element tags are not required. Any XML content that appears between the
start and end ContentPage tags is assumed to be assigned to the Content property.
StackLayout , Grid , AbsoluteLayout , and RelativeLayout all derive from Layout<View> , and if you look up
Layout<T> in the Xamarin.Forms documentation, you’ll see another ContentProperty attribute:

[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...

That allows content of the layout to be automatically added to the Children collection without explicit Children
property-element tags.
Other classes also have ContentProperty attribute definitions. For example, the content property of Label is
Text . Check the API documentation for others.

Platform Differences with OnPlatform


In single page applications, it is common to set the Padding property on the page to avoid overwriting the iOS
status bar. In code, you can use the Device.RuntimePlatform property for this purpose:
if (Device.RuntimePlatform == Device.iOS)
{
Padding = new Thickness(0, 20, 0, 0);
}

You can also do something similar in XAML using the OnPlatform and On classes. First include property
elements for the Padding property near the top of the page:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>

</ContentPage.Padding>
...
</ContentPage>

Within these tags, include an OnPlatform tag. OnPlatform is a generic class. You need to specify the generic type
argument, in this case, Thickness , which is the type of Padding property. Fortunately, there’s a XAML attribute
specifically to define generic arguments called x:TypeArguments . This should match the type of the property you're
setting:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">

</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

OnPlatform has a property named Platforms that is an IList of On objects. Use property element tags for that
property:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>

</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

Now add On elements. For each one set the Platform property and the Value property to markup for the
Thickness property:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

This markup can be simplified. The content property of OnPlatform is Platforms , so those property-element tags
can be removed:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

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

The Platform property of On is of type IList<string> , so you can include multiple platforms if the values are the
same:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

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

Because Android and UWP are set to the default value of Padding , that tag can be removed:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

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

This is the standard way to set a platform-dependent Padding property in XAML. If the Value setting cannot be
represented by a single string, you can define property elements for it:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

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

NOTE
The OnPlatform markup extension can also be used in XAML to customize UI appearance on a per-platform basis. It
provides the same functionality as the OnPlatform and On classes, but with a more concise representation. For more
information, see OnPlatform Markup Extension.

Summary
With property elements and attached properties, much of the basic XAML syntax has been established. However,
sometimes you need to set properties to objects in an indirect manner, for example, from a resource dictionary.
This approach is covered in the next part, Part 3. XAML Markup Extensions.

Related Links
XamlSamples
Part 1. Getting Started with XAML
Part 3. XAML Markup Extensions
Part 4. Data Binding Basics
Part 5. From Data Binding to MVVM
Part 3. XAML Markup Extensions
11 minutes to read • Edit Online

Download the sample


XAML markup extensions constitute an important feature in XAML that allow properties to be set to objects or
values that are referenced indirectly from other sources. XAML markup extensions are particularly important for
sharing objects, and referencing constants used throughout an application, but they find their greatest utility in
data bindings.

XAML Markup Extensions


In general, you use XAML to set properties of an object to explicit values, such as a string, a number, an
enumeration member, or a string that is converted to a value behind the scenes.
Sometimes, however, properties must instead reference values defined somewhere else, or which might require a
little processing by code at runtime. For these purposes, XAML markup extensions are available.
These XAML markup extensions are not extensions of XML. XAML is entirely legal XML. They’re called
“extensions” because they are backed by code in classes that implement IMarkupExtension . You can write your
own custom markup extensions.
In many cases, XAML markup extensions are instantly recognizable in XAML files because they appear as
attribute settings delimited by curly braces: { and }, but sometimes markup extensions appear in markup as
conventional elements.

Shared Resources
Some XAML pages contain several views with properties set to the same values. For example, many of the
property settings for these Button objects are the same:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<StackLayout>
<Button Text="Do this!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />

<Button Text="Do that!"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />

<Button Text="Do the other thing!"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />

</StackLayout>
</ContentPage>

If one of these properties needs to be changed, you might prefer to make the change just once rather than three
times. If this were code, you’d likely be using constants and static read-only objects to help keep such values
consistent and easy to modify.
In XAML, one popular solution is to store such values or objects in a resource dictionary. The VisualElement
class defines a property named Resources of type ResourceDictionary , which is a dictionary with keys of type
string and values of type object . You can put objects into this dictionary and then reference them from
markup, all in XAML.
To use a resource dictionary on a page, include a pair of Resources property-element tags. It’s most convenient
to put these at the top of the page:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<ContentPage.Resources>

</ContentPage.Resources>
...
</ContentPage>

It’s also necessary to explicitly include ResourceDictionary tags:


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<ContentPage.Resources>
<ResourceDictionary>

</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

Now objects and values of various types can be added to the resource dictionary. These types must be
instantiable. They can’t be abstract classes, for example. These types must also have a public parameterless
constructor. Each item requires a dictionary key specified with the x:Key attribute. For example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />

<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

These two items are values of the structure type LayoutOptions , and each has a unique key and one or two
properties set. In code and markup, it’s much more common to use the static fields of LayoutOptions , but here
it’s more convenient to set the properties.
Now it’s necessary to set the HorizontalOptions and VerticalOptions properties of these buttons to these
resources, and that’s done with the StaticResource XAML markup extension:

<Button Text="Do this!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />

The StaticResource markup extension is always delimited with curly braces, and includes the dictionary key.
The name StaticResource distinguishes it from DynamicResource , which Xamarin.Forms also supports.
DynamicResource is for dictionary keys associated with values that might change during runtime, while
StaticResource accesses elements from the dictionary just once when the elements on the page are constructed.
For the BorderWidth property, it’s necessary to store a double in the dictionary. XAML conveniently defines tags
for common data types like x:Double and x:Int32 :
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />

<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />

<x:Double x:Key="borderWidth">
3
</x:Double>
</ResourceDictionary>
</ContentPage.Resources>

You don’t need to put it on three lines. This dictionary entry for this rotation angle only takes up one line:

<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />

<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />

<x:Double x:Key="borderWidth">
3
</x:Double>

<x:Double x:Key="rotationAngle">-15</x:Double>
</ResourceDictionary>
</ContentPage.Resources>

Those two resources can be referenced in the same way as the LayoutOptions values:

<Button Text="Do this!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="Red"
FontSize="24" />

For resources of type Color , you can use the same string representations that you use when directly assigning
attributes of these types. The type converters are invoked when the resource is created. Here's a resource of type
Color :

<Color x:Key="textColor">Red</Color>

Often, programs set a FontSize property to a member of the NamedSize enumeration such as Large . The
FontSizeConverter class works behind the scenes to convert it into a platform -dependent value using the
Device.GetNamedSized method. However, when defining a font-size resource, it makes more sense to use a
numeric value, shown here as an x:Double type:

<x:Double x:Key="fontSize">24</x:Double>
Now all the properties except Text are defined by resource settings:

<Button Text="Do this!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />

It's also possible to use OnPlatform within the resource dictionary to define different values for the platforms.
Here’s how an OnPlatform object can be part of the resource dictionary for different text colors:

<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>

Notice that gets both an x:Key attribute because it’s an object in the dictionary and an
OnPlatform
x:TypeArguments attribute because it’s a generic class. The iOS , Android , and UWP attributes are converted to
Color values when the object is initialized.

Here’s the final complete XAML file with three buttons accessing six shared values:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />

<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />

<x:Double x:Key="borderWidth">3</x:Double>

<x:Double x:Key="rotationAngle">-15</x:Double>

<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>

<x:Double x:Key="fontSize">24</x:Double>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />

<Button Text="Do that!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />

<Button Text="Do the other thing!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />

</StackLayout>
</ContentPage>

The screenshots verify the consistent styling, and the platform-dependent styling:
Although it is most common to define the Resources collection at the top of the page, keep in mind that the
Resources property is defined by VisualElement , and you can have Resources collections on other elements on
the page. For example, try adding one to the StackLayout in this example:

<StackLayout>
<StackLayout.Resources>
<ResourceDictionary>
<Color x:Key="textColor">Blue</Color>
</ResourceDictionary>
</StackLayout.Resources>
...
</StackLayout>

You’ll discover that the text color of the buttons is now blue. Basically, whenever the XAML parser encounters a
StaticResource markup extension, it searches up the visual tree and uses the first ResourceDictionary it
encounters containing that key.
One of the most common types of objects stored in resource dictionaries is the Xamarin.Forms Style , which
defines a collection of property settings. Styles are discussed in the article Styles.
Sometimes developers new to XAML wonder if they can put a visual element such as Label or Button in a
ResourceDictionary . While it’s surely possible, it doesn’t make much sense. The purpose of the
ResourceDictionary is to share objects. A visual element cannot be shared. The same instance cannot appear
twice on a single page.

The x:Static Markup Extension


Despite the similarities of their names, x:Static and StaticResource are very different. StaticResource returns
an object from a resource dictionary while x:Static accesses one of the following:
a public static field
a public static property
a public constant field
an enumeration member.
The StaticResource markup extension is supported by XAML implementations that define a resource dictionary,
while x:Static is an intrinsic part of XAML, as the x prefix reveals.
Here are a few examples that demonstrate how x:Static can explicitly reference static fields and enumeration
members:

<Label Text="Hello, XAML!"


VerticalOptions="{x:Static LayoutOptions.Start}"
HorizontalTextAlignment="{x:Static TextAlignment.Center}"
TextColor="{x:Static Color.Aqua}" />

So far, this is not very impressive. But the x:Static markup extension can also reference static fields or
properties from your own code. For example, here’s an AppConstants class that contains some static fields that
you might want to use on multiple pages throughout an application:

using System;
using Xamarin.Forms;

namespace XamlSamples
{
static class AppConstants
{
public static readonly Thickness PagePadding;

public static readonly Font TitleFont;

public static readonly Color BackgroundColor = Color.Aqua;

public static readonly Color ForegroundColor = Color.Brown;

static AppConstants()
{
switch (Device.RuntimePlatform)
{
case Device.iOS:
PagePadding = new Thickness(5, 20, 5, 0);
TitleFont = Font.SystemFontOfSize(35, FontAttributes.Bold);
break;

case Device.Android:
PagePadding = new Thickness(5, 0, 5, 0);
TitleFont = Font.SystemFontOfSize(40, FontAttributes.Bold);
break;

case Device.UWP:
PagePadding = new Thickness(5, 0, 5, 0);
TitleFont = Font.SystemFontOfSize(50, FontAttributes.Bold);
break;
}
}
}
}

To reference the static fields of this class in the XAML file, you’ll need some way to indicate within the XAML file
where this file is located. You do this with an XML namespace declaration.
Recall that the XAML files created as part of the standard Xamarin.Forms XAML template contain two XML
namespace declarations: one for accessing Xamarin.Forms classes and another for referencing tags and
attributes intrinsic to XAML:

xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

You’ll need additional XML namespace declarations to access other classes. Each additional XML namespace
declaration defines a new prefix. To access classes local to the shared application .NET Standard library, such as
AppConstants , XAML programmers often use the prefix local . The namespace declaration must indicate the
CLR (Common Language Runtime) namespace name, also known as the .NET namespace name, which is the
name that appears in a C# namespace definition or in a using directive:

xmlns:local="clr-namespace:XamlSamples"

You can also define XML namespace declarations for .NET namespaces in any assembly that the .NET Standard
library references. For example, here’s a sys prefix for the standard .NET System namespace, which is in the
mscorlib assembly, which once stood for "Microsoft Common Object Runtime Library," but now means
"Multilanguage Standard Common Object Runtime Library." Because this is another assembly, you must also
specify the assembly name, in this case mscorlib:

xmlns:sys="clr-namespace:System;assembly=mscorlib"

Notice that the keyword clr-namespace is followed by a colon and then the .NET namespace name, followed by a
semicolon, the keyword assembly , an equal sign, and the assembly name.

Yes, a colon follows clr-namespace but equal sign follows assembly . The syntax was defined in this way
deliberately: Most XML namespace declarations reference a URI that begins a URI scheme name such as http ,
which is always followed by a colon. The clr-namespace part of this string is intended to mimic that convention.
Both these namespace declarations are included in the StaticConstantsPage sample. Notice that the BoxView
dimensions are set to Math.PI and Math.E , but scaled by a factor of 100:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="XamlSamples.StaticConstantsPage"
Title="Static Constants Page"
Padding="{x:Static local:AppConstants.PagePadding}">

<StackLayout>
<Label Text="Hello, XAML!"
TextColor="{x:Static local:AppConstants.BackgroundColor}"
BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
Font="{x:Static local:AppConstants.TitleFont}"
HorizontalOptions="Center" />

<BoxView WidthRequest="{x:Static sys:Math.PI}"


HeightRequest="{x:Static sys:Math.E}"
Color="{x:Static local:AppConstants.ForegroundColor}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="100" />
</StackLayout>
</ContentPage>

The size of the resultant BoxView relative to the screen is platform-dependent:


Other Standard Markup Extensions
Several markup extensions are intrinsic to XAML and supported in Xamarin.Forms XAML files. Some of these
are not used very often but are essential when you need them:
If a property has a non- null value by default but you want to set it to null , set it to the {x:Null} markup
extension.
If a property is of type Type , you can assign it to a Type object using the markup extension
{x:Type someClass} .
You can define arrays in XAML using the x:Array markup extension. This markup extension has a required
attribute named Type that indicates the type of the elements in the array.
The Binding markup extension is discussed in Part 4. Data Binding Basics.
The RelativeSource markup extension is discussed in Relative Bindings.

The ConstraintExpression Markup Extension


Markup extensions can have properties, but they are not set like XML attributes. In a markup extension, property
settings are separated by commas, and no quotation marks appear within the curly braces.
This can be illustrated with the Xamarin.Forms markup extension named ConstraintExpression , which is used
with the RelativeLayout class. You can specify the location or size of a child view as a constant, or relative to a
parent or other named view. The syntax of the ConstraintExpression allows you set the position or size of a view
using a Factor times a property of another view, plus a Constant . Anything more complex than that requires
code.
Here’s an example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.RelativeLayoutPage"
Title="RelativeLayout Page">

<RelativeLayout>

<!-- Upper left -->


<BoxView Color="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}" />
<!-- Upper right -->
<BoxView Color="Green"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=-40}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}" />
<!-- Lower left -->
<BoxView Color="Blue"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=-40}" />
<!-- Lower right -->
<BoxView Color="Yellow"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=-40}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=-40}" />

<!-- Centered and 1/3 width and height of parent -->


<BoxView x:Name="oneThird"
Color="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.33}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.33}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}" />

<!-- 1/3 width and height of previous -->


<BoxView Color="Blue"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=X}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Y}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Width,
Factor=0.33}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Height,
Factor=0.33}" />
</RelativeLayout>
</ContentPage>

Perhaps the most important lesson you should take from this sample is the syntax of the markup extension: No
quotation marks must appear within the curly braces of a markup extension. When typing the markup extension
in a XAML file, it is natural to want to enclose the values of the properties in quotation marks. Resist the
temptation!
Here’s the program running:

Summary
The XAML markup extensions shown here provide important support for XAML files. But perhaps the most
valuable XAML markup extension is Binding , which is covered in the next part of this series, Part 4. Data Binding
Basics.

Related Links
XamlSamples
Part 1. Getting Started with XAML
Part 2. Essential XAML Syntax
Part 4. Data Binding Basics
Part 5. From Data Binding to MVVM
Part 4. Data Binding Basics
11 minutes to read • Edit Online

Download the sample


Data bindings allow properties of two objects to be linked so that a change in one causes a change in the other.
This is a very valuable tool, and while data bindings can be defined entirely in code, XAML provides shortcuts
and convenience. Consequently, one of the most important markup extensions in Xamarin.Forms is Binding.

Data Bindings
Data bindings connect properties of two objects, called the source and the target. In code, two steps are required:
The BindingContext property of the target object must be set to the source object, and the SetBinding method
(often used in conjunction with the Binding class) must be called on the target object to bind a property of that
object to a property of the source object.
The target property must be a bindable property, which means that the target object must derive from
BindableObject . The online Xamarin.Forms documentation indicates which properties are bindable properties. A
property of Label such as Text is associated with the bindable property TextProperty .
In markup, you must also perform the same two steps that are required in code, except that the Binding markup
extension takes the place of the SetBinding call and the Binding class.
However, when you define data bindings in XAML, there are multiple ways to set the BindingContext of the
target object. Sometimes it’s set from the code-behind file, sometimes using a StaticResource or x:Static
markup extension, and sometimes as the content of BindingContext property-element tags.
Bindings are used most often to connect the visuals of a program with an underlying data model, usually in a
realization of the MVVM (Model-View -ViewModel) application architecture, as discussed in Part 5. From Data
Bindings to MVVM, but other scenarios are possible.

View-to-View Bindings
You can define data bindings to link properties of two views on the same page. In this case, you set the
BindingContext of the target object using the x:Reference markup extension.

Here’s a XAML file that contains a Slider and two Label views, one of which is rotated by the Slider value
and another which displays the Slider value:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SliderBindingsPage"
Title="Slider Bindings Page">

<StackLayout>
<Label Text="ROTATION"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />

<Label BindingContext="{x:Reference slider}"


Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

The Slider contains an x:Name attribute that is referenced by the two Label views using the x:Reference
markup extension.
The x:Reference binding extension defines a property named Name to set to the name of the referenced
element, in this case slider . However, the ReferenceExtension class that defines the x:Reference markup
extension also defines a ContentProperty attribute for Name , which means that it isn’t explicitly required. Just for
variety, the first x:Reference includes “Name=” but the second does not:

BindingContext="{x:Reference Name=slider}"

BindingContext="{x:Reference slider}"

The Binding markup extension itself can have several properties, just like the BindingBase and Binding class.
The ContentProperty for Binding is Path , but the “Path=” part of the markup extension can be omitted if the
path is the first item in the Binding markup extension. The first example has “Path=” but the second example
omits it:

Rotation="{Binding Path=Value}"

Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"

The properties can all be on one line or separated into multiple lines:

Text="{Binding Value,
StringFormat='The angle is {0:F0} degrees'}"

Do whatever is convenient.
Notice the StringFormat property in the second Binding markup extension. In Xamarin.Forms, bindings do not
perform any implicit type conversions, and if you need to display a non-string object as a string you must
provide a type converter or use StringFormat . Behind the scenes, the static String.Format method is used to
implement StringFormat . That’s potentially a problem, because .NET formatting specifications involve curly
braces, which are also used to delimit markup extensions. This creates a risk of confusing the XAML parser. To
avoid that, put the entire formatting string in single quotation marks:

Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"

Here’s the running program:

The Binding Mode


A single view can have data bindings on several of its properties. However, each view can have only one
BindingContext , so multiple data bindings on that view must all reference properties of the same object.

The solution to this and other problems involves the Mode property, which is set to a member of the
BindingMode enumeration:

Default
OneWay — values are transferred from the source to the target
OneWayToSource — values are transferred from the target to the source
TwoWay — values are transferred both ways between source and target
OneTime — data goes from source to target, but only when the BindingContext changes

The following program demonstrates one common use of the OneWayToSource and TwoWay binding modes. Four
Slider views are intended to control the Scale , Rotate , RotateX , and RotateY properties of a Label . At first,
it seems as if these four properties of the Label should be data-binding targets because each is being set by a
Slider . However, the BindingContext of Label can be only one object, and there are four different sliders.

For that reason, all the bindings are set in seemingly backwards ways: The BindingContext of each of the four
sliders is set to the Label , and the bindings are set on the Value properties of the sliders. By using the
OneWayToSource and TwoWay modes, these Value properties can set the source properties, which are the Scale ,
Rotate , RotateX , and RotateY properties of the Label :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SliderTransformsPage"
Padding="5"
Title="Slider Transforms Page">
Title="Slider Transforms Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<!-- Scaled and rotated Label -->


<Label x:Name="label"
Text="TEXT"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<!-- Slider and identifying Label for Scale -->


<Slider x:Name="scaleSlider"
BindingContext="{x:Reference label}"
Grid.Row="1" Grid.Column="0"
Maximum="10"
Value="{Binding Scale, Mode=TwoWay}" />

<Label BindingContext="{x:Reference scaleSlider}"


Text="{Binding Value, StringFormat='Scale = {0:F1}'}"
Grid.Row="1" Grid.Column="1"
VerticalTextAlignment="Center" />

<!-- Slider and identifying Label for Rotation -->


<Slider x:Name="rotationSlider"
BindingContext="{x:Reference label}"
Grid.Row="2" Grid.Column="0"
Maximum="360"
Value="{Binding Rotation, Mode=OneWayToSource}" />

<Label BindingContext="{x:Reference rotationSlider}"


Text="{Binding Value, StringFormat='Rotation = {0:F0}'}"
Grid.Row="2" Grid.Column="1"
VerticalTextAlignment="Center" />

<!-- Slider and identifying Label for RotationX -->


<Slider x:Name="rotationXSlider"
BindingContext="{x:Reference label}"
Grid.Row="3" Grid.Column="0"
Maximum="360"
Value="{Binding RotationX, Mode=OneWayToSource}" />

<Label BindingContext="{x:Reference rotationXSlider}"


Text="{Binding Value, StringFormat='RotationX = {0:F0}'}"
Grid.Row="3" Grid.Column="1"
VerticalTextAlignment="Center" />

<!-- Slider and identifying Label for RotationY -->


<Slider x:Name="rotationYSlider"
BindingContext="{x:Reference label}"
Grid.Row="4" Grid.Column="0"
Maximum="360"
Value="{Binding RotationY, Mode=OneWayToSource}" />

<Label BindingContext="{x:Reference rotationYSlider}"


Text="{Binding Value, StringFormat='RotationY = {0:F0}'}"
Grid.Row="4" Grid.Column="1"
VerticalTextAlignment="Center" />
</Grid>
</ContentPage>

The bindings on three of the Slider views are OneWayToSource , meaning that the Slider value causes a change
in the property of its BindingContext , which is the Label named label . These three Slider views cause
changes to the Rotate , RotateX , and RotateY properties of the Label .
However, the binding for the Scale property is TwoWay . This is because the Scale property has a default value
of 1, and using a TwoWay binding causes the Slider initial value to be set at 1 rather than 0. If that binding were
OneWayToSource , the Scale property would initially be set to 0 from the Slider default value. The Label would
not be visible, and that might cause some confusion to the user.

NOTE
The VisualElement class also has ScaleX and ScaleY properties, which scale the VisualElement on the x-axis and
y-axis respectively.

Bindings and Collections


Nothing illustrates the power of XAML and data bindings better than a templated ListView .
ListView defines an ItemsSource property of type IEnumerable , and it displays the items in that collection.
These items can be objects of any type. By default, ListView uses the ToString method of each item to display
that item. Sometimes this is just what you want, but in many cases, ToString returns only the fully-qualified
class name of the object.
However, the items in the ListView collection can be displayed any way you want through the use of a template,
which involves a class that derives from Cell . The template is cloned for every item in the ListView , and data
bindings that have been set on the template are transferred to the individual clones.
Very often, you’ll want to create a custom cell for these items using the ViewCell class. This process is
somewhat messy in code, but in XAML it becomes very straightforward.
Included in the XamlSamples project is a class called NamedColor . Each NamedColor object has Name and
FriendlyName properties of type string , and a Color property of type Color . In addition, NamedColor has 141
static read-only fields of type Color corresponding to the colors defined in the Xamarin.Forms Color class. A
static constructor creates an IEnumerable<NamedColor> collection that contains NamedColor objects corresponding
to these static fields, and assigns it to its public static All property.
Setting the static NamedColor.All property to the ItemsSource of a ListView is easy using the x:Static
markup extension:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.ListViewDemoPage"
Title="ListView Demo Page">

<ListView ItemsSource="{x:Static local:NamedColor.All}" />

</ContentPage>

The resultant display establishes that the items are truly of type XamlSamples.NamedColor :

It’s not much information, but the ListView is scrollable and selectable.
To define a template for the items, you’ll want to break out the ItemTemplate property as a property element,
and set it to a DataTemplate , which then references a ViewCell . To the View property of the ViewCell you can
define a layout of one or more views to display each item. Here’s a simple example:

<ListView ItemsSource="{x:Static local:NamedColor.All}">


<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Label Text="{Binding FriendlyName}" />
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

NOTE
The binding source for cells, and children of cells, is the ListView.ItemsSource collection.

The Label element is set to the View property of the ViewCell . (The ViewCell.View tags are not needed
because the View property is the content property of ViewCell .) This markup displays the FriendlyName
property of each NamedColor object:

Much better. Now all that’s needed is to spruce up the item template with more information and the actual color.
To support this template, some values and objects have been defined in the page’s resource dictionary:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.ListViewDemoPage"
Title="ListView Demo Page">

<ContentPage.Resources>
<ResourceDictionary>
<OnPlatform x:Key="boxSize"
x:TypeArguments="x:Double">
<On Platform="iOS, Android, UWP" Value="50" />
</OnPlatform>

<OnPlatform x:Key="rowHeight"
x:TypeArguments="x:Int32">
<On Platform="iOS, Android, UWP" Value="60" />
</OnPlatform>

<local:DoubleToIntConverter x:Key="intConverter" />

</ResourceDictionary>
</ContentPage.Resources>

<ListView ItemsSource="{x:Static local:NamedColor.All}"


RowHeight="{StaticResource rowHeight}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="5, 5, 0, 5"
Orientation="Horizontal"
Spacing="15">

<BoxView WidthRequest="{StaticResource boxSize}"


HeightRequest="{StaticResource boxSize}"
Color="{Binding Color}" />

<StackLayout Padding="5, 0, 0, 0"


VerticalOptions="Center">

<Label Text="{Binding FriendlyName}"


FontAttributes="Bold"
FontSize="Medium" />
FontSize="Medium" />

<StackLayout Orientation="Horizontal"
Spacing="0">
<Label Text="{Binding Color.R,
Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat='R={0:X2}'}" />

<Label Text="{Binding Color.G,


Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat=', G={0:X2}'}" />

<Label Text="{Binding Color.B,


Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat=', B={0:X2}'}" />
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

Notice the use of OnPlatform to define the size of a BoxView and the height of the ListView rows. Although the
values for all the platforms are the same, the markup could easily be adapted for other values to fine-tune the
display.

Binding Value Converters


The previous ListView Demo XAML file displays the individual R , G , and B properties of the Xamarin.Forms
Color structure. These properties are of type double and range from 0 to 1. If you want to display the
hexadecimal values, you can’t simply use StringFormat with an “X2” formatting specification. That only works
for integers and besides, the double values need to be multiplied by 255.
This little problem was solved with a value converter, also called a binding converter. This is a class that
implements the IValueConverter interface, which means it has two methods named Convert and ConvertBack .
The Convert method is called when a value is transferred from source to target; the ConvertBack method is
called for transfers from target to source in OneWayToSource or TwoWay bindings:
using System;
using System.Globalization;
using Xamarin.Forms;

namespace XamlSamples
{
class DoubleToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
double multiplier;

if (!Double.TryParse(parameter as string, out multiplier))


multiplier = 1;

return (int)Math.Round(multiplier * (double)value);


}

public object ConvertBack(object value, Type targetType,


object parameter, CultureInfo culture)
{
double divider;

if (!Double.TryParse(parameter as string, out divider))


divider = 1;

return ((double)(int)value) / divider;


}
}
}

The ConvertBack method does not play a role in this program because the bindings are only one way from
source to target.
A binding references a binding converter with the Converter property. A binding converter can also accept a
parameter specified with the ConverterParameter property. For some versatility, this is how the multiplier is
specified. The binding converter checks the converter parameter for a valid double value.
The converter is instantiated in the resource dictionary so it can be shared among multiple bindings:

<local:DoubleToIntConverter x:Key="intConverter" />

Three data bindings reference this single instance. Notice that the Binding markup extension contains an
embedded StaticResource markup extension:

<Label Text="{Binding Color.R,


Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat='R={0:X2}'}" />

Here’s the result:


The ListView is quite sophisticated in handling changes that might dynamically occur in the underlying data,
but only if you take certain steps. If the collection of items assigned to the ItemsSource property of the
ListView changes during runtime—that is, if items can be added to or removed from the collection—use an
ObservableCollection class for these items. ObservableCollection implements the INotifyCollectionChanged
interface, and ListView will install a handler for the CollectionChanged event.
If properties of the items themselves change during runtime, then the items in the collection should implement
the INotifyPropertyChanged interface and signal changes to property values using the PropertyChanged event.
This is demonstrated in the next part of this series, Part 5. From Data Binding to MVVM.

Summary
Data bindings provide a powerful mechanism for linking properties between two objects within a page, or
between visual objects and underlying data. But when the application begins working with data sources, a
popular application architectural pattern begins to emerge as a useful paradigm. This is covered in Part 5. From
Data Bindings to MVVM.

Related Links
XamlSamples
Part 1. Getting Started with XAML (sample)
Part 2. Essential XAML Syntax (sample)
Part 3. XAML Markup Extensions (sample)
Part 5. From Data Binding to MVVM (sample)
Part 5. From Data Bindings to MVVM
13 minutes to read • Edit Online

Download the sample


The Model-View -ViewModel (MVVM ) architectural pattern was invented with XAML in mind. The pattern
enforces a separation between three software layers — the XAML user interface, called the View; the underlying
data, called the Model; and an intermediary between the View and the Model, called the ViewModel. The View
and the ViewModel are often connected through data bindings defined in the XAML file. The BindingContext for
the View is usually an instance of the ViewModel.

A Simple ViewModel
As an introduction to ViewModels, let’s first look at a program without one. Earlier you saw how to define a new
XML namespace declaration to allow a XAML file to reference classes in other assemblies. Here’s a program that
defines an XML namespace declaration for the System namespace:

xmlns:sys="clr-namespace:System;assembly=mscorlib"

The program can use x:Static to obtain the current date and time from the static DateTime.Now property and
set that DateTime value to the BindingContext on a StackLayout :

<StackLayout BindingContext="{x:Static sys:DateTime.Now}" …>

BindingContext is a special property: When you set the BindingContext on an element, it is inherited by all the
children of that element. This means that all the children of the StackLayout have this same BindingContext , and
they can contain simple bindings to properties of that object.
In the One-Shot DateTime program, two of the children contain bindings to properties of that DateTime value,
but two other children contain bindings that seem to be missing a binding path. This means that the DateTime
value itself is used for the StringFormat :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="XamlSamples.OneShotDateTimePage"
Title="One-Shot DateTime Page">

<StackLayout BindingContext="{x:Static sys:DateTime.Now}"


HorizontalOptions="Center"
VerticalOptions="Center">

<Label Text="{Binding Year, StringFormat='The year is {0}'}" />


<Label Text="{Binding StringFormat='The month is {0:MMMM}'}" />
<Label Text="{Binding Day, StringFormat='The day is {0}'}" />
<Label Text="{Binding StringFormat='The time is {0:T}'}" />

</StackLayout>
</ContentPage>

The problem is that the date and time are set once when the page is first built, and never change:
A XAML file can display a clock that always shows the current time, but it needs some code to help out. When
thinking in terms of MVVM, the Model and ViewModel are classes written entirely in code. The View is often a
XAML file that references properties defined in the ViewModel through data bindings.
A proper Model is ignorant of the ViewModel, and a proper ViewModel is ignorant of the View. However, often
a programmer tailors the data types exposed by the ViewModel to the data types associated with particular user
interfaces. For example, if a Model accesses a database that contains 8-bit character ASCII strings, the
ViewModel would need to convert between those strings to Unicode strings to accommodate the exclusive use
of Unicode in the user interface.
In simple examples of MVVM (such as those shown here), often there is no Model at all, and the pattern involves
just a View and ViewModel linked with data bindings.
Here’s a ViewModel for a clock with just a single property named DateTime , which updates that DateTime
property every second:
using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace XamlSamples
{
class ClockViewModel : INotifyPropertyChanged
{
DateTime dateTime;

public event PropertyChangedEventHandler PropertyChanged;

public ClockViewModel()
{
this.DateTime = DateTime.Now;

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

public DateTime DateTime


{
set
{
if (dateTime != value)
{
dateTime = value;

if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
}
}
}
get
{
return dateTime;
}
}
}
}

ViewModels generally implement the INotifyPropertyChanged interface, which means that the class fires a
PropertyChanged event whenever one of its properties changes. The data binding mechanism in Xamarin.Forms
attaches a handler to this PropertyChanged event so it can be notified when a property changes and keep the
target updated with the new value.
A clock based on this ViewModel can be as simple as this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.ClockPage"
Title="Clock Page">

<Label Text="{Binding DateTime, StringFormat='{0:T}'}"


FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.BindingContext>
<local:ClockViewModel />
</Label.BindingContext>
</Label>
</ContentPage>

Notice how the ClockViewModel is set to the BindingContext of the Label using property element tags.
Alternatively, you can instantiate the ClockViewModel in a Resources collection and set it to the BindingContext
via a StaticResource markup extension. Or, the code-behind file can instantiate the ViewModel.
The Binding markup extension on the Text property of the Label formats the DateTime property. Here’s the
display:

It’s also possible to access individual properties of the DateTime property of the ViewModel by separating the
properties with periods:

<Label Text="{Binding DateTime.Second, StringFormat='{0}'}" … >

Interactive MVVM
MVVM is often used with two-way data bindings for an interactive view based on an underlying data model.
Here’s a class named HslViewModel that converts a Color value into Hue , Saturation , and Luminosity values,
and vice versa:

using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace XamlSamples
namespace XamlSamples
{
public class HslViewModel : INotifyPropertyChanged
{
double hue, saturation, luminosity;
Color color;

public event PropertyChangedEventHandler PropertyChanged;

public double Hue


{
set
{
if (hue != value)
{
hue = value;
OnPropertyChanged("Hue");
SetNewColor();
}
}
get
{
return hue;
}
}

public double Saturation


{
set
{
if (saturation != value)
{
saturation = value;
OnPropertyChanged("Saturation");
SetNewColor();
}
}
get
{
return saturation;
}
}

public double Luminosity


{
set
{
if (luminosity != value)
{
luminosity = value;
OnPropertyChanged("Luminosity");
SetNewColor();
}
}
get
{
return luminosity;
}
}

public Color Color


{
set
{
if (color != value)
{
color = value;
OnPropertyChanged("Color");

Hue = value.Hue;
Hue = value.Hue;
Saturation = value.Saturation;
Luminosity = value.Luminosity;
}
}
get
{
return color;
}
}

void SetNewColor()
{
Color = Color.FromHsla(Hue, Saturation, Luminosity);
}

protected virtual void OnPropertyChanged(string propertyName)


{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Changes to the Hue , Saturation , and Luminosity properties cause the Color property to change, and changes
to Color causes the other three properties to change. This might seem like an infinite loop, except that the class
doesn't invoke the PropertyChanged event unless the property has changed. This puts an end to the otherwise
uncontrollable feedback loop.
The following XAML file contains a BoxView whose Color property is bound to the Color property of the
ViewModel, and three Slider and three Label views bound to the Hue , Saturation , and Luminosity
properties:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.HslColorScrollPage"
Title="HSL Color Scroll Page">
<ContentPage.BindingContext>
<local:HslViewModel Color="Aqua" />
</ContentPage.BindingContext>

<StackLayout Padding="10, 0">


<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />

<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}"


HorizontalOptions="Center" />

<Slider Value="{Binding Hue, Mode=TwoWay}" />

<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}"


HorizontalOptions="Center" />

<Slider Value="{Binding Saturation, Mode=TwoWay}" />

<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}"


HorizontalOptions="Center" />

<Slider Value="{Binding Luminosity, Mode=TwoWay}" />


</StackLayout>
</ContentPage>

The binding on each Label is the default OneWay . It only needs to display the value. But the binding on each
Slider is TwoWay . This allows the Slider to be initialized from the ViewModel. Notice that the Color property
is set to Aqua when the ViewModel is instantiated. But a change in the Slider also needs to set a new value for
the property in the ViewModel, which then calculates a new color.

Commanding with ViewModels


In many cases, the MVVM pattern is restricted to the manipulation of data items: User-interface objects in the
View parallel data objects in the ViewModel.
However, sometimes the View needs to contain buttons that trigger various actions in the ViewModel. But the
ViewModel must not contain Clicked handlers for the buttons because that would tie the ViewModel to a
particular user-interface paradigm.
To allow ViewModels to be more independent of particular user interface objects but still allow methods to be
called within the ViewModel, a command interface exists. This command interface is supported by the following
elements in Xamarin.Forms:
Button
MenuItem
ToolbarItem
SearchBar
TextCell (and hence also ImageCell )
ListView
TapGestureRecognizer

With the exception of the SearchBar and ListView element, these elements define two properties:
Command of type System.Windows.Input.ICommand
CommandParameter of type Object

The defines SearchCommand and SearchCommandParameter properties, while the


SearchBar ListView defines a
RefreshCommand property of type ICommand .

The ICommand interface defines two methods and one event:


void Execute(object arg)
bool CanExecute(object arg)
event EventHandler CanExecuteChanged
The ViewModel can define properties of type ICommand . You can then bind these properties to the Command
property of each Button or other element, or perhaps a custom view that implements this interface. You can
optionally set the CommandParameter property to identify individual Button objects (or other elements) that are
bound to this ViewModel property. Internally, the Button calls the Execute method whenever the user taps the
Button , passing to the Execute method its CommandParameter .

The CanExecute method and CanExecuteChanged event are used for cases where a Button tap might be currently
invalid, in which case the Button should disable itself. The Button calls CanExecute when the Command property
is first set and whenever the CanExecuteChanged event is fired. If CanExecute returns false , the Button disables
itself and doesn’t generate Execute calls.
For help with adding commanding to your ViewModels, Xamarin.Forms defines two classes that implement
ICommand : Command and Command<T> where T is the type of the arguments to Execute and CanExecute . These
two classes define several constructors plus a ChangeCanExecute method that the ViewModel can call to force the
Command object to fire the CanExecuteChanged event.

Here is a ViewModel for a simple keypad that is intended for entering telephone numbers. Notice that the
Execute and CanExecute method are defined as lambda functions right in the constructor:

using System;
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;

namespace XamlSamples
{
class KeypadViewModel : INotifyPropertyChanged
{
string inputString = "";
string displayText = "";
char[] specialChars = { '*', '#' };

public event PropertyChangedEventHandler PropertyChanged;

// Constructor
public KeypadViewModel()
{
AddCharCommand = new Command<string>((key) =>
{
// Add the key to the input string.
InputString += key;
});

DeleteCharCommand = new Command(() =>


{
// Strip a character from the input string.
InputString = InputString.Substring(0, InputString.Length - 1);
},
() =>
{
// Return true if there's something to delete.
return InputString.Length > 0;
});
}

// Public properties
public string InputString
{
protected set
{
if (inputString != value)
{
inputString = value;
OnPropertyChanged("InputString");
OnPropertyChanged("InputString");
DisplayText = FormatText(inputString);

// Perhaps the delete button must be enabled/disabled.


((Command)DeleteCharCommand).ChangeCanExecute();
}
}

get { return inputString; }


}

public string DisplayText


{
protected set
{
if (displayText != value)
{
displayText = value;
OnPropertyChanged("DisplayText");
}
}
get { return displayText; }
}

// ICommand implementations
public ICommand AddCharCommand { protected set; get; }

public ICommand DeleteCharCommand { protected set; get; }

string FormatText(string str)


{
bool hasNonNumbers = str.IndexOfAny(specialChars) != -1;
string formatted = str;

if (hasNonNumbers || str.Length < 4 || str.Length > 10)


{
}
else if (str.Length < 8)
{
formatted = String.Format("{0}-{1}",
str.Substring(0, 3),
str.Substring(3));
}
else
{
formatted = String.Format("({0}) {1}-{2}",
str.Substring(0, 3),
str.Substring(3, 3),
str.Substring(6));
}
return formatted;
}

protected void OnPropertyChanged(string propertyName)


{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

This ViewModel assumes that the AddCharCommand property is bound to the Command property of several buttons
(or anything else that has a command interface), each of which is identified by the CommandParameter . These
buttons add characters to an InputString property, which is then formatted as a phone number for the
DisplayText property.

There is also a second property of type ICommand named DeleteCharCommand . This is bound to a back-spacing
button, but the button should be disabled if there are no characters to delete.
The following keypad is not as visually sophisticated as it could be. Instead, the markup has been reduced to a
minimum to demonstrate more clearly the use of the command interface:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.KeypadPage"
Title="Keypad Page">

<Grid HorizontalOptions="Center"
VerticalOptions="Center">
<Grid.BindingContext>
<local:KeypadViewModel />
</Grid.BindingContext>

<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>

<!-- Internal Grid for top row of items -->


<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<Frame Grid.Column="0"
OutlineColor="Accent">
<Label Text="{Binding DisplayText}" />
</Frame>

<Button Text="&#x21E6;"
Command="{Binding DeleteCharCommand}"
Grid.Column="1"
BorderWidth="0" />
</Grid>

<Button Text="1"
Command="{Binding AddCharCommand}"
CommandParameter="1"
Grid.Row="1" Grid.Column="0" />

<Button Text="2"
Command="{Binding AddCharCommand}"
CommandParameter="2"
Grid.Row="1" Grid.Column="1" />

<Button Text="3"
Command="{Binding AddCharCommand}"
CommandParameter="3"
Grid.Row="1" Grid.Column="2" />

<Button Text="4"
Command="{Binding AddCharCommand}"
CommandParameter="4"
Grid.Row="2" Grid.Column="0" />
Grid.Row="2" Grid.Column="0" />

<Button Text="5"
Command="{Binding AddCharCommand}"
CommandParameter="5"
Grid.Row="2" Grid.Column="1" />

<Button Text="6"
Command="{Binding AddCharCommand}"
CommandParameter="6"
Grid.Row="2" Grid.Column="2" />

<Button Text="7"
Command="{Binding AddCharCommand}"
CommandParameter="7"
Grid.Row="3" Grid.Column="0" />

<Button Text="8"
Command="{Binding AddCharCommand}"
CommandParameter="8"
Grid.Row="3" Grid.Column="1" />

<Button Text="9"
Command="{Binding AddCharCommand}"
CommandParameter="9"
Grid.Row="3" Grid.Column="2" />

<Button Text="*"
Command="{Binding AddCharCommand}"
CommandParameter="*"
Grid.Row="4" Grid.Column="0" />

<Button Text="0"
Command="{Binding AddCharCommand}"
CommandParameter="0"
Grid.Row="4" Grid.Column="1" />

<Button Text="#"
Command="{Binding AddCharCommand}"
CommandParameter="#"
Grid.Row="4" Grid.Column="2" />
</Grid>
</ContentPage>

The Command property of the first Button that appears in this markup is bound to the DeleteCharCommand ; the
rest are bound to the AddCharCommand with a CommandParameter that is the same as the character that appears on
the Button face. Here’s the program in action:
Invoking Asynchronous Methods
Commands can also invoke asynchronous methods. This is achieved by using the async and await keywords
when specifying the Execute method:

DownloadCommand = new Command (async () => await DownloadAsync ());

This indicates that the DownloadAsync method is a Task and should be awaited:

async Task DownloadAsync ()


{
await Task.Run (() => Download ());
}

void Download ()
{
...
}

Implementing a Navigation Menu


The XamlSamples program that contains all the source code in this series of articles uses a ViewModel for its
home page. This ViewModel is a definition of a short class with three properties named Type , Title , and
Description that contain the type of each of the sample pages, a title, and a short description. In addition, the
ViewModel defines a static property named All that is a collection of all the pages in the program:

public class PageDataViewModel


{
public PageDataViewModel(Type type, string title, string description)
{
Type = type;
Title = title;
Description = description;
}

public Type Type { private set; get; }

public string Title { private set; get; }

public string Description { private set; get; }


static PageDataViewModel()
{
All = new List<PageDataViewModel>
{
// Part 1. Getting Started with XAML
new PageDataViewModel(typeof(HelloXamlPage), "Hello, XAML",
"Display a Label with many properties set"),

new PageDataViewModel(typeof(XamlPlusCodePage), "XAML + Code",


"Interact with a Slider and Button"),

// Part 2. Essential XAML Syntax


new PageDataViewModel(typeof(GridDemoPage), "Grid Demo",
"Explore XAML syntax with the Grid"),

new PageDataViewModel(typeof(AbsoluteDemoPage), "Absolute Demo",


"Explore XAML syntax with AbsoluteLayout"),

// Part 3. XAML Markup Extensions


new PageDataViewModel(typeof(SharedResourcesPage), "Shared Resources",
"Using resource dictionaries to share resources"),

new PageDataViewModel(typeof(StaticConstantsPage), "Static Constants",


"Using the x:Static markup extensions"),

new PageDataViewModel(typeof(RelativeLayoutPage), "Relative Layout",


"Explore XAML markup extensions"),

// Part 4. Data Binding Basics


new PageDataViewModel(typeof(SliderBindingsPage), "Slider Bindings",
"Bind properties of two views on the page"),

new PageDataViewModel(typeof(SliderTransformsPage), "Slider Transforms",


"Use Sliders with reverse bindings"),

new PageDataViewModel(typeof(ListViewDemoPage), "ListView Demo",


"Use a ListView with data bindings"),

// Part 5. From Data Bindings to MVVM


new PageDataViewModel(typeof(OneShotDateTimePage), "One-Shot DateTime",
"Obtain the current DateTime and display it"),

new PageDataViewModel(typeof(ClockPage), "Clock",


"Dynamically display the current time"),

new PageDataViewModel(typeof(HslColorScrollPage), "HSL Color Scroll",


"Use a view model to select HSL colors"),

new PageDataViewModel(typeof(KeypadPage), "Keypad",


"Use a view model for numeric keypad logic")
};
}

public static IList<PageDataViewModel> All { private set; get; }


}

The XAML file for MainPage defines a ListBox whose ItemsSource property is set to that All property and
which contains a TextCell for displaying the Title and Description properties of each page:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.MainPage"
Padding="5, 0"
Title="XAML Samples">

<ListView ItemsSource="{x:Static local:PageDataViewModel.All}"


ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"
Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

The pages are shown in a scrollable list:

The handler in the code-behind file is triggered when the user selects an item. The handler sets the SelectedItem
property of the ListBox back to null and then instantiates the selected page and navigates to it:

private async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs args)


{
(sender as ListView).SelectedItem = null;

if (args.SelectedItem != null)
{
PageDataViewModel pageData = args.SelectedItem as PageDataViewModel;
Page page = (Page)Activator.CreateInstance(pageData.Type);
await Navigation.PushAsync(page);
}
}

Video
Xamarin Evolve 2016: MVVM Made Simple with Xamarin.Forms and Prism
Summary
XAML is a powerful tool for defining user interfaces in Xamarin.Forms applications, particularly when data-
binding and MVVM are used. The result is a clean, elegant, and potentially toolable representation of a user
interface with all the background support in code.

Related Links
XamlSamples
Part 1. Getting Started with XAML
Part 2. Essential XAML Syntax
Part 3. XAML Markup Extensions
Part 4. Data Binding Basics

Related Videos

Find more Xamarin videos on Channel 9 and YouTube.


XAML Controls
2 minutes to read • Edit Online

Download the sample


Views are user-interface objects such as labels, buttons, and sliders that are commonly known as controls or
widgets in other graphical programming environments. The views supported by Xamarin.Forms all derive from the
View class.

All of the views that are defined in Xamarin.Forms can be referenced from XAML files.

Views for presentation

BoxView
<BoxView Color="Accent"
Displays a rectangle of a particular color. WidthRequest="150"
HeightRequest="150"
HorizontalOptions="Center">

API / Guide

Image
<Image Source="https://aka.ms/campus.jpg"
Displays a bitmap. Aspect="AspectFit"
HorizontalOptions="Center" />

API / Guide

Label
<Label Text="Hello, Xamarin.Forms!"
Displays one or more lines of text. FontSize="Large"
FontAttributes="Italic"
HorizontalTextAlignment="Center" />

API / Guide
Map
<maps:Map ItemsSource="{Binding Locations}" />
Displays a map.

API / Guide

WebView
<WebView
Displays Web pages or HTML content. Source="https://docs.microsoft.com/xamarin/"
VerticalOptions="FillAndExpand" />

API / Guide

Views that initiate commands

Button
<Button Text="Click Me!"
Displays text in a rectangular object. Font="Large"
BorderWidth="1"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />

API / Guide

ImageButton
<ImageButton Source="XamarinLogo.png"
Displays an image in a rectangular object. HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnImageButtonClicked" />

API / Guide
RefreshView
<RefreshView IsRefreshing="{Binding IsRefreshing}"
Provides pull-to-refresh functionality for scrollable content. Command="{Binding RefreshCommand}" >
<!-- Scrollable control goes here -->
</RefreshView>

Guide

SearchBar
<SearchBar Placeholder="Enter search term"
Accepts user input that it uses to perform a search.
SearchButtonPressed="OnSearchBarButtonPressed" />

Guide

SwipeView
<SwipeView>
Provides context menu items that are revealed by a swipe <SwipeView.LeftItems>
gesture. <SwipeItems>
<SwipeItem Text="Delete"
IconImageSource="delete.png"
BackgroundColor="LightPink"
Invoked="OnDeleteInvoked" />
</SwipeItems>
Guide </SwipeView.LeftItems>
<!-- Content -->
</SwipeView>

Views for setting values

CheckBox
<CheckBox IsChecked="true"
Allows the selection of a boolean value. HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

Guide

Slider
<Slider Minimum="0"
Allows the selection of a double value from a continuous Maximum="100"
range. VerticalOptions="CenterAndExpand" />

API / Guide
Stepper
<Stepper Minimum="0"
Allows the selection of a double value from an incremental Maximum="10"
range. Increment="0.1"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

API / Guide

Switch
<Switch IsToggled="false"
Allows the selection of a boolean value. HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

API / Guide

DatePicker
<DatePicker Format="D"
Allows the selection of a date. VerticalOptions="CenterAndExpand" />

API / Guide

TimePicker
<TimePicker Format="T"
Allows the selection of a time. VerticalOptions="CenterAndExpand" />

API / Guide
Views for editing text

Entry
<Entry Keyboard="Email"
Allows a single line of text to be entered and edited. Placeholder="Enter email address"
VerticalOptions="CenterAndExpand" />

API / Guide

Editor
<Editor VerticalOptions="FillAndExpand" />
Allows multiple lines of text to be entered and edited.

API / Guide

Views to indicate activity

ActivityIndicator
<ActivityIndicator IsRunning="True"
Displays an animation to show that the application is engaged
in a lengthy activity, without giving any indication of progress. VerticalOptions="CenterAndExpand" />

API / Guide

ProgressBar
<ProgressBar Progress=".5"
Displays an animation to show that the application is VerticalOptions="CenterAndExpand" />
progressing through a lengthy activity.

API / Guide

Views that display collections


CarouselView
<CarouselView ItemsSource="{Binding Monkeys}">
Displays a scrollable list of data items. ItemTemplate="{StaticResource
MonkeyTemplate}" />

Guide

CollectionView
<CollectionView ItemsSource="{Binding Monkeys}">
Displays a scrollable list of selectable data items, using ItemTemplate="{StaticResource
different layout specifications. MonkeyTemplate}"
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
</CollectionView/>

Guide

IndicatorView
<IndicatorView ItemsSourceBy="carouselView"
Displays indicators that represent the number of items in a IndicatorColor="LightGray"
CarouselView . SelectedIndicatorColor="DarkGray" />

Guide
ListView
<ListView ItemsSource="{Binding Monkeys}">
Displays a scrollable list of selectable data items. ItemTemplate="{StaticResource
MonkeyTemplate}" />

API / Guide

Picker
<Picker Title="Select a monkey"
Displays a select item from a list of text strings. TitleColor="Red">
<Picker.ItemsSource<
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>

API / Guide

TableView
<TableView Intent="Settings">
Displays a list of interactive rows. <TableRoot>
<TableSection Title="Ring">
<SwitchCell Text="New Voice Mail" />
<SwitchCell Text="New Mail" On="true"
/>
</TableSection>
</TableRoot>
API / Guide </TableView>

Related links
Xamarin.Forms FormsGallery sample
Xamarin.Forms Samples
Xamarin.Forms API Documentation
XAML Compilation in Xamarin.Forms
2 minutes to read • Edit Online

XAML can be optionally compiled directly into intermediate language (IL ) with the XAML compiler (XAMLC ).
XAML compilation offers a number of a benefits:
It performs compile-time checking of XAML, notifying the user of any errors.
It removes some of the load and instantiation time for XAML elements.
It helps to reduce the file size of the final assembly by no longer including .xaml files.
XAML compilation is disabled by default to ensure backwards compatibility. It can be enabled at both the
assembly and class level by adding the XamlCompilation attribute.
The following code example demonstrates enabling XAML compilation at the assembly level:

using Xamarin.Forms.Xaml;
...
[assembly: XamlCompilation (XamlCompilationOptions.Compile)]
namespace PhotoApp
{
...
}

In this example, compile-time checking of all the XAML contained within the assembly will be performed, with
XAML errors being reported at compile-time rather than run-time. Therefore, the assembly prefix to the
XamlCompilation attribute specifies that the attribute applies to the entire assembly.

NOTE
The XamlCompilation attribute and the XamlCompilationOptions enumeration reside in the Xamarin.Forms.Xaml
namespace, which must be imported to use them.

The following code example demonstrates enabling XAML compilation at the class level:

using Xamarin.Forms.Xaml;
...
[XamlCompilation (XamlCompilationOptions.Compile)]
public class HomePage : ContentPage
{
...
}

In this example, compile-time checking of the XAML for the HomePage class will be performed and errors reported
as part of the compilation process.

NOTE
Compiled bindings can be enabled to improve data binding performance in Xamarin.Forms applications. For more
information, see Compiled Bindings.
Related Links
XamlCompilation
XamlCompilationOptions
XAML Markup Extensions
2 minutes to read • Edit Online

Download the sample


XAML markup extensions help extend the power and flexibility of XAML by allowing element attributes to be set
from sources other than literal text strings.
For example, normally you set the Color property of BoxView like this:

<BoxView Color="Blue" />

Or, you can set it to a hexadecimal RGB color value:

<BoxView Color="#FF0080" />

In either case, the text string set to the Color attribute is converted to a Color value by the ColorTypeConverter
class.
You might prefer instead to set the Color attribute from a value stored in a resource dictionary, or from the value
of a static property of a class that you've created, or from a property of type Color of another element on the
page, or constructed from separate hue, saturation, and luminosity values.
All these options are possible using XAML markup extensions. But don't let the phrase "markup extensions" scare
you: XAML markup extensions are not extensions to XML. Even with XAML markup extensions, XAML is always
legal XML.
A markup extension is really just a different way to express an attribute of an element. XAML markup extensions
are usually identifiable by an attribute setting that is enclosed in curly braces:

<BoxView Color="{StaticResource themeColor}" />

Any attribute setting in curly braces is always a XAML markup extension. However, as you'll see, XAML markup
extensions can also be referenced without the use of curly braces.
This article is divided in two parts:

Consuming XAML Markup Extensions


Use the XAML markup extensions defined in Xamarin.Forms.

Creating XAML Markup Extensions


Write your own custom XAML markup extensions.

Related Links
Markup Extensions (sample)
XAML markup extensions chapter from Xamarin.Forms book
Resource Dictionaries
Dynamic Styles
Data Binding
Consuming XAML Markup Extensions
17 minutes to read • Edit Online

Download the sample


XAML markup extensions help enhance the power and flexibility of XAML by allowing element attributes to be set
from a variety of sources. Several XAML markup extensions are part of the XAML 2009 specification. These
appear in XAML files with the customary x namespace prefix, and are commonly referred to with this prefix. This
article discusses the following markup extensions:
x:Static – reference static properties, fields, or enumeration members.
x:Reference – reference named elements on the page.
x:Type – set an attribute to a System.Type object.
x:Array – construct an array of objects of a particular type.
x:Null – set an attribute to a null value.
OnPlatform – customize UI appearance on a per -platform basis.
OnIdiom – customize UI appearance based on the idiom of the device the application is running on.
DataTemplate - converts a type into a DataTemplate .
FontImage - display a font icon in any view that can display an ImageSource .

Additional XAML markup extensions have historically been supported by other XAML implementations, and are
also supported by Xamarin.Forms. These are described more fully in other articles:
StaticResource - reference objects from a resource dictionary, as described in the article Resource
Dictionaries.
DynamicResource - respond to changes in objects in a resource dictionary, as described in the article Dynamic
Styles.
Binding- establish a link between properties of two objects, as described in the article Data Binding.
TemplateBinding - performs data binding from a control template, as discussed in the article Xamarin.Forms
control templates.
RelativeSource - sets the binding source relative to the position of the binding target, as discussed in the article
Relative Bindings.
The RelativeLayout layout makes use of the custom markup extension ConstraintExpression . This markup
extension is described in the article RelativeLayout.

x:Static markup extension


The markup extension is supported by the StaticExtension class. The class has a single property named
x:Static
Member of type string that you set to the name of a public constant, static property, static field, or enumeration
member.
One common way to use x:Static is to first define a class with some constants or static variables, such as this tiny
AppConstants class in the MarkupExtensions program:
static class AppConstants
{
public static double NormalFontSize = 18;
}

The x:Static Demo page demonstrates several ways to use the x:Static markup extension. The most verbose
approach instantiates the StaticExtension class between Label.FontSize property-element tags:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.StaticDemoPage"
Title="x:Static Demo">
<StackLayout Margin="10, 0">
<Label Text="Label No. 1">
<Label.FontSize>
<x:StaticExtension Member="local:AppConstants.NormalFontSize" />
</Label.FontSize>
</Label>

···

</StackLayout>
</ContentPage>

The XAML parser also allows the StaticExtension class to be abbreviated as x:Static :

<Label Text="Label No. 2">


<Label.FontSize>
<x:Static Member="local:AppConstants.NormalFontSize" />
</Label.FontSize>
</Label>

This can be simplified even further, but the change introduces some new syntax: It consists of putting the
StaticExtension class and the member setting in curly braces. The resulting expression is set directly to the
FontSize attribute:

<Label Text="Label No. 3"


FontSize="{x:StaticExtension Member=local:AppConstants.NormalFontSize}" />

Notice that there are no quotation marks within the curly braces. The Member property of StaticExtension is no
longer an XML attribute. It is instead part of the expression for the markup extension.
Just as you can abbreviate x:StaticExtension to x:Static when you use it as an object element, you can also
abbreviate it in the expression within curly braces:

<Label Text="Label No. 4"


FontSize="{x:Static Member=local:AppConstants.NormalFontSize}" />

The StaticExtension class has a ContentProperty attribute referencing the property Member , which marks this
property as the class's default content property. For XAML markup extensions expressed with curly braces, you
can eliminate the Member= part of the expression:
<Label Text="Label No. 5"
FontSize="{x:Static local:AppConstants.NormalFontSize}" />

This is the most common form of the x:Static markup extension.


The Static Demo page contains two other examples. The root tag of the XAML file contains an XML namespace
declaration for the .NET System namespace:

xmlns:sys="clr-namespace:System;assembly=mscorlib"

This allows the Label font size to be set to the static field Math.PI . That results in rather small text, so the Scale
property is set to Math.E :

<Label Text="&#x03C0; &#x00D7; E sized text"


FontSize="{x:Static sys:Math.PI}"
Scale="{x:Static sys:Math.E}"
HorizontalOptions="Center" />

The final example displays the Device.RuntimePlatform value. The Environment.NewLine static property is used to
insert a new -line character between the two Span objects:

<Label HorizontalTextAlignment="Center"
FontSize="{x:Static local:AppConstants.NormalFontSize}">
<Label.FormattedText>
<FormattedString>
<Span Text="Runtime Platform: " />
<Span Text="{x:Static sys:Environment.NewLine}" />
<Span Text="{x:Static Device.RuntimePlatform}" />
</FormattedString>
</Label.FormattedText>
</Label>

Here's the sample running:

x:Reference markup extension


The x:Reference markup extension is supported by the ReferenceExtension class. The class has a single property
named Name of type string that you set to the name of an element on the page that has been given a name with
x:Name . This Name property is the content property of ReferenceExtension , so Name= is not required when
x:Reference appears in curly braces.

The x:Reference markup extension is used exclusively with data bindings, which are described in more detail in
the article Data Binding.
The x:Reference Demo page shows two uses of x:Reference with data bindings, the first where it's used to set
the Source property of the Binding object, and the second where it's used to set the BindingContext property for
two data bindings:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MarkupExtensions.ReferenceDemoPage"
x:Name="page"
Title="x:Reference Demo">

<StackLayout Margin="10, 0">

<Label Text="{Binding Source={x:Reference page},


StringFormat='The type of this page is {0}'}"
FontSize="18"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="Center" />

<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />

<Label BindingContext="{x:Reference slider}"


Text="{Binding Value, StringFormat='{0:F0}&#x00B0; rotation'}"
Rotation="{Binding Value}"
FontSize="24"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

</StackLayout>
</ContentPage>

Both x:Reference expressions use the abbreviated version of the ReferenceExtension class name and eliminate
the Name= part of the expression. In the first example, the x:Reference markup extension is embedded in the
Binding markup extension. Notice that the Source and StringFormat settings are separated by commas. Here's
the program running:
x:Type markup extension
The x:Type markup extension is the XAML equivalent of the C# typeof keyword. It is supported by the
TypeExtension class, which defines one property named TypeName of type string that is set to a class or structure
name. The x:Type markup extension returns the System.Type object of that class or structure. TypeName is the
content property of TypeExtension , so TypeName= is not required when x:Type appears with curly braces.
Within Xamarin.Forms, there are several properties that have arguments of type Type . Examples include the
TargetType property of Style , and the x:TypeArguments attribute used to specify arguments in generic classes.
However, the XAML parser performs the typeof operation automatically, and the x:Type markup extension is
not used in these cases.
One place where x:Type is required is with the x:Array markup extension, which is described in the next section.
The x:Type markup extension is also useful when constructing a menu where each menu item corresponds to an
object of a particular type. You can associate a Type object with each menu item, and then instantiate the object
when the menu item is selected.
This is how the navigation menu in MainPage in the Markup Extensions program works. The MainPage.xaml
file contains a TableView with each TextCell corresponding to a particular page in the program:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.MainPage"
Title="Markup Extensions"
Padding="10">
<TableView Intent="Menu">
<TableRoot>
<TableSection>
<TextCell Text="x:Static Demo"
Detail="Access constants or statics"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:StaticDemoPage}" />

<TextCell Text="x:Reference Demo"


Detail="Reference named elements on the page"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ReferenceDemoPage}" />

<TextCell Text="x:Type Demo"


Detail="Associate a Button with a Type"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:TypeDemoPage}" />

<TextCell Text="x:Array Demo"


Detail="Use an array to fill a ListView"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ArrayDemoPage}" />

···

</TableRoot>
</TableView>
</ContentPage>

Here's the opening main page in Markup Extensions:

Each CommandParameterproperty is set to an x:Type markup extension that references one of the other pages. The
Command property is bound to a property named NavigateCommand . This property is defined in the MainPage code-
behind file:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();

NavigateCommand = new Command<Type>(async (Type pageType) =>


{
Page page = (Page)Activator.CreateInstance(pageType);
await Navigation.PushAsync(page);
});

BindingContext = this;
}

public ICommand NavigateCommand { private set; get; }


}

The NavigateCommand property is a Command object that implements an execute command with an argument of
type Type — the value of CommandParameter . The method uses Activator.CreateInstance to instantiate the page
and then navigates to it. The constructor concludes by setting the BindingContext of the page to itself, which
enables the Binding on Command to work. See the Data Binding article and particularly the Commanding
article for more details about this type of code.
The x:Type Demo page uses a similar technique to instantiate Xamarin.Forms elements and to add them to a
StackLayout . The XAML file initially consists of three Button elements with their Command properties set to a
Binding and the CommandParameter properties set to types of three Xamarin.Forms views:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MarkupExtensions.TypeDemoPage"
Title="x:Type Demo">

<StackLayout x:Name="stackLayout"
Padding="10, 0">

<Button Text="Create a Slider"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Command="{Binding CreateCommand}"
CommandParameter="{x:Type Slider}" />

<Button Text="Create a Stepper"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Command="{Binding CreateCommand}"
CommandParameter="{x:Type Stepper}" />

<Button Text="Create a Switch"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Command="{Binding CreateCommand}"
CommandParameter="{x:Type Switch}" />
</StackLayout>
</ContentPage>

The code-behind file defines and initializes the CreateCommand property:


public partial class TypeDemoPage : ContentPage
{
public TypeDemoPage()
{
InitializeComponent();

CreateCommand = new Command<Type>((Type viewType) =>


{
View view = (View)Activator.CreateInstance(viewType);
view.VerticalOptions = LayoutOptions.CenterAndExpand;
stackLayout.Children.Add(view);
});

BindingContext = this;
}

public ICommand CreateCommand { private set; get; }


}

The method that is executed when a Button is pressed creates a new instance of the argument, sets its
VerticalOptions property, and adds it to the StackLayout . The three Button elements then share the page with
dynamically created views:

x:Array markup extension


The x:Array markup extension allows you to define an array in markup. It is supported by the ArrayExtension
class, which defines two properties:
Type of type Type , which indicates the type of the elements in the array.
Items of type IList , which is a collection of the items themselves. This is the content property of
ArrayExtension .

The x:Array markup extension itself never appears in curly braces. Instead, x:Array start and end tags delimit
the list of items. Set the Type property to an x:Type markup extension.
The x:Array Demo page shows how to use x:Array to add items to a ListView by setting the ItemsSource
property to an array:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MarkupExtensions.ArrayDemoPage"
Title="x:Array Demo Page">
<ListView Margin="10">
<ListView.ItemsSource>
<x:Array Type="{x:Type Color}">
<Color>Aqua</Color>
<Color>Black</Color>
<Color>Blue</Color>
<Color>Fuchsia</Color>
<Color>Gray</Color>
<Color>Green</Color>
<Color>Lime</Color>
<Color>Maroon</Color>
<Color>Navy</Color>
<Color>Olive</Color>
<Color>Pink</Color>
<Color>Purple</Color>
<Color>Red</Color>
<Color>Silver</Color>
<Color>Teal</Color>
<Color>White</Color>
<Color>Yellow</Color>
</x:Array>
</ListView.ItemsSource>

<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<BoxView Color="{Binding}"
Margin="3" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

The ViewCell creates a simple BoxView for each color entry:

There are several ways to specify the individual Color items in this array. You can use an x:Static markup
extension:
<x:Static Member="Color.Blue" />

Or, you can use StaticResource to retrieve a color from a resource dictionary:

<StaticResource Key="myColor" />

Towards the end of this article, you'll see a custom XAML markup extension that also creates a new color value:

<local:HslColor H="0.5" S="1.0" L="0.5" />

When defining arrays of common types like strings or numbers, use the tags listed in the Passing Constructor
Arguments article to delimit the values.

x:Null markup extension


The x:Null markup extension is supported by the NullExtension class. It has no properties and is simply the
XAML equivalent of the C# null keyword.
The x:Null markup extension is rarely needed and seldom used, but if you do find a need for it, you'll be glad that
it exists.
The x:Null Demo page illustrates one scenario when x:Null might be convenient. Suppose that you define an
implicit Style for Label that includes a Setter that sets the FontFamily property to a platform-dependent
family name:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MarkupExtensions.NullDemoPage"
Title="x:Null Demo">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="48" />
<Setter Property="FontFamily">
<Setter.Value>
<OnPlatform x:TypeArguments="x:String">
<On Platform="iOS" Value="Times New Roman" />
<On Platform="Android" Value="serif" />
<On Platform="UWP" Value="Times New Roman" />
</OnPlatform>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<ContentPage.Content>
<StackLayout Padding="10, 0">
<Label Text="Text 1" />
<Label Text="Text 2" />

<Label Text="Text 3"


FontFamily="{x:Null}" />

<Label Text="Text 4" />


<Label Text="Text 5" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Then you discover that for one of the Label elements, you want all the property settings in the implicit Style
except for the FontFamily , which you want to be the default value. You could define another Style for that
purpose but a simpler approach is simply to set the FontFamily property of the particular Label to x:Null , as
demonstrated in the center Label .
Here's the program running:

Notice that four of the Label elements have a serif font, but the center Label has the default sans-serif font.
OnPlatform markup extension
The OnPlatform markup extension allows you to customize UI appearance on a per-platform basis. It provides the
same functionality as the OnPlatform and On classes, but with a more concise representation.
The OnPlatform markup extension is supported by the OnPlatformExtension class, which defines the following
properties:
Default of type object , that you set to a default value to be applied to the properties that represent platforms.
Android of type object , that you set to a value to be applied on Android.
GTK of type object , that you set to a value to be applied on GTK platforms.
iOS of type object , that you set to a value to be applied on iOS.
macOS of type object , that you set to a value to be applied on macOS.
Tizen of type object , that you set to a value to be applied on the Tizen platform.
UWP of type object , that you set to a value to be applied on the Universal Windows Platform.
WPF of type object , that you set to a value to be applied on the Windows Presentation Foundation platform.
Converter of type IValueConverter , that you set to an IValueConverter implementation.
ConverterParameter of type object , that you set to a value to pass to the IValueConverter implementation.

NOTE
The XAML parser allows the OnPlatformExtension class to be abbreviated as OnPlatform .

The Default property is the content property of OnPlatformExtension . Therefore, for XAML markup expressions
expressed with curly braces, you can eliminate the Default= part of the expression provided that it's the first
argument. If the Default property isn't set, it will default to the BindableProperty.DefaultValue property value,
provided that the markup extension is targeting a BindableProperty .

IMPORTANT
The XAML parser expects that values of the correct type will be provided to properties consuming the OnPlatform markup
extension. If type conversion is necessary, the OnPlatform markup extension will attempt to perform it using the default
converters provided by Xamarin.Forms. However, there are some type conversions that can't be performed by the default
converters and in these cases the Converter property should be set to an IValueConverter implementation.

The OnPlatform Demo page shows how to use the OnPlatform markup extension:

<BoxView Color="{OnPlatform Yellow, iOS=Red, Android=Green, UWP=Blue}"


WidthRequest="{OnPlatform 250, iOS=200, Android=300, UWP=400}"
HeightRequest="{OnPlatform 250, iOS=200, Android=300, UWP=400}"
HorizontalOptions="Center" />

In this example, all three OnPlatform expressions use the abbreviated version of the OnPlatformExtension class
name. The three OnPlatform markup extensions set the Color , WidthRequest , and HeightRequest properties of
the BoxView to different values on iOS, Android, and UWP. The markup extensions also provide default values for
these properties on the platforms that aren't specified, while eliminating the Default= part of the expression.
Notice that the markup extension properties that are set are separated by commas.
Here's the program running:
OnIdiom markup extension
The OnIdiom markup extension allows you to customize UI appearance based on the idiom of the device the
application is running on. It's supported by the OnIdiomExtension class, which defines the following properties:
Default of type object , that you set to a default value to be applied to the properties that represent device
idioms.
Phone of type object , that you set to a value to be applied on phones.
Tablet of type object , that you set to a value to be applied on tablets.
Desktop of type object , that you set to a value to be applied on desktop platforms.
TV of type object , that you set to a value to be applied on TV platforms.
Watch of type object , that you set to a value to be applied on Watch platforms.
Converter of type IValueConverter , that you set to an IValueConverter implementation.
ConverterParameter of type object , that you set to a value to pass to the IValueConverter implementation.

NOTE
The XAML parser allows the OnIdiomExtension class to be abbreviated as OnIdiom .

The Default property is the content property of OnIdiomExtension . Therefore, for XAML markup expressions
expressed with curly braces, you can eliminate the Default= part of the expression provided that it's the first
argument.

IMPORTANT
The XAML parser expects that values of the correct type will be provided to properties consuming the OnIdiom markup
extension. If type conversion is necessary, the OnIdiom markup extension will attempt to perform it using the default
converters provided by Xamarin.Forms. However, there are some type conversions that can't be performed by the default
converters and in these cases the Converter property should be set to an IValueConverter implementation.

The OnIdiom Demo page shows how to use the OnIdiom markup extension:
<BoxView Color="{OnIdiom Yellow, Phone=Red, Tablet=Green, Desktop=Blue}"
WidthRequest="{OnIdiom 100, Phone=200, Tablet=300, Desktop=400}"
HeightRequest="{OnIdiom 100, Phone=200, Tablet=300, Desktop=400}"
HorizontalOptions="Center" />

In this example, all three OnIdiom expressions use the abbreviated version of the OnIdiomExtension class name.
The three OnIdiom markup extensions set the Color , WidthRequest , and HeightRequest properties of the
BoxView to different values on the phone, tablet, and desktop idioms. The markup extensions also provide default
values for these properties on the idioms that aren't specified, while eliminating the Default= part of the
expression. Notice that the markup extension properties that are set are separated by commas.
Here's the program running:

DataTemplate markup extension


The DataTemplate markup extension allows you to convert a type into a DataTemplate . It's supported by the
DataTemplateExtension class, which defines a TypeName property, of type string , that is set to the name of the
type to be converted into a DataTemplate . The TypeName property is the content property of
DataTemplateExtension . Therefore, for XAML markup expressions expressed with curly braces, you can eliminate
the TypeName= part of the expression.

NOTE
The XAML parser allows the DataTemplateExtension class to be abbreviated as DataTemplate .

A typical usage of this markup extension is in a Shell application, as shown in the following example:

<ShellContent Title="Monkeys"
Icon="monkey.png"
ContentTemplate="{DataTemplate views:MonkeysPage}" />

In this example, MonkeysPageis converted from a ContentPage to a DataTemplate , which is set as the value of the
ShellContent.ContentTemplate property. This ensures that MonkeysPage is only created when navigation to the
page occurs, rather than at application startup.
For more information about Shell applications, see Xamarin.Forms Shell.
FontImage markup extension
The FontImage markup extension allows you to display a font icon in any view that can display an ImageSource . It
provides the same functionality as the FontImageSource class, but with a more concise representation.
The FontImage markup extension is supported by the FontImageExtension class, which defines the following
properties:
FontFamily of type string , the font family to which the font icon belongs.
Glyph of type string , the unicode character value of the font icon.
Color of type Color , the color to be used when displaying the font icon.
Size of type double , the size, in device-independent units, of the rendered font icon. The default value is 30. In
addition, this property can be set to a named font size.

NOTE
The XAML parser allows the FontImageExtension class to be abbreviated as FontImage .

The Glyph property is the content property of FontImageExtension . Therefore, for XAML markup expressions
expressed with curly braces, you can eliminate the Glyph= part of the expression provided that it's the first
argument.
The FontImage Demo page shows how to use the FontImage markup extension:

<Image BackgroundColor="#D1D1D1"
Source="{FontImage &#xf30c;, FontFamily={OnPlatform iOS=Ionicons, Android=ionicons.ttf#}, Size=44}" />

In this example, the abbreviated version of the FontImageExtension class name is used to display an XBox icon,
from the Ionicons font family, in an Image . The expression also uses the OnPlatform markup extension to specify
different FontFamily property values on iOS and Android. In addition, the Glyph= part of the expression is
eliminated, and the markup extension properties that are set are separated by commas. Note that while the
unicode character for the icon is \uf30c , it has to be escaped in XAML and so becomes &#xf30c; .
Here's the program running:

For information about displaying font icons by specifying the font icon data in a FontImageSource object, see
Display font icons.

Define Your Own Markup Extensions


If you've encountered a need for a XAML markup extension that isn't available in Xamarin.Forms, you can create
your own.

Related Links
Markup Extensions (sample)
XAML markup extensions chapter from Xamarin.Forms book
Resource Dictionaries
Dynamic Styles
Data Binding
Xamarin.Forms Shell.
Creating XAML Markup Extensions
5 minutes to read • Edit Online

Download the sample


On the programmatic level, a XAML markup extension is a class that implements the IMarkupExtension or
IMarkupExtension<T> interface. You can explore the source code of the standard markup extensions described
below in the MarkupExtensions directory of the Xamarin.Forms GitHub repository.
It's also possible to define your own custom XAML markup extensions by deriving from IMarkupExtension or
IMarkupExtension<T> . Use the generic form if the markup extension obtains a value of a particular type. This is the
case with several of the Xamarin.Forms markup extensions:
TypeExtension derives from IMarkupExtension<Type>
ArrayExtension derives from IMarkupExtension<Array>
DynamicResourceExtension derives from IMarkupExtension<DynamicResource>
BindingExtension derives from IMarkupExtension<BindingBase>
ConstraintExpression derives from IMarkupExtension<Constraint>

The two IMarkupExtension interfaces define only one method each, named ProvideValue :

public interface IMarkupExtension


{
object ProvideValue(IServiceProvider serviceProvider);
}

public interface IMarkupExtension<out T> : IMarkupExtension


{
new T ProvideValue(IServiceProvider serviceProvider);
}

Since IMarkupExtension<T> derives from IMarkupExtension and includes the new keyword on ProvideValue , it
contains both ProvideValue methods.
Very often, XAML markup extensions define properties that contribute to the return value. (The obvious exception
is NullExtension , in which ProvideValue simply returns null .) The ProvideValue method has a single argument
of type IServiceProvider that will be discussed later in this article.

A Markup Extension for Specifying Color


The following XAML markup extension allows you to construct a Color value using hue, saturation, and
luminosity components. It defines four properties for the four components of the color, including an alpha
component that is initialized to 1. The class derives from IMarkupExtension<Color> to indicate a Color return
value:
public class HslColorExtension : IMarkupExtension<Color>
{
public double H { set; get; }

public double S { set; get; }

public double L { set; get; }

public double A { set; get; } = 1.0;

public Color ProvideValue(IServiceProvider serviceProvider)


{
return Color.FromHsla(H, S, L, A);
}

object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)


{
return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
}
}

Because IMarkupExtension<T> derives from IMarkupExtension , the class must contain two ProvideValue methods,
one that returns Color and another that returns object , but the second method can simply call the first method.
The HSL Color Demo page shows a variety of ways that HslColorExtension can appear in a XAML file to specify
the color for a BoxView :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.HslColorDemoPage"
Title="HSL Color Demo">

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="BoxView">
<Setter Property="WidthRequest" Value="80" />
<Setter Property="HeightRequest" Value="80" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
<BoxView>
<BoxView.Color>
<local:HslColorExtension H="0" S="1" L="0.5" A="1" />
</BoxView.Color>
</BoxView>

<BoxView>
<BoxView.Color>
<local:HslColor H="0.33" S="1" L="0.5" />
</BoxView.Color>
</BoxView>

<BoxView Color="{local:HslColorExtension H=0.67, S=1, L=0.5}" />

<BoxView Color="{local:HslColor H=0, S=0, L=0.5}" />

<BoxView Color="{local:HslColor A=0.5}" />


</StackLayout>
</ContentPage>
Notice that when HslColorExtension is an XML tag, the four properties are set as attributes, but when it appears
between curly braces, the four properties are separated by commas without quotation marks. The default values
for H , S , and L are 0, and the default value of A is 1, so those properties can be omitted if you want them set
to default values. The last example shows an example where the luminosity is 0, which normally results in black,
but the alpha channel is 0.5, so it is half transparent and appears gray against the white background of the page:

A Markup Extension for Accessing Bitmaps


The argument to ProvideValue is an object that implements the IServiceProvider interface, which is defined in
the .NET System namespace. This interface has one member, a method named GetService with a Type
argument.
The ImageResourceExtension class shown below shows one possible use of IServiceProvider and GetService to
obtain an IXmlLineInfoProvider object that can provide line and character information indicating where a
particular error was detected. In this case, an exception is raised when the Source property has not been set:
[ContentProperty("Source")]
class ImageResourceExtension : IMarkupExtension<ImageSource>
{
public string Source { set; get; }

public ImageSource ProvideValue(IServiceProvider serviceProvider)


{
if (String.IsNullOrEmpty(Source))
{
IXmlLineInfoProvider lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider))
as IXmlLineInfoProvider;
IXmlLineInfo lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new
XmlLineInfo();
throw new XamlParseException("ImageResourceExtension requires Source property to be set",
lineInfo);
}

string assemblyName = GetType().GetTypeInfo().Assembly.GetName().Name;


return ImageSource.FromResource(assemblyName + "." + Source,
typeof(ImageResourceExtension).GetTypeInfo().Assembly);
}

object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)


{
return (this as IMarkupExtension<ImageSource>).ProvideValue(serviceProvider);
}
}

ImageResourceExtension is helpful when a XAML file needs to access an image file stored as an embedded
resource in the .NET Standard library project. It uses the Source property to call the static
ImageSource.FromResource method. This method requires a fully-qualified resource name, which consists of the
assembly name, the folder name, and the filename separated by periods. The second argument to the
ImageSource.FromResource method provides the assembly name, and is only required for release builds on UWP.
Regardless, ImageSource.FromResource must be called from the assembly that contains the bitmap, which means
that this XAML resource extension cannot be part of an external library unless the images are also in that library.
(See the Embedded Images article for more information on accessing bitmaps stored as embedded resources.)
Although ImageResourceExtension requires the Source property to be set, the Source property is indicated in an
attribute as the content property of the class. This means that the Source= part of the expression in curly braces
can be omitted. In the Image Resource Demo page, the Image elements fetch two images using the folder name
and the filename separated by periods:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.ImageResourceDemoPage"
Title="Image Resource Demo">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<Image Source="{local:ImageResource Images.SeatedMonkey.jpg}"


Grid.Row="0" />

<Image Source="{local:ImageResource Images.FacePalm.jpg}"


Grid.Row="1" />

</Grid>
</ContentPage>
Here's the program running:

Service Providers
By using the IServiceProvider argument to ProvideValue , XAML markup extensions can get access to helpful
information about the XAML file in which they're being used. But to use the IServiceProvider argument
successfully, you need to know what kind of services are available in particular contexts. The best way to get an
understanding of this feature is by studying the source code of existing XAML markup extensions in the
MarkupExtensions folder in the Xamarin.Forms repository on GitHub. Be aware that some types of services are
internal to Xamarin.Forms.
In some XAML markup extensions, this service might be useful:

IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as


IProvideValueTarget;

The IProvideValueTarget interface defines two properties, TargetObject and TargetProperty . When this
information is obtained in the ImageResourceExtension class, TargetObject is the Image and TargetProperty is a
BindableProperty object for the Source property of Image . This is the property on which the XAML markup
extension has been set.
The GetService call with an argument of typeof(IProvideValueTarget) actually returns an object of type
SimpleValueTargetProvider , which is defined in the Xamarin.Forms.Xaml.Internals namespace. If you cast the
return value of GetService to that type, you can also access a ParentObjects property, which is an array that
contains the Image element, the Grid parent, and the ImageResourceDemoPage parent of the Grid .

Conclusion
XAML markup extensions play a vital role in XAML by extending the ability to set attributes from a variety of
sources. Moreover, if the existing XAML markup extensions don't provide exactly what you need, you can also
write your own.

Related Links
Markup Extensions (sample)
XAML markup extensions chapter from Xamarin.Forms book
XAML Hot Reload for Xamarin.Forms (Preview)
3 minutes to read • Edit Online

XAML Hot Reload plugs into your existing workflow to increase your productivity and save you time. Without
XAML Hot Reload, you have to build and deploy your app every time you want to see a XAML change. With Hot
Reload, when you save your XAML file the changes are reflected live in your running app. In addition, your
navigation state and data will be maintained, enabling you to quickly iterate on your UI without losing your place in
the app. Therefore, with XAML Hot Reload, you'll spend less time rebuilding and deploying your apps to validate
UI changes.

NOTE
If you're writing a WPF or UWP app, see XAML Hot Reload for UWP and WPF.
XAML Hot Reload for Xamarin.Forms does not currently work for Xamarin.Forms UWP projects.

System requirements
IDE/FRAMEWORK VERSION REQUIRED

Visual Studio 2019 16.4 or greater

Visual Studio 2019 for Mac 8.4 or greater

Xamarin.Forms 4.1 or greater

Use XAML Hot Reload for Xamarin.Forms


No additional installation or setup is required to use XAML Hot Reload. It's built into Visual Studio and can be
enabled in the IDE settings. Once enabled, you can start using XAML Hot Reload by debugging your app on an
emulator, simulator, or physical device. Currently, XAML Hot Reload only works when debugging on iOS or
Android.
On Windows, XAML Hot Reload can be enabled by checking the Enable Xamarin Hot Reload checkbox at Tools
> Options > Xamarin > Hot Reload.
On a Mac, XAML Hot Reload can be enabled by checking the Enable Xamarin Hot Reload checkbox at Visual
Studio > Preferences > Projects > Xamarin Hot Reload.

Resilient reloading
If you make a change that XAML Hot Reload can't reload, it will show you an error message using IntelliSense.
These changes, known as rude edits, include mistyping your XAML or wiring a control to an event handler that
doesn't exist. Even with a rude edit, you can continue to reload without restarting the app - make another change
elsewhere in the XAML file and hit save. The rude edit won't be reloaded, but your other changes will continue to
be applied.

Known limitations
You can't add, remove, or rename files or NuGet packages during a XAML Hot Reload session. If you add or
remove a file or NuGet package, rebuild and redeploy your app to continue using XAML Hot Reload.
Set the linker to Don't Link for the best experience. The Link SDK only setting works most of the time, but it
may fail in certain cases.
Debugging on a physical iPhone requires the interpreter to use XAML Hot Reload. To do this, open the project
settings, select the iOS Build tab, and ensure Enable the Mono interpreter setting is enabled. You may need
to change the Platform option at the top of the property page to iPhone.
Any references created by assigning a control to another field or property using its x:Name value won't be
reloaded.
Updating the visual hierarchy of your Shell application in AppShell.xaml can cause issues maintaining the
state of your application. Rebuild the app to continue reloading.
XAML Hot Reload can't reload C# code, including event handlers, custom controls, page code-behind, and
additional classes.
Does not work on other Xamarin.Forms-supported platforms (such as mac OS or UWP ).

Migrate from the private preview


If you were part of the private preview, your XAML Hot Reload extension will be automatically updated when
Visual Studio updates. If you choose not to update Visual Studio, you can continue using the current version of
XAML Hot Reload, but you won't receive any further updates through the private preview extension feed.

Troubleshooting
If XAML Hot Reload fails to initialize:
Update your Xamarin.Forms version.
Ensure you are on the latest version of the IDE.
Set your Android or iOS Linker settings to Don't Link in the project's build settings.
If nothing happens upon saving your XAML file, ensure that Hot Reload is enabled in the IDE.
If you're debugging on a physical iPhone and your app becomes unresponsive, check that the interpreter is
enabled. To turn it on, open the project settings, select the iOS Build tab, and check the Enable the Mono
interpreter setting.
To report a bug, use the feedback tool at the Help > Send Feedback > Report a Problem menu on Windows,
and the Help > Report a Problem menu on a Mac.
Xamarin.Forms XAML Toolbox
2 minutes to read • Edit Online

Visual Studio 2017 version 15.8 and Visual Studio for Mac 7.6 now have a Toolbox available while editing
Xamarin.Forms XAML files. The toolbox contains all the built-in Xamarin.Forms controls and layouts, which can be
dragged into the XAML editor.
Visual Studio
Visual Studio for Mac
In Visual Studio 2017, open a Xamarin.Forms XAML file for editing. The toolbox can be shown by pressing Ctrl +
W, X on the keyboard, or choosing the View > Toolbox menu item.

The toolbox can be hidden and docked like other panes in Visual Studio 2017, using the icons in the top-right or
the context menu. The Xamarin.Forms XAML toolbox has custom view options that can be changed by right-
clicking on each section. Toggle the List View option to switch between the list and compact views:

When a Xamarin.Forms XAML file is opened for editing, drag any control or layout from the toolbox into the file,
then take advantage of Intellisense to customize the user interface.
XAML Previewer for Xamarin.Forms
2 minutes to read • Edit Online

See your Xamarin.Forms layouts rendered as you type

Overview
The XAML Previewer shows you how your Xamarin.Forms XAML page will look on iOS and Android. When you
make changes to your XAML, you'll see them previewed immediately alongside your code. The XAML Previewer is
available in Visual Studio and Visual Studio for Mac.

Getting started
Visual Studio 2019
You can open the XAML Previewer by clicking the arrows on the split view pane. If you want to change the default
split view behavior, use the Tools > Options > Xamarin > Forms Previewer dialog. In this dialog, you can select
the default document view and the split orientation.

When you open a XAML file, the editor will open either full-sized or next to the previewer, based on the settings
selected in the Tools > Options > Xamarin > Forms Previewer dialog. However, the split can be changed for
each file in the editor window.
XAML preview controls
Choose whether you want to see your code, the XAML Previewer, or both by selecting these buttons on the split
view pane. The middle button swaps what side the Previewer and your code are on:

You can change whether the screen is split vertically or horizontally, or collapse one pane altogether:

Visual Studio for Mac


The Preview button is displayed on the editor when you open a XAML page. Show or hide the Previewer by
pressing the Preview or Split buttons in the bottom-left of any XAML document window:
NOTE
In older versions of Visual Studio for Mac, the Preview button was located in the top-right of the window.

XAML previewer options


The options along the top of the preview pane are:
Android – show the Android version of the screen
iOS – show the iOS version of the screen (Note: If you're using Visual Studio on Windows, you must be paired
to a Mac to use this mode)
Device - Drop-down list of Android or iOS devices including resolution and screen size
Portrait (icon) – uses portrait orientation for the preview
Landscape (icon) – uses landscape orientation for the preview

Detect design mode


The static DesignMode.IsDesignModeEnabled property tells you if the application is running in the previewer. Using it,
you can specify code that will only execute when the application is or isn't running in the previewer:

if (DesignMode.IsDesignModeEnabled)
{
// Previewer only code
}

if (!DesignMode.IsDesignModeEnabled)
{
// Don't run in the Previewer
}

This property is useful if you initialize a library in your page constructor that fails to run at design time.
Troubleshooting
Check the issues below and the Xamarin Forums, if the Previewer isn't working.
XAML Previewer isn't showing or shows an error
It can take some time for the Previewer to start up - you'll see "Initializing Render" until it's ready.
Try closing and reopening the XAML file.
Ensure that your App class has a parameterless constructor.
Check your Xamarin.Forms version - it has to be at least Xamarin.Forms 3.6. You can update to the latest
Xamarin.Forms version through NuGet.
Check your JDK installation - previewing Android requires at least JDK 8.
Try wrapping any initialized classes in the page's C# code behind in if (!DesignMode.IsDesignModeEnabled) .
Custom controls aren't rendering
Try building your project. The previewer shows the control's base class if it fails to render the control, or if the
control's creator opted-out of design time rendering. For more information, see Render Custom Controls in the
XAML Previewer.
Use Design Time Data with the XAML Previewer
3 minutes to read • Edit Online

Some layouts are hard to visualize without data. Use these tips to make the most out of previewing your data -
heavy pages in the XAML Previewer.

Design time data basics


Design time data is fake data you set to make your controls easier to visualize in the XAML Previewer. To get
started, add the following lines of code to the header of your XAML page:

xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"

After adding the namespaces, you can put d: in front of any attribute or control to show it in the XAML
Previewer. Elements with d: aren't shown at runtime.
For example, you can add text to a label that usually has data bound to it.

<Label Text="{Binding Name}" d:Text="Name!" />

In this example, without d:Text , the XAML Previewer would show nothing for the label. Instead, it shows "Name!"
where the label will have real data at runtime.
You can use d: with any attribute for a Xamarin.Forms control, like colors, font sizes, and spacing. You can even
add it to the control itself:

<d:Button Text="Design Time Button" />


In this example, the button only appears at design time. Use this method to put a placeholder in for a custom
control not supported by the XAML Previewer.

Preview images at design time


You can set a design time Source for images that are bound to the page or loaded in dynamically. In your Android
project, add the image you want to show in the XAML Previewer to the Resources > Drawable folder. In your iOS
project, add the image to the Resources folder. You can then show that image in the XAML Previewer at design
time:

<Image Source={Binding ProfilePicture} d:Source="DesignTimePicture.jpg" />


Design time data for ListViews
ListViews are a popular way to display data in a mobile app. However, they're difficult to visualize without real data.
To use design time data with them, you have to create a design time array to use as an ItemsSource. The XAML
Previewer displays what is in that array in your ListView at design time.

<StackLayout>
<ListView ItemsSource="{Binding Items}">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Item One</x:String>
<x:String>Item Two</x:String>
<x:String>Item Three</x:String>
</x:Array>
</d:ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding ItemName}"
d:Text="{Binding .}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
This example will show a ListView of three TextCells in the XAML Previewer. You can change x:String to an
existing data model in your project.
You can also create an array of data objects. For example, public properties of a Monkey data object can be
constructed as design time data:

namespace Monkeys.Models
{
public class Monkey
{
public string Name { get; set; }
public string Location { get; set; }
}
}

To use the class in XAML you will need to import the namespace in the root node:

xmlns:models="clr-namespace:Monkeys.Models"

<StackLayout>
<ListView ItemsSource="{Binding Items}">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type models:Monkey}">
<models:Monkey Name="Baboon" Location="Africa and Asia"/>
<models:Monkey Name="Capuchin Monkey" Location="Central and South America"/>
<models:Monkey Name="Blue Monkey" Location="Central and East Africa"/>
</x:Array>
</d:ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Monkey">
<TextCell Text="{Binding Name}"
Detail="{Binding Location}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>

The benefit here is that you can bind to the actual model that you plan to use.

Alternative: Hardcode a static ViewModel


If you don't want to add design time data to individual controls, you can set up a mock data store to bind to your
page. Refer to James Montemagno's blog post on adding design-time data to see how to bind to a static
ViewModel in XAML.
Troubleshooting
Requirements
Design time data requires a minimum version of Xamarin.Forms 3.6.
IntelliSense shows squiggly lines under my design time data
This is a known issue and will be fixed in an upcoming version of Visual Studio. The project will still build without
errors.
The XAML Previewer stopped working
Try closing and reopening the XAML file, and cleaning and rebuilding your project.
Render Custom Controls in the XAML Previewer
2 minutes to read • Edit Online

Custom controls sometimes don't work as expected in the XAML Previewer. Use the guidance in this article to
understand the limitations of previewing your custom controls.

Basic Preview mode


Even if you haven't built your project, the XAML Previewer will render your pages. Until you build, any control that
relies on code-behind will show its base Xamarin.Forms type. When your project is built, the XAML Previewer will
try to show custom controls with design time rendering enabled. If the render fails, it will show the base
Xamarin.Forms type.

Enable design time rendering for custom controls


If you make your own custom controls, or use controls from a third-party library, the Previewer might display
them incorrectly. Custom controls must opt in to design time rendering to appear in the previewer, whether you
wrote the control or imported it from a library. With controls you've created, add the [DesignTimeVisible(true)] to
your control's class to show it in the Previewer:

namespace MyProject
{
[DesignTimeVisible(true)]
public class MyControl : BaseControl
{
// Your control's code here
}

Use James Montemagno's ImageCirclePlugin's base class as an example.

SkiaSharp controls
Currently, SkiaSharp controls are only supported when you're previewing on iOS. They won't render on the
Android preview.

Troubleshooting
Check your Xamarin.Forms version
Make sure you have at least Xamarin.Forms 3.6 installed. You can update your Xamarin.Forms version on NuGet.
Even with [DesignTimeVisible(true)] , my custom control isn't rendering properly.
Custom controls that rely heavily on code-behind or backend data don't always work in the XAML Previewer. You
can try:
Moving the control so it doesn't initialize if design mode is enabled
Setting up design time data to show fake data from the backend
The XAML Previewer shows the error "Custom Controls aren't rendering properly"
Try cleaning and rebuilding your project, or closing and reopening the XAML file.
XAML Namespaces in Xamarin.Forms
3 minutes to read • Edit Online

XAML uses the xmlns XML attribute for namespace declarations. This article introduces the XAML namespace
syntax, and demonstrates how to declare a XAML namespace to access a type.

Overview
There are two XAML namespace declarations that are always within the root element of a XAML file. The first
defines the default namespace, as shown in the following XAML code example:

xmlns="http://xamarin.com/schemas/2014/forms"

The default namespace specifies that elements defined within the XAML file with no prefix refer to Xamarin.Forms
classes, such as ContentPage .
The second namespace declaration uses the x prefix, as shown in the following XAML code example:

xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

XAML uses prefixes to declare non-default namespaces, with the prefix being used when referencing types within
the namespace. The x namespace declaration specifies that elements defined within the XAML with a prefix of
x are used for elements and attributes that are intrinsic to XAML (specifically the 2009 XAML specification).

The following table outlines the x namespace attributes supported by Xamarin.Forms:

CONSTRUCT DESCRIPTION

x:Arguments Specifies constructor arguments for a non-default constructor,


or for a factory method object declaration.

x:Class Specifies the namespace and class name for a class defined in
XAML. The class name must match the class name of the
code-behind file. Note that this construct can only appear in
the root element of a XAML file.

x:DataType Specifies the type of the object that the XAML element, and
it's children, will bind to.

x:FactoryMethod Specifies a factory method that can be used to initialize an


object.

x:FieldModifier Specifies the access level for generated fields for named XAML
elements.

x:Key Specifies a unique user-defined key for each resource in a


ResourceDictionary . The key's value is used to retrieve the
XAML resource, and is typically used as the argument for the
StaticResource markup extension.
CONSTRUCT DESCRIPTION

x:Name Specifies a runtime object name for the XAML element.


Setting x:Name is similar to declaring a variable in code.

x:TypeArguments Specifies the generic type arguments to the constructor of a


generic type.

For more information about the x:DataType attribute, see Compiled Bindings. For more information about the
x:FieldModifier attribute, see Field Modifiers. For more information about the x:Arguments , x:FactoryMethod ,
and x:TypeArguments attributes, see Passing Arguments in XAML.

NOTE
In addition to the namespace attributes listed above, Xamarin.Forms also includes markup extensions that can be consumed
through the x namespace prefix. For more information, see Consuming XAML Markup Extensions.

In XAML, namespace declarations inherit from parent element to child element. Therefore, when defining a
namespace in the root element of a XAML file, all elements within that file inherit the namespace declaration.

Declaring Namespaces for Types


Types can be referenced in XAML by declaring a XAML namespace with a prefix, with the namespace declaration
specifying the Common Language Runtime (CLR ) namespace name, and optionally an assembly name. This is
achieved by defining values for the following keywords within the namespace declaration:
clr-namespace: or using: – the CLR namespace declared within the assembly that contains the types to
expose as XAML elements. This keyword is required.
assembly= – the assembly that contains the referenced CLR namespace. This value is the name of the
assembly, without the file extension. The path to the assembly should be established as a reference in the
project file that contains the XAML file that will reference the assembly. This keyword can be omitted if the clr-
namespace value is within the same assembly as the application code that's referencing the types.
Note that the character separating the clr-namespace or using token from its value is a colon, whereas the
character separating the assembly token from its value is an equal sign. The character to use between the two
tokens is a semicolon.
The following code example shows a XAML namespace declaration:

<ContentPage ... xmlns:local="clr-namespace:HelloWorld" ...>


...
</ContentPage>

Alternatively, this can be written as:

<ContentPage ... xmlns:local="using:HelloWorld" ...>


...
</ContentPage>

The local prefix is a convention used to indicate that the types within the namespace are local to the application.
Alternatively, if the types are in a different assembly, the assembly name should also be defined in the namespace
declaration, as demonstrated in the following XAML code example:
<ContentPage ... xmlns:behaviors="clr-namespace:Behaviors;assembly=BehaviorsLibrary" ...>
...
</ContentPage>

The namespace prefix is then specified when declaring an instance of a type from an imported namespace, as
demonstrated in the following XAML code example:

<ListView ...>
<ListView.Behaviors>
<behaviors:EventToCommandBehavior EventName="ItemSelected" ... />
</ListView.Behaviors>
</ListView>

For information about defining a custom namespace schema, see XAML Custom Namespace Schemas.

Summary
This article introduced the XAML namespace syntax, and demonstrated how to declare a XAML namespace to
access a type. XAML uses the xmlns XML attribute for namespace declarations, and types can be referenced in
XAML by declaring a XAML namespace with a prefix.

Related Links
Passing Arguments in XAML
XAML Custom Namespace Schemas in
Xamarin.Forms
3 minutes to read • Edit Online

Download the sample


Types in a library can be referenced in XAML by declaring a XAML namespace for the library, with the namespace
declaration specifying the Common Language Runtime (CLR ) namespace name and an assembly name:

<ContentPage ...
xmlns:controls="clr-namespace:MyCompany.Controls;assembly="MyCompany.Controls">
...
</ContentPage>

However, specifying a CLR namespace and assembly name in a xmlns definition can be awkward and error prone.
In addition, multiple XAML namespace declarations may be required if the library contains types in multiple
namespaces.
An alternative approach is to define a custom namespace schema, such as http://mycompany.com/schemas/controls ,
that maps to one or more CLR namespaces. This enables a single XAML namespace declaration to reference all
the types in an assembly, even if they are in different namespaces. It also enables a single XAML namespace
declaration to reference types in multiple assemblies.
For more information about XAML namespaces, see XAML Namespaces in Xamarin.Forms.

Defining a custom namespace schema


The sample application contains a library that exposes some simple controls, such as CircleButton :

using Xamarin.Forms;

namespace MyCompany.Controls
{
public class CircleButton : Button
{
...
}
}

All the controls in the library reside in the MyCompany.Controls namespace. These controls can be exposed to a
calling assembly through a custom namespace schema.
A custom namespace schema is defined with the XmlnsDefinitionAttribute class, which specifies the mapping
between a XAML namespace and one or more CLR namespaces. The XmlnsDefinitionAttribute takes two
arguments: the XAML namespace name, and the CLR namespace name. The XAML namespace name is stored in
the XmlnsDefinitionAttribute.XmlNamespace property, and the CLR namespace name is stored in the
XmlnsDefinitionAttribute.ClrNamespace property.
NOTE
The XmlnsDefinitionAttribute class also has a property named AssemblyName , which can be optionally set to the name
of the assembly. This is only required when a CLR namespace referenced from a XmlnsDefinitionAttribute is in a external
assembly.

The XmlnsDefinitionAttribute should be defined at the assembly level in the project that contains the CLR
namespaces that will be mapped in the custom namespace schema. The following example shows the
AssemblyInfo.cs file from the sample application:

using Xamarin.Forms;
using MyCompany.Controls;

[assembly: Preserve]
[assembly: XmlnsDefinition("http://mycompany.com/schemas/controls", "MyCompany.Controls")]

This code creates a custom namespace schema that maps the http://mycompany.com/schemas/controls URL to the
MyCompany.Controls CLR namespace. In addition, the Preserve attribute is specified on the assembly, to ensure
that the linker preserves all the types in the assembly.

IMPORTANT
The Preserve attribute should be applied to classes in the assembly that are mapped through the custom namespace
schema, or applied to the entire assembly.

The custom namespace schema can then be used for type resolution in XAML files.

Consuming a custom namespace schema


To consume types from the custom namespace schema, the XAML compiler requires that there's a code reference
from the assembly that consumes the types, to the assembly that defines the types. This can be accomplished by
adding a class containing an Init method to the assembly that defines the types that will be consumed through
XAML:

namespace MyCompany.Controls
{
public static class Controls
{
public static void Init()
{
}
}
}

The Init method can then be called from the assembly that consumes types from the custom namespace
schema:
using Xamarin.Forms;
using MyCompany.Controls;

namespace CustomNamespaceSchemaDemo
{
public partial class MainPage : ContentPage
{
public MainPage()
{
Controls.Init();
InitializeComponent();
}
}
}

WARNING
Failure to include such a code reference will result in the XAML compiler being unable to locate the assembly containing the
custom namespace schema types.

To consume the CircleButton control, a XAML namespace is declared, with the namespace declaration specifying
the custom namespace schema URL:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="http://mycompany.com/schemas/controls"
x:Class="CustomNamespaceSchemaDemo.MainPage">
<StackLayout Margin="20,35,20,20">
...
<controls:CircleButton Text="+"
BackgroundColor="Fuchsia"
BorderColor="Black"
CircleDiameter="100" />
<controls:CircleButton Text="-"
BackgroundColor="Teal"
BorderColor="Silver"
CircleDiameter="70" />
...
</StackLayout>
</ContentPage>

CircleButton instances can then be added to the ContentPage by declaring them with the controls namespace
prefix.
To find the custom namespace schema types, Xamarin.Forms will search referenced assemblies for
XmlnsDefinitionAttribute instances. If the xmlns attribute for an element in a XAML file matches the
XmlNamespace property value in a XmlnsDefinitionAttribute , Xamarin.Forms will attempt to use the
XmlnsDefinitionAttribute.ClrNamespace property value for resolution of the type. If type resolution fails,
Xamarin.Forms will continue to attempt type resolution based on any additional matching
XmlnsDefinitionAttribute instances.

The result is that two CircleButton instances are displayed:


Related links
Custom Namespace Schemas (sample)
XAML Namespace Recommended Prefixes
XAML Namespaces in Xamarin.Forms
XAML Namespace Recommended Prefixes in
Xamarin.Forms
2 minutes to read • Edit Online

The XmlnsPrefixAttribute class can be used by control authors to specify a recommended prefix to associate with
a XAML namespace, for XAML usage. The prefix is useful when supporting object tree serialization to XAML, or
when interacting with a design environment that has XAML editing features. For example:
XAML text editors could use the XmlnsPrefixAttribute as a hint for an initial XAML namespace xmlns
mapping.
XAML design environments could use the XmlnsPrefixAttribute to add mappings to the XAML when dragging
objects out of a toolbox and onto a visual design surface.
Recommended namespace prefixes should be defined at the assembly level with the XmlnsPrefixAttribute
constructor, which takes two arguments: a string that specifies the identifier of a XAML namespace, and a string
that specifies a recommended prefix:

[assembly: XmlnsPrefix("http://xamarin.com/schemas/2014/forms", "xf")]

Prefixes should use short strings, because the prefix is typically applied to all serialized elements that come from
the XAML namespace. Therefore, the prefix string length can have a noticeable effect on the size of the serialized
XAML output.

NOTE
More than one XmlnsPrefixAttribute can be applied to an assembly. For example, if you have an assembly that defines
types for more than one XAML namespace, you could define different prefix values for each XAML namespace.

Related links
XAML Custom Namespace Schemas
XAML Namespaces in Xamarin.Forms
Xamarin.Forms Bindable Properties
7 minutes to read • Edit Online

Download the sample


Bindable properties extend CLR property functionality by backing a property with a BindableProperty type,
instead of backing a property with a field. The purpose of bindable properties is to provide a property system that
supports data binding, styles, templates, and values set through parent-child relationships. In addition, bindable
properties can provide default values, validation of property values, and callbacks that monitor property changes.
Properties should be implemented as bindable properties to support one or more of the following features:
Acting as a valid target property for data binding.
Setting the property through a style.
Providing a default property value that's different from the default for the type of the property.
Validating the value of the property.
Monitoring property changes.
Examples of Xamarin.Forms bindable properties include Label.Text , Button.BorderRadius , and
StackLayout.Orientation . Each bindable property has a corresponding public static readonly property of type
BindableProperty that is exposed on the same class and that is the identifier of the bindable property. For
example, the corresponding bindable property identifier for the Label.Text property is Label.TextProperty .

Create a bindable property


The process for creating a bindable property is as follows:
1. Create a BindableProperty instance with one of the BindableProperty.Create method overloads.
2. Define property accessors for the BindableProperty instance.

Note that all BindableProperty instances must be created on the UI thread. This means that only code that runs on
the UI thread can get or set the value of a bindable property. However, BindableProperty instances can be
accessed from other threads by marshaling to the UI thread with the Device.BeginInvokeOnMainThread method.
Create a property
To create a BindableProperty instance, the containing class must derive from the BindableObject class. However,
the BindableObject class is high in the class hierarchy, so the majority of classes used for user interface
functionality support bindable properties.
A bindable property can be created by declaring a public static readonly property of type BindableProperty .
The bindable property should be set to the returned value of one of the BindableProperty.Create method
overloads. The declaration should be within the body of BindableObject derived class, but outside of any member
definitions.
At a minimum, an identifier must be specified when creating a BindableProperty , along with the following
parameters:
The name of the BindableProperty .
The type of the property.
The type of the owning object.
The default value for the property. This ensures that the property always returns a particular default value
when it is unset, and it can be different from the default value for the type of the property. The default value will
be restored when the ClearValue method is called on the bindable property.

The following code shows an example of a bindable property, with an identifier and values for the four required
parameters:

public static readonly BindableProperty EventNameProperty =


BindableProperty.Create ("EventName", typeof(string), typeof(EventToCommandBehavior), null);

This creates a BindablePropertyinstance named EventName , of type string . The property is owned by the
EventToCommandBehavior class, and has a default value of null . The naming convention for bindable properties is
that the bindable property identifier must match the property name specified in the Create method, with
"Property" appended to it. Therefore, in the example above, the bindable property identifier is EventNameProperty .
Optionally, when creating a BindableProperty instance, the following parameters can be specified:
The binding mode. This is used to specify the direction in which property value changes will propagate. In the
default binding mode, changes will propagate from the source to the target.
A validation delegate that will be invoked when the property value is set. For more information, see Validation
callbacks.
A property changed delegate that will be invoked when the property value has changed. For more information,
see Detect property changes.
A property changing delegate that will be invoked when the property value will change. This delegate has the
same signature as the property changed delegate.
A coerce value delegate that will be invoked when the property value has changed. For more information, see
Coerce value callbacks.
A Func that's used to initialize a default property value. For more information, see Create a default value with
a Func.
Create accessors
Property accessors are required to use property syntax to access a bindable property. The Get accessor should
return the value that's contained in the corresponding bindable property. This can be achieved by calling the
GetValue method, passing in the bindable property identifier on which to get the value, and then casting the result
to the required type. The Set accessor should set the value of the corresponding bindable property. This can be
achieved by calling the SetValue method, passing in the bindable property identifier on which to set the value,
and the value to set.
The following code example shows accessors for the EventName bindable property:

public string EventName


{
get { return (string)GetValue (EventNameProperty); }
set { SetValue (EventNameProperty, value); }
}

Consume a bindable property


Once a bindable property has been created, it can be consumed from XAML or code. In XAML, this is achieved by
declaring a namespace with a prefix, with the namespace declaration indicating the CLR namespace name, and
optionally, an assembly name. For more information, see XAML Namespaces.
The following code example demonstrates a XAML namespace for a custom type that contains a bindable
property, which is defined within the same assembly as the application code that's referencing the custom type:
<ContentPage ... xmlns:local="clr-namespace:EventToCommandBehavior" ...>
...
</ContentPage>

The namespace declaration is used when setting the EventName bindable property, as demonstrated in the
following XAML code example:

<ListView ...>
<ListView.Behaviors>
<local:EventToCommandBehavior EventName="ItemSelected" ... />
</ListView.Behaviors>
</ListView>

The equivalent C# code is shown in the following code example:

var listView = new ListView ();


listView.Behaviors.Add (new EventToCommandBehavior
{
EventName = "ItemSelected",
...
});

Advanced scenarios
When creating a BindableProperty instance, there are a number of optional parameters that can be set to enable
advanced bindable property scenarios. This section explores these scenarios.
Detect property changes
A static property-changed callback method can be registered with a bindable property by specifying the
propertyChanged parameter for the BindableProperty.Create method. The specified callback method will be
invoked when the value of the bindable property changes.
The following code example shows how the EventName bindable property registers the OnEventNameChanged
method as a property-changed callback method:

public static readonly BindableProperty EventNameProperty =


BindableProperty.Create (
"EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
...

static void OnEventNameChanged (BindableObject bindable, object oldValue, object newValue)


{
// Property changed implementation goes here
}

In the property-changed callback method, the BindableObject parameter is used to denote which instance of the
owning class has reported a change, and the values of the two object parameters represent the old and new
values of the bindable property.
Validation callbacks
A static validation callback method can be registered with a bindable property by specifying the validateValue
parameter for the BindableProperty.Create method. The specified callback method will be invoked when the value
of the bindable property is set.
The following code example shows how the Angle bindable property registers the IsValidValue method as a
validation callback method:

public static readonly BindableProperty AngleProperty =


BindableProperty.Create ("Angle", typeof(double), typeof(HomePage), 0.0, validateValue: IsValidValue);
...

static bool IsValidValue (BindableObject view, object value)


{
double result;
bool isDouble = double.TryParse (value.ToString (), out result);
return (result >= 0 && result <= 360);
}

Validation callbacks are provided with a value, and should return true if the value is valid for the property,
otherwise false . An exception will be raised if a validation callback returns false , which should be handled by
the developer. A typical use of a validation callback method is constraining the values of integers or doubles when
the bindable property is set. For example, the IsValidValue method checks that the property value is a double
within the range 0 to 360.
Coerce value callbacks
A static coerce value callback method can be registered with a bindable property by specifying the coerceValue
parameter for the BindableProperty.Create method. The specified callback method will be invoked when the value
of the bindable property changes.
Coerce value callbacks are used to force a reevaluation of a bindable property when the value of the property
changes. For example, a coerce value callback can be used to ensure that the value of one bindable property is not
greater than the value of another bindable property.
The following code example shows how the Angle bindable property registers the CoerceAngle method as a
coerce value callback method:

public static readonly BindableProperty AngleProperty = BindableProperty.Create (


"Angle", typeof(double), typeof(HomePage), 0.0, coerceValue: CoerceAngle);
public static readonly BindableProperty MaximumAngleProperty = BindableProperty.Create (
"MaximumAngle", typeof(double), typeof(HomePage), 360.0);
...

static object CoerceAngle (BindableObject bindable, object value)


{
var homePage = bindable as HomePage;
double input = (double)value;

if (input > homePage.MaximumAngle)


{
input = homePage.MaximumAngle;
}
return input;
}

The CoerceAngle method checks the value of the MaximumAngle property, and if the Angle property value is
greater than it, it coerces the value to the MaximumAngle property value.
Create a default value with a Func
A Func can be used to initialize the default value of a bindable property, as demonstrated in the following code
example:
public static readonly BindableProperty SizeProperty =
BindableProperty.Create ("Size", typeof(double), typeof(HomePage), 0.0,
defaultValueCreator: bindable => Device.GetNamedSize (NamedSize.Large, (Label)bindable));

The defaultValueCreator parameter is set to a Func that invokes the Device.GetNamedSize method to return a
double that represents the named size for the font that is used on a Label on the native platform.

Related links
XAML Namespaces
Event To Command Behavior (sample)
Validation Callback (sample)
Coerce Value Callback (sample)
BindableProperty API
BindableObject API
Attached Properties
4 minutes to read • Edit Online

Download the sample


Attached properties enable an object to assign a value for a property that its own class doesn't define. For
example, child elements can use attached properties to inform their parent element of how they are to be
presented in the user interface. The Grid control allows the row and column of a child to be specified by setting
the Grid.Row and Grid.Column attached properties. Grid.Row and Grid.Column are attached properties because
they are set on elements that are children of a Grid , rather than on the Grid itself.
Bindable properties should be implemented as attached properties in the following scenarios:
When there's a need to have a property setting mechanism available for classes other than the defining class.
When the class represents a service that needs to be easily integrated with other classes.
For more information about bindable properties, see Bindable Properties.

Create an attached property


The process for creating an attached property is as follows:
1. Create a BindableProperty instance with one of the CreateAttached method overloads.
2. Provide static Get PropertyName and Set PropertyName methods as accessors for the attached property.
Create a property
When creating an attached property for use on other types, the class where the property is created does not have
to derive from BindableObject . However, the target property for accessors should be of, or derive from,
BindableObject .

An attached property can be created by declaring a public static readonly property of type BindableProperty .
The bindable property should be set to the returned value of one of the BindableProperty.CreateAttached method
overloads. The declaration should be within the body of the owning class, but outside of any member definitions.
The following code shows an example of an attached property:

public static readonly BindableProperty HasShadowProperty =


BindableProperty.CreateAttached ("HasShadow", typeof(bool), typeof(ShadowEffect), false);

This creates an attached property named HasShadow , of type bool . The property is owned by the ShadowEffect
class, and has a default value of false . The naming convention for attached properties is that the attached
property identifier must match the property name specified in the CreateAttached method, with "Property"
appended to it. Therefore, in the example above, the attached property identifier is HasShadowProperty .
For more information about creating bindable properties, including parameters that can be specified during
creation, see Create a bindable property.
Create accessors
Static Get PropertyName and Set PropertyName methods are required as accessors for the attached property,
otherwise the property system will be unable to use the attached property. The Get PropertyName accessor
should conform to the following signature:
public static valueType GetPropertyName(BindableObject target)

The Get PropertyName accessor should return the value that's contained in the corresponding BindableProperty
field for the attached property. This can be achieved by calling the GetValue method, passing in the bindable
property identifier on which to get the value, and then casting the resulting value to the required type.
The Set PropertyName accessor should conform to the following signature:

public static void SetPropertyName(BindableObject target, valueType value)

The Set PropertyName accessor should set the value of the corresponding BindableProperty field for the
attached property. This can be achieved by calling the SetValue method, passing in the bindable property
identifier on which to set the value, and the value to set.
For both accessors, the target object should be of, or derive from, BindableObject .
The following code example shows accessors for the HasShadow attached property:

public static bool GetHasShadow (BindableObject view)


{
return (bool)view.GetValue (HasShadowProperty);
}

public static void SetHasShadow (BindableObject view, bool value)


{
view.SetValue (HasShadowProperty, value);
}

Consume an attached property


Once an attached property has been created, it can be consumed from XAML or code. In XAML, this is achieved
by declaring a namespace with a prefix, with the namespace declaration indicating the Common Language
Runtime (CLR ) namespace name, and optionally an assembly name. For more information, see XAML
Namespaces.
The following code example demonstrates a XAML namespace for a custom type that contains an attached
property, which is defined within the same assembly as the application code that's referencing the custom type:

<ContentPage ... xmlns:local="clr-namespace:EffectsDemo" ...>


...
</ContentPage>

The namespace declaration is then used when setting the attached property on a specific control, as demonstrated
in the following XAML code example:

<Label Text="Label Shadow Effect" local:ShadowEffect.HasShadow="true" />

The equivalent C# code is shown in the following code example:

var label = new Label { Text = "Label Shadow Effect" };


ShadowEffect.SetHasShadow (label, true);

Consume an attached property with a style


Attached properties can also be added to a control by a style. The following XAML code example shows an
explicit style that uses the HasShadow attached property, that can be applied to Label controls:

<Style x:Key="ShadowEffectStyle" TargetType="Label">


<Style.Setters>
<Setter Property="local:ShadowEffect.HasShadow" Value="true" />
</Style.Setters>
</Style>

The Stylecan be applied to a Label by setting its Style property to the Style instance using the
StaticResource markup extension, as demonstrated in the following code example:

<Label Text="Label Shadow Effect" Style="{StaticResource ShadowEffectStyle}" />

For more information about styles, see Styles.

Advanced scenarios
When creating an attached property, there are a number of optional parameters that can be set to enable
advanced attached property scenarios. This includes detecting property changes, validating property values, and
coercing property values. For more information, see Advanced scenarios.

Related links
Bindable Properties
XAML Namespaces
Shadow Effect (sample)
BindableProperty API
BindableObject API
Resource Dictionaries
8 minutes to read • Edit Online

Download the sample


XAML resources are definitions of objects that can be shared and re-used throughout a Xamarin.Forms
application. These resource objects are stored in a resource dictionary.
A ResourceDictionary is a repository for resources that are used by a Xamarin.Forms application. Typical
resources that are stored in a ResourceDictionary include styles, control templates, data templates, colors, and
converters.
In XAML, resources that are stored in a ResourceDictionary can then be retrieved and applied to elements by
using the StaticResource markup extension. In C#, resources can also be defined in a ResourceDictionary and
then retrieved and applied to elements by using a string-based indexer. However, there's little advantage to using
a ResourceDictionary in C#, as shared objects can simply be stored as fields or properties, and accessed directly
without having to first retrieve them from a dictionary.

Create and consume a ResourceDictionary


Resources are defined in a ResourceDictionary that is then set to one of the following Resources properties:
The Resources property of any class that derives from Application
The Resources property of any class that derives from VisualElement

A Xamarin.Forms program contains only one class that derives from Application but often makes use of many
classes that derive from VisualElement , including pages, layouts, and controls. Any of these objects can have its
Resources property set to a ResourceDictionary . Choosing where to put a particular ResourceDictionary
impacts where the resources can be used:
Resources in a ResourceDictionary that is attached to a view such as Button or Label can only be applied to
that particular object, so this is not very useful.
Resources in a ResourceDictionary attached to a layout such as StackLayout or Grid can be applied to the
layout and all the children of that layout.
Resources in a ResourceDictionary defined at the page level can be applied to the page and to all its children.
Resources in a ResourceDictionary defined at the application level can be applied throughout the application.
The following XAML shows resources defined in an application level ResourceDictionary in the App.xaml file
created as part of the standard Xamarin.Forms program:
<Application ...>
<Application.Resources>
<ResourceDictionary>
<Color x:Key="PageBackgroundColor">Yellow</Color>
<Color x:Key="HeadingTextColor">Black</Color>
<Color x:Key="NormalTextColor">Blue</Color>
<Style x:Key="LabelPageHeadingStyle" TargetType="Label">
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

This ResourceDictionary defines three Color resources and a Style resource. For more information about the
App class, see App Class.
Beginning in Xamarin.Forms 3.0, the explicit ResourceDictionary tags are not required. The ResourceDictionary
object is created automatically, and you can insert the resources directly between the Resources property-
element tags:

<Application ...>
<Application.Resources>
<Color x:Key="PageBackgroundColor">Yellow</Color>
<Color x:Key="HeadingTextColor">Black</Color>
<Color x:Key="NormalTextColor">Blue</Color>
<Style x:Key="LabelPageHeadingStyle" TargetType="Label">
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
</Style>
</Application.Resources>
</Application>

Each resource has a key that is specified using the x:Key attribute, which becomes it dictionary key in the
ResourceDictionary . The key is used to retrieve a resource from the ResourceDictionary by the StaticResource
markup extension, as demonstrated in the following XAML code example that shows additional resources
defined within the StackLayout :
<StackLayout Margin="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="LabelNormalStyle" TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource NormalTextColor}" />
</Style>
<Style x:Key="MediumBoldText" TargetType="Button">
<Setter Property="FontSize" Value="Medium" />
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
<Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries."
Margin="10,20,10,0"
Style="{StaticResource LabelNormalStyle}" />
<Button Text="Navigate"
Clicked="OnNavigateButtonClicked"
TextColor="{StaticResource NormalTextColor}"
Margin="0,20,0,0"
HorizontalOptions="Center"
Style="{StaticResource MediumBoldText}" />
</StackLayout>

The first Label instance retrieves and consumes the LabelPageHeadingStyle resource defined in the application
level ResourceDictionary , with the second Label instance retrieving and consuming the LabelNormalStyle
resource defined in the control level ResourceDictionary . Similarly, the Button instance retrieves and consumes
the NormalTextColor resource defined in the application level ResourceDictionary , and the MediumBoldText
resource defined in the control level ResourceDictionary . This results in the appearance shown in the following
screenshots:
NOTE
Resources that are specific to a single page shouldn't be included in an application level resource dictionary, as such
resources will then be parsed at application startup instead of when required by a page. For more information, see Reduce
the Application Resource Dictionary Size.

Override resources
When ResourceDictionary resources share x:Key attribute values, resources defined lower in the view hierarchy
will take precedence over those defined higher up. For example, setting the PageBackgroundColor resource to
Blue at the application level will be overridden by a page level PageBackgroundColor resource set to Yellow .
Similarly, a page level PageBackgroundColor resource will be overridden by a control level PageBackgroundColor
resource. This precedence is demonstrated by the following XAML code example:

<ContentPage ... BackgroundColor="{StaticResource PageBackgroundColor}">


<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="PageBackgroundColor">Blue</Color>
<Color x:Key="NormalTextColor">Yellow</Color>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="0,20,0,0">
...
<Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
<Label Text="This app demonstrates consuming resources that have been defined in resource
dictionaries."
Margin="10,20,10,0"
Style="{StaticResource LabelNormalStyle}" />
<Button Text="Navigate"
Clicked="OnNavigateButtonClicked"
TextColor="{StaticResource NormalTextColor}"
Margin="0,20,0,0"
HorizontalOptions="Center"
Style="{StaticResource MediumBoldText}" />
</StackLayout>
</ContentPage>

The original PageBackgroundColor and NormalTextColor instances, defined at the application level, are overridden
by the PageBackgroundColor and NormalTextColor instances defined at page level. Therefore, the page
background color becomes blue, and the text on the page becomes yellow, as demonstrated in the following
screenshots:
However, note that the background bar of the NavigationPage is still yellow, because the BarBackgroundColor
property is set to the value of the PageBackgroundColor resource defined in the application level
ResourceDictionary .

Here's another way to think about ResourceDictionary precedence: When the XAML parser encounters a
StaticResource , it searches for a matching key by traveling up through the visual tree, using the first match it
finds. If this search ends at the page and the key still hasn't been found, the XAML parser searches the
ResourceDictionary attached to the App object. If the key is still not found, an exception is raised.

Stand-alone resource dictionaries


A class derived from ResourceDictionary can also be in a separate stand-alone file. (More precisely, a class
derived from ResourceDictionary generally requires a pair of files because the resources are defined in a XAML
file but a code-behind file with an InitializeComponent call is also necessary.) The resultant file can then be
shared among applications.
To create such a file, add a new Content View or Content Page item to the project (but not a Content View or
Content Page with only a C# file). In both the XAML file and C# file, change the name of the base class from
ContentView or ContentPage to ResourceDictionary . In the XAML file, the name of the base class is the top-level
element.
The following XAML example shows a ResourceDictionary named MyResourceDictionary :
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceDictionaryDemo.MyResourceDictionary">
<DataTemplate x:Key="PersonDataTemplate">
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Name}" TextColor="{StaticResource NormalTextColor}"
FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Age}" TextColor="{StaticResource NormalTextColor}" />
<Label Grid.Column="2" Text="{Binding Location}" TextColor="{StaticResource
NormalTextColor}" HorizontalTextAlignment="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ResourceDictionary>

This ResourceDictionary contains a single resource, which is an object of type DataTemplate .


You can instantiate MyResourceDictionary by putting it between a pair of Resources property-element tags, for
example, in a ContentPage :

<ContentPage ...>
<ContentPage.Resources>
<local:MyResourceDictionary />
</ContentPage.Resources>
...
</ContentPage>

An instance of MyResourceDictionary is set to the Resources property of the ContentPage object.


However, this approach has some limitations: The Resources property of the ContentPage references only this
one ResourceDictionary . In most cases, you want the option of including other ResourceDictionary instances
and perhaps other resources as well.
This task requires merged resource dictionaries.

Merged resource dictionaries


Merged resource dictionaries combine one or more ResourceDictionary objects into another
ResourceDictionary .

Merge local resource dictionaries


A local ResourceDictionary can be merged into another ResourceDictionary by setting the Source property to
the filename of the XAML file with the resources:

<ContentPage ...>
<ContentPage.Resources>
<!-- Add more resources here -->
<ResourceDictionary Source="MyResourceDictionary.xaml" />
<!-- Add more resources here -->
</ContentPage.Resources>
...
</ContentPage>
This syntax does not instantiate the MyResourceDictionary class. Instead, it references the XAML file. For that
reason, when setting the Source property, the code-behind file (MyResourceDictionary.xaml.cs) isn't
required, and the x:Class attribute can be removed from the root tag of the MyResourceDictionary.xaml file.
In addition, when merging resource dictionaries using this approach, Xamarin.Forms will automatically
instantiate the ResourceDictionary , hence the outer ResourceDictionary tags are not required.

IMPORTANT
The Source property can only be set from XAML.

Merge resource dictionaries from other assemblies


A ResourceDictionary can also be merged into another ResourceDictionary by adding it into the
MergedDictionaries property of the ResourceDictionary . This technique allows resource dictionaries to be
merged, regardless of the assembly in which they reside.

IMPORTANT
The ResourceDictionary class also defines a MergedWith property. However, this property has been deprecated and
should no longer be used.

The following code example shows MyResourceDictionary being added to the MergedDictionaries collection of a
page level ResourceDictionary :

<ContentPage ...
xmlns:local="clr-namespace:ResourceDictionaryDemo">
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyResourceDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

This example shows an instance of MyResourceDictionary , which resides in the same assembly, being added to
the ResourceDictionary . In addition, you can also add resource dictionaries from other assemblies, other
ResourceDictionary objects within the MergedDictionaries property-element tags, and other resources outside
of those tags:
<ContentPage ...
xmlns:local="clr-namespace:ResourceDictionaryDemo"
xmlns:theme="clr-namespace:MyThemes;assembly=MyThemes">
<ContentPage.Resources>
<ResourceDictionary>
<!-- Add more resources here -->
<ResourceDictionary.MergedDictionaries>
<!-- Add more resource dictionaries here -->
<local:MyResourceDictionary />
<theme:LightTheme />
<!-- Add more resource dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Add more resources here -->
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

IMPORTANT
There can be only one MergedDictionaries property-element tag in a ResourceDictionary , but you can put as many
ResourceDictionary objects in there as you want.

When merged ResourceDictionary resources share identical x:Key attribute values, Xamarin.Forms uses the
following resource precedence:
1. The resources local to the resource dictionary.
2. The resources contained in the resource dictionaries that were merged via the MergedDictionaries collection,
in the reverse order they are listed in the MergedDictionaries property.

NOTE
Searching resource dictionaries can be a computationally intensive task if an application contains multiple, large resource
dictionaries. Therefore, to avoid unnecessary searching, you should ensure that each page in an application only uses
resource dictionaries that are appropriate to the page.

Related links
Resource Dictionaries (sample)
Styles
ResourceDictionary

Related video
Find more Xamarin videos on Channel 9 and YouTube.
Passing Arguments in XAML
3 minutes to read • Edit Online

Download the sample


This article demonstrates using the XAML attributes that can be used to pass arguments to non-default
constructors, to call factory methods, and to specify the type of a generic argument.

Overview
It's often necessary to instantiate objects with constructors that require arguments, or by calling a static creation
method. This can be achieved in XAML by using the x:Arguments and x:FactoryMethod attributes:
The x:Arguments attribute is used to specify constructor arguments for a non-default constructor, or for a
factory method object declaration. For more information, see Passing Constructor Arguments.
The x:FactoryMethod attribute is used to specify a factory method that can be used to initialize an object. For
more information, see Calling Factory Methods.
In addition, the x:TypeArguments attribute can be used to specify the generic type arguments to the constructor of
a generic type. For more information, see Specifying a Generic Type Argument.

Passing Constructor Arguments


Arguments can be passed to a non-default constructor using the x:Arguments attribute. Each constructor
argument must be delimited within an XML element that represents the type of the argument. Xamarin.Forms
supports the following elements for basic types:
x:Object
x:Boolean
x:Byte
x:Int16
x:Int32
x:Int64
x:Single
x:Double
x:Decimal
x:Char
x:String
x:TimeSpan
x:Array
x:DateTime

The following code example demonstrates using the x:Arguments attribute with three Color constructors:
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color>
<x:Arguments>
<x:Double>0.9</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color>
<x:Arguments>
<x:Double>0.25</x:Double>
<x:Double>0.5</x:Double>
<x:Double>0.75</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color>
<x:Arguments>
<x:Double>0.8</x:Double>
<x:Double>0.5</x:Double>
<x:Double>0.2</x:Double>
<x:Double>0.5</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>

The number of elements within the x:Arguments tag, and the types of these elements, must match one of the
Color constructors. The Color constructor with a single parameter requires a grayscale value from 0 (black) to 1
(white). The Color constructor with three parameters requires a red, green, and blue value ranging from 0 to 1.
The Color constructor with four parameters adds an alpha channel as the fourth parameter.
The following screenshots show the result of calling each Color constructor with the specified argument values:
Calling Factory Methods
Factory methods can be called in XAML by specifying the method's name using the x:FactoryMethod attribute,
and its arguments using the x:Arguments attribute. A factory method is a public static method that returns
objects or values of the same type as the class or structure that defines the methods.
The Color structure defines a number of factory methods, and the following code example demonstrates calling
three of them:
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color x:FactoryMethod="FromRgba">
<x:Arguments>
<x:Int32>192</x:Int32>
<x:Int32>75</x:Int32>
<x:Int32>150</x:Int32>
<x:Int32>128</x:Int32>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color x:FactoryMethod="FromHsla">
<x:Arguments>
<x:Double>0.23</x:Double>
<x:Double>0.42</x:Double>
<x:Double>0.69</x:Double>
<x:Double>0.7</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color x:FactoryMethod="FromHex">
<x:Arguments>
<x:String>#FF048B9A</x:String>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>

The number of elements within the x:Arguments tag, and the types of these elements, must match the arguments
of the factory method being called. The FromRgba factory method requires four Int32 parameters, which
represent the red, green, blue, and alpha values, ranging from 0 to 255 respectively. The FromHsla factory method
requires four Double parameters, which represent the hue, saturation, luminosity, and alpha values, ranging from
0 to 1 respectively. The FromHex factory method requires a String that represents the hexadecimal (A)RGB color.
The following screenshots show the result of calling each Color factory method with the specified argument
values:
Specifying a Generic Type Argument
Generic type arguments for the constructor of a generic type can be specified using the x:TypeArguments attribute,
as demonstrated in the following code example:

<ContentPage ...>
<StackLayout>
<StackLayout.Margin>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0,20,0,0" />
<On Platform="Android" Value="5, 10" />
<On Platform="UWP" Value="10" />
</OnPlatform>
</StackLayout.Margin>
</StackLayout>
</ContentPage>

The OnPlatform class is a generic class and must be instantiated with an x:TypeArguments attribute that matches
the target type. In the On class, the Platform attribute can accept a single string value, or multiple comma-
delimited string values. In this example, the StackLayout.Margin property is set to a platform-specific Thickness
.

Summary
This article demonstrated using the XAML attributes that can be used to pass arguments to non-default
constructors, to call factory methods, and to specify the type of a generic argument.

Related Links
XAML Namespaces
Passing Constructor Arguments (sample)
Calling Factory Methods (sample)
XAML Field Modifiers in Xamarin.Forms
2 minutes to read • Edit Online

The x:FieldModifier namespace attribute specifies the access level for generated fields for named XAML
elements. Valid values of the attribute are:
private – specifies that the generated field for the XAML element is accessible only within the body of the
class in which it is declared.
public – specifies that the generated field for the XAML element has no access restrictions.
protected – specifies that the generated field for the XAML element is accessible within its class and by derived
class instances.
internal – specifies that the generated field for the XAML element is accessible only within types in the same
assembly.
notpublic – specifies that the generated field for the XAML element is accessible only within types in the same
assembly.
By default, if the value of the attribute isn't set, the generated field for the element will be private .

NOTE
The value of the attribute can use any casing, as it will be converted to lowercase by Xamarin.Forms.

The following conditions must be met for an x:FieldModifier attribute to be processed:


The top-level XAML element must be a valid x:Class .
The current XAML element has an x:Name specified.
The following XAML shows examples of setting the attribute:

<Label x:Name="privateLabel" />


<Label x:Name="internalLabel" x:FieldModifier="internal" />
<Label x:Name="publicLabel" x:FieldModifier="public" />

IMPORTANT
The x:FieldModifier attribute cannot be used to specify the access level of a XAML class.
Loading XAML at Runtime in Xamarin.Forms
2 minutes to read • Edit Online

Download the sample


The Xamarin.Forms.Xaml namespace includes two LoadFromXaml extension methods that can be used to load, and
parse XAML at runtime.

Background
When a Xamarin.Forms XAML class is constructed, the LoadFromXaml method is indirectly called. This occurs
because the code-behind file for a XAML class calls the InitializeComponent method from its constructor:

public partial class MainPage : ContentPage


{
public MainPage()
{
InitializeComponent();
}
}

When Visual Studio builds a project containing a XAML file, it parses the XAML file to generate a C# code file (for
example, MainPage.xaml.g.cs) that contains the definition of the InitializeComponent method:

private void InitializeComponent()


{
global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage));
...
}

The InitializeComponent method calls the LoadFromXaml method to extract the XAML file (or its compiled binary)
from the .NET Standard library. After extraction, it initializes all of the objects defined in the XAML file, connects
them all together in parent-child relationships, attaches event handlers defined in code to events set in the XAML
file, and sets the resultant tree of objects as the content of the page.

Loading XAML at runtime


The LoadFromXaml methods are public , and therefore can be called from Xamarin.Forms applications to load, and
parse XAML at runtime. This permits scenarios such as an application downloading XAML from a web service,
creating the required view from the XAML, and displaying it in the application.

WARNING
Loading XAML at runtime has a significant performance cost, and generally should be avoided.

The following code example shows a simple usage:


using Xamarin.Forms.Xaml;
...

string navigationButtonXAML = "<Button Text=\"Navigate\" />";


Button navigationButton = new Button().LoadFromXaml(navigationButtonXAML);
...
_stackLayout.Children.Add(navigationButton);

In this example, a Button instance is created, with it's Text property value being set from the XAML defined in
the string . The Button is then added to a StackLayout that has been defined in the XAML for the page.

NOTE
The LoadFromXaml extension methods allow a generic type argument to be specified. However, it's rarely necessary to
specify the type argument, as it will be inferred from the type of the instance its operating on.

The LoadFromXaml method can be used to inflate any XAML, with the following example inflating a ContentPage
and then navigating to it:

using Xamarin.Forms.Xaml;
...

// See the sample for the full XAML string


string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage
xmlns=\"http://xamarin.com/schemas/2014/forms\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:Cl
ass=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n</ContentPage>";

ContentPage page = new ContentPage().LoadFromXaml(pageXAML);


await Navigation.PushAsync(page);

Accessing elements
Loading XAML at runtime with the LoadFromXaml method does not permit strongly-typed access to the XAML
elements that have specified runtime object names (using x:Name ). However, these XAML elements can be
retrieved using the FindByName method, and then accessed as required:

// See the sample for the full XAML string


string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage
xmlns=\"http://xamarin.com/schemas/2014/forms\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:Cl
ass=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n<StackLayout>\n<Label
x:Name=\"monkeyName\"\n />\n</StackLayout>\n</ContentPage>";
ContentPage page = new ContentPage().LoadFromXaml(pageXAML);

Label monkeyLabel = page.FindByName<Label>("monkeyName");


monkeyLabel.Text = "Seated Monkey";
...

In this example, the XAML for a ContentPage is inflated. This XAML includes a Label named monkeyName , which is
retrieved using the FindByName method, before it's Text property is set.

Related links
LoadRuntimeXAML (sample)
Xamarin.Forms Accessibility
2 minutes to read • Edit Online

Building an accessible application ensures that the application is usable by people who approach the user interface
with a range of needs and experiences.
Making a Xamarin.Forms application accessible means thinking about the layout and design of many user interface
elements. For guidelines on issues to consider, see the Accessibility Checklist. Many accessibility concerns such as
large fonts, and suitable color and contrast settings can already be addressed by Xamarin.Forms APIs.
The Android accessibility and iOS accessibility guides contain details of the native APIs exposed by Xamarin, and
the UWP accessibility guide on MSDN explains the native approach on that platform. These APIs are used to fully
implement accessible applications on each platform.
Xamarin.Forms does not currently have built-in support for all of the accessibility APIs available on each of the
underlying platforms. However, it does support setting automation properties on user interface elements to
support screen reader and navigation assistance tools, which is one of the most important parts of building
accessible applications. For more information, see Automation Properties.
Xamarin.Forms applications can also have the tab order of controls specified, to improve usability and accessibility.
For more information, see Keyboard Accessibility.
Other accessibility APIs (such as PostNotification on iOS ) may be better suited to a DependencyService or Custom
Renderer implementation. These are not covered in this guide.

Testing Accessibility
Xamarin.Forms applications typically target multiple platforms, which means testing the accessibility features
according to the platform. Follow these links to learn how to test accessibility on each platform:
iOS Testing
Android Testing
Windows AccScope (MSDN )

Related Links
Cross-platform Accessibility
Automation Properties
Keyboard Accessibility

Related Video
Find more Xamarin videos on Channel 9 and YouTube.
Automation Properties in Xamarin.Forms
5 minutes to read • Edit Online

Download the sample


Xamarin.Forms allows accessibility values to be set on user interface elements by using attached properties from
the AutomationProperties class, which in turn set native accessibility values. This article explains how to use the
AutomationProperties class, so that a screen reader can speak about the elements on the page.
Xamarin.Forms allows automation properties to be set on user interface elements via the following attached
properties:
AutomationProperties.IsInAccessibleTree – indicates whether the element is available to an accessible
application. For more information, see AutomationProperties.IsInAccessibleTree.
AutomationProperties.Name – a short description of the element that serves as a speakable identifier for the
element. For more information, see AutomationProperties.Name.
AutomationProperties.HelpText – a longer description of the element, which can be thought of as tooltip text
associated with the element. For more information, see AutomationProperties.HelpText.
AutomationProperties.LabeledBy – allows another element to define accessibility information for the current
element. For more information, see AutomationProperties.LabeledBy.
These attached properties set native accessibility values so that a screen reader can speak about the element. For
more information about attached properties, see Attached Properties.

IMPORTANT
Using the AutomationProperties attached properties may impact UI Test execution on Android. The AutomationId ,
AutomationProperties.Name and AutomationProperties.HelpText properties will both set the native
ContentDescription property, with the AutomationProperties.Name and AutomationProperties.HelpText property
values taking precedence over the AutomationId value (if both AutomationProperties.Name and
AutomationProperties.HelpText are set, the values will be concatenated). This means that any tests looking for
AutomationId will fail if AutomationProperties.Name or AutomationProperties.HelpText are also set on the element.
In this scenario, UI Tests should be altered to look for the value of AutomationProperties.Name or
AutomationProperties.HelpText , or a concatenation of both.

Each platform has a different screen reader to narrate the accessibility values:
iOS has VoiceOver. For more information, see Test Accessibility on Your Device with VoiceOver on
developer.apple.com.
Android has TalkBack. For more information, see Testing Your App's Accessibility on developer.android.com.
Windows has Narrator. For more information, see Verify main app scenarios by using Narrator.
However, the exact behavior of a screen reader depends on the software and on the user's configuration of it. For
example, most screen readers read the text associated with a control when it receives focus, enabling users to
orient themselves as they move among the controls on the page. Some screen readers also read the entire
application user interface when a page appears, which enables the user to receive all of the page's available
informational content before attempting to navigate it.
Screen readers also read different accessibility values. In the sample application:
VoiceOver will read the Placeholder value of the Entry , followed by instructions for using the control.
TalkBack will read the Placeholder value of the Entry , followed by the AutomationProperties.HelpText value,
followed by instructions for using the control.
Narrator will read the AutomationProperties.LabeledBy value of the Entry , followed by instructions on using
the control.
In addition, Narrator will prioritize AutomationProperties.Name , AutomationProperties.LabeledBy , and then
AutomationProperties.HelpText . On Android, TalkBack may combine the AutomationProperties.Name and
AutomationProperties.HelpText values. Therefore, it's recommended that thorough accessibility testing is carried
out on each platform to ensure an optimal experience.

AutomationProperties.IsInAccessibleTree
The AutomationProperties.IsInAccessibleTree attached property is a boolean that determines if the element is
accessible, and hence visible, to screen readers. It must be set to true to use the other accessibility attached
properties. This can be accomplished in XAML as follows:

<Entry AutomationProperties.IsInAccessibleTree="true" />

Alternatively, it can be set in C# as follows:

var entry = new Entry();


AutomationProperties.SetIsInAccessibleTree(entry, true);

NOTE
Note that the SetValue method can also be used to set the AutomationProperties.IsInAccessibleTree attached
property – entry.SetValue(AutomationProperties.IsInAccessibleTreeProperty, true);

AutomationProperties.Name
The AutomationProperties.Name attached property value should be a short, descriptive text string that a screen
reader uses to announce an element. This property should be set for elements that have a meaning that is
important for understanding the content or interacting with the user interface. This can be accomplished in XAML
as follows:

<ActivityIndicator AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.Name="Progress indicator" />

Alternatively, it can be set in C# as follows:

var activityIndicator = new ActivityIndicator();


AutomationProperties.SetIsInAccessibleTree(activityIndicator, true);
AutomationProperties.SetName(activityIndicator, "Progress indicator");

NOTE
Note that the SetValue method can also be used to set the AutomationProperties.Name attached property –
activityIndicator.SetValue(AutomationProperties.NameProperty, "Progress indicator");
AutomationProperties.HelpText
The AutomationProperties.HelpText attached property should be set to text that describes the user interface
element, and can be thought of as tooltip text associated with the element. This can be accomplished in XAML as
follows:

<Button Text="Toggle ActivityIndicator"


AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.HelpText="Tap to toggle the activity indicator" />

Alternatively, it can be set in C# as follows:

var button = new Button { Text = "Toggle ActivityIndicator" };


AutomationProperties.SetIsInAccessibleTree(button, true);
AutomationProperties.SetHelpText(button, "Tap to toggle the activity indicator");

NOTE
Note that the SetValue method can also be used to set the AutomationProperties.HelpText attached property –
button.SetValue(AutomationProperties.HelpTextProperty, "Tap to toggle the activity indicator");

On some platforms, for edit controls such as an Entry , the HelpText property can sometimes be omitted and
replaced with placeholder text. For example, "Enter your name here" is a good candidate for the Entry.Placeholder
property that places the text in the control prior to the user's actual input.

AutomationProperties.LabeledBy
The AutomationProperties.LabeledBy attached property allows another element to define accessibility information
for the current element. For example, a Label next to an Entry can be used to describe what the Entry
represents. This can be accomplished in XAML as follows:

<Label x:Name="label" Text="Enter your name: " />


<Entry AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.LabeledBy="{x:Reference label}" />

Alternatively, it can be set in C# as follows:

var nameLabel = new Label { Text = "Enter your name: " };


var entry = new Entry();
AutomationProperties.SetIsInAccessibleTree(entry, true);
AutomationProperties.SetLabeledBy(entry, nameLabel);

NOTE
Note that the SetValue method can also be used to set the AutomationProperties.IsInAccessibleTree attached
property – entry.SetValue(AutomationProperties.LabeledByProperty, nameLabel);

Accessibility intricacies
The following sections describe the intricacies of setting accessibility values on certain controls.
NavigationPage
On Android, to set the text that screen readers will read for the back arrow in the action bar in a NavigationPage ,
set the AutomationProperties.Name and AutomationProperties.HelpText properties on a Page . However, note that
this will not have an effect on OS back buttons.
MasterDetailPage
On iOS and the Universal Windows Platform (UWP ), to set the text that screen readers will read for the toggle
button on a MasterDetailPage , either set the AutomationProperties.Name , and AutomationProperties.HelpText
properties on the MasterDetailPage , or on the IconImageSource property of the Master page.
On Android, to set the text that screen readers will read for the toggle button on a MasterDetailPage , add string
resources to the Android project:

<resources>
<string name="app_name">Xamarin Forms Control Gallery</string>
<string name="btnMDPAutomationID_open">Open Side Menu message</string>
<string name="btnMDPAutomationID_close">Close Side Menu message</string>
</resources>

Then set the AutomationId property of the IconImageSource property of the Master page to the appropriate
string:

var master = new ContentPage { ... };


master.IconImageSource.AutomationId = "btnMDPAutomationID";

ToolbarItem
On iOS, Android, and UWP, screen readers will read the Text property value of ToolbarItem instances, provided
that AutomationProperties.Name or AutomationProperties.HelpText values aren't defined.
On iOS and UWP the AutomationProperties.Name property value will replace the Text property value that is read
by the screen reader.
On Android, the AutomationProperties.Name and/or AutomationProperties.HelpText property values will
completely replace the Text property value that is both visible and read by the screen reader. Note that this is a
limitation of APIs less than 26.

Related Links
Attached Properties
Accessibility (sample)
Keyboard Accessibility in Xamarin.Forms
3 minutes to read • Edit Online

Download the sample


Users who use screen readers, or have mobility issues, can have difficulty using applications that don't provide
appropriate keyboard access. Xamarin.Forms applications can have an expected tab order specified to improve
their usability and accessibility. Specifying a tab order for controls enables keyboard navigation, prepares
application pages to receive input in a particular order, and permits screen readers to read focusable elements to
the user.
By default, the tab order of controls is the same order in which they are listed in XAML, or programmatically
added to a child collection. This order is the order in which the controls will be navigated through with a keyboard
and read by screen readers, and often this default order is the best order. However, the default order is not always
the same as the expected order, as shown in the following XAML code example:

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Text="You"
HorizontalOptions="Center" />
<Label Grid.Column="1"
Text="Manager"
HorizontalOptions="Center" />
<Entry Grid.Row="1"
Placeholder="Enter forename" />
<Entry Grid.Column="1"
Grid.Row="1"
Placeholder="Enter forename" />
<Entry Grid.Row="2"
Placeholder="Enter surname" />
<Entry Grid.Column="1"
Grid.Row="2"
Placeholder="Enter surname" />
</Grid>

The following screenshot shows the default tab order for this code example:

The tab order here is row -based, and is the order the controls are listed in the XAML. Therefore, pressing the Tab
key navigates through forename Entry instances, followed by surname Entry instances. However, a more
intuitive experience would be to use a column-first tab navigation, so that pressing the Tab key navigates through
forename-surname pairs. This can be achieved by specifying the tab order of the input controls.

NOTE
On the Universal Windows Platform, keyboard shortcuts can be defined that provide an intuitive way for users to quickly
navigate and interact with the application's visible UI through a keyboard instead of via touch or a mouse. For more
information, see Setting VisualElement Access Keys.

Setting the tab order


The VisualElement.TabIndex property is used to indicate the order in which VisualElement instances receive focus
when the user navigates through controls by pressing the Tab key. The default value of the property is 0, and it can
be set to any int value.
The following rules apply when using the default tab order, or setting the TabIndex property:
VisualElement instances with a TabIndex equal to 0 are added to the tab order based on their declaration
order in XAML or child collections.
VisualElement instances with a TabIndex greater than 0 are added to the tab order based on their TabIndex
value.
VisualElement instances with a TabIndex less than 0 are added to the tab order and appear before any zero
value.
Conflicts on a TabIndex are resolved by declaration order.

After defining a tab order, pressing the Tab key will cycle the focus through controls in ascending TabIndex order,
wrapping around to the beginning once the final control is reached.
The following XAML example shows the TabIndex property set on input controls to enable column-first tab
navigation:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Text="You"
HorizontalOptions="Center" />
<Label Grid.Column="1"
Text="Manager"
HorizontalOptions="Center" />
<Entry Grid.Row="1"
Placeholder="Enter forename"
TabIndex="1" />
<Entry Grid.Column="1"
Grid.Row="1"
Placeholder="Enter forename"
TabIndex="3" />
<Entry Grid.Row="2"
Placeholder="Enter surname"
TabIndex="2" />
<Entry Grid.Column="1"
Grid.Row="2"
Placeholder="Enter surname"
TabIndex="4" />
</Grid>

The following screenshot shows the tab order for this code example:

The tab order here is column-based. Therefore, pressing the Tab key navigates through forename-surname Entry
pairs.

IMPORTANT
Screen readers on iOS and Android will respect the TabIndex of a VisualElement when reading the accessible elements
on the screen.

Excluding controls from the tab order


In addition to setting the tab order of controls, it may be necessary to exclude controls from the tab order. One way
of achieving this is by setting the IsEnabled property of controls to false , because disabled controls are excluded
from the tab order.
However, it may be necessary to exclude controls from the tab order even when they aren't disabled. This can be
achieved with the VisualElement.IsTabStop property, which indicates whether a VisualElement is included in tab
navigation. Its default value is true , and when its value is false the control is ignored by the tab-navigation
infrastructure, irrespective if a TabIndex is set.

Supported controls
The TabIndex and IsTabStop properties are supported on the following controls, which accept keyboard input on
one or more platforms:
Button
DatePicker
Editor
Entry
NavigationPage
Picker
ProgressBar
SearchBar
Slider
Stepper
Switch
TabbedPage
TimePicker

NOTE
Each of these controls isn't tab focusable on every platform.

Related Links
Accessibility (sample)
Xamarin.Forms App Class
4 minutes to read • Edit Online

The Application base class offers the following features, which are exposed in your projects default App subclass:
A MainPage property, which is where to set the initial page for the app.
A persistent Properties dictionary to store simple values across lifecycle state changes.
A static Current property that contains a reference to the current application object.
It also exposes Lifecycle methods such as OnStart , OnSleep , and OnResume as well as modal navigation events.
Depending on which template you chose, the App class could be defined in one of two ways:
C#, or
XAML & C#
To create an App class using XAML, the default App class must be replaced with a XAML App class and
associated code-behind, as shown in the following code example:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Photos.App">

</Application>

The following code example shows the associated code-behind:

public partial class App : Application


{
public App ()
{
InitializeComponent ();
MainPage = new HomePage ();
}
...
}

As well as setting the MainPage property, the code-behind must also call the InitializeComponent method to load
and parse the associated XAML.

MainPage property
The MainPage property on the Application class sets the root page of the application.
For example, you can create logic in your App class to display a different page depending on whether the user is
logged in or not.
The MainPage property should be set in the App constructor,
public class App : Xamarin.Forms.Application
{
public App ()
{
MainPage = new ContentPage { Title = "App Lifecycle Sample" }; // your page here
}
}

Properties dictionary
The Application subclass has a static Properties dictionary which can be used to store data, in particular for use
in the OnStart , OnSleep , and OnResume methods. This can be accessed from anywhere in your Xamarin.Forms
code using Application.Current.Properties .
The Properties dictionary uses a string key and stores an object value.
For example, you could set a persistent "id" property anywhere in your code (when an item is selected, in a
page's OnDisappearing method, or in the OnSleep method) like this:

Application.Current.Properties ["id"] = someClass.ID;

In the OnStart or OnResume methods you can then use this value to recreate the user's experience in some way.
The Properties dictionary stores object s so you need to cast its value before using it.

if (Application.Current.Properties.ContainsKey("id"))
{
var id = Application.Current.Properties ["id"] as int;
// do something with id
}

Always check for the presence of the key before accessing it to prevent unexpected errors.

NOTE
The Properties dictionary can only serialize primitive types for storage. Attempting to store other types (such as
List<string> ) can fail silently.

Persistence
The Properties dictionary is saved to the device automatically. Data added to the dictionary will be available when
the application returns from the background or even after it is restarted.
Xamarin.Forms 1.4 introduced an additional method on the Application class - SavePropertiesAsync() - which
can be called to proactively persist the Properties dictionary. This is to allow you to save properties after
important updates rather than risk them not getting serialized out due to a crash or being killed by the OS.
You can find references to using the Properties dictionary in the Creating Mobile Apps with Xamarin.Forms
book chapters 6, 15, and 20, and in the associated samples.

The Application class


A complete Application class implementation is shown below for reference:
public class App : Xamarin.Forms.Application
{
public App ()
{
MainPage = new ContentPage { Title = "App Lifecycle Sample" }; // your page here
}

protected override void OnStart()


{
// Handle when your app starts
Debug.WriteLine ("OnStart");
}

protected override void OnSleep()


{
// Handle when your app sleeps
Debug.WriteLine ("OnSleep");
}

protected override void OnResume()


{
// Handle when your app resumes
Debug.WriteLine ("OnResume");
}
}

This class is then instantiated in each platform-specific project and passed to the LoadApplication method which is
where the MainPage is loaded and displayed to the user. The code for each platform is shown in the following
sections. The latest Xamarin.Forms solution templates already contain all this code, preconfigured for your app.
iOS project
The iOS AppDelegate class inherits from FormsApplicationDelegate . It should:
Call LoadApplication with an instance of the App class.
Always return base.FinishedLaunching (app, options); .

[Register ("AppDelegate")]
public partial class AppDelegate :
global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate // superclass new in 1.3
{
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init ();

LoadApplication (new App ()); // method is new in 1.3

return base.FinishedLaunching (app, options);


}
}

Android project
The Android MainActivity inherits from FormsAppCompatActivity . In the OnCreate override the LoadApplication
method is called with an instance of the App class.
[Activity (Label = "App Lifecycle Sample", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher =
true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);

global::Xamarin.Forms.Forms.Init (this, bundle);

LoadApplication (new App ()); // method is new in 1.3


}
}

Universal Windows project (UWP) for Windows 10


The main page in the UWP project should inherit from WindowsPage :

<forms:WindowsPage
...
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
...>
</forms:WindowsPage>

The C# code behind construction must call LoadApplication to create an instance of your Xamarin.Forms App .
Note that it is good practice to explicitly use the application namespace to qualify the App because UWP
applications also have their own App class unrelated to Xamarin.Forms.

public sealed partial class MainPage


{
public MainPage()
{
InitializeComponent();

LoadApplication(new YOUR_NAMESPACE.App());
}
}

Note that Forms.Init() must be called from App.xaml.cs in the UWP project.
For more information, see Setup Windows Projects, which includes steps to add a UWP project to an existing
Xamarin.Forms solution that doesn't target UWP.

Related video
Find more Xamarin videos on Channel 9 and YouTube.
Xamarin.Forms App Lifecycle
2 minutes to read • Edit Online

The Application base class provides the following features:


Lifecycle methods OnStart , OnSleep , and OnResume .
Page navigation events PageAppearing , PageDisappearing .
Modal navigation events ModalPushing , ModalPushed , ModalPopping , and ModalPopped .

Lifecycle methods
The Application class contains three virtual methods that can be overridden to respond to lifecycle changes:
OnStart - called when the application starts.
OnSleep - called each time the application goes to the background.
OnResume - called when the application is resumed, after being sent to the background.

NOTE
There is no method for application termination. Under normal circumstances (i.e. not a crash) application termination will
happen from the OnSleep state, without any additional notifications to your code.

To observe when these methods are called, implement a WriteLine call in each (as shown below ) and test on each
platform.

protected override void OnStart()


{
Debug.WriteLine ("OnStart");
}
protected override void OnSleep()
{
Debug.WriteLine ("OnSleep");
}
protected override void OnResume()
{
Debug.WriteLine ("OnResume");
}

IMPORTANT
On Android, the OnStart method will be called on rotation as well as when the application first starts, if the main activity
lacks ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation in the [Activity()]
attribute.

Page notification events


There are two events on the Application class that provide notification of pages appearing and disappearing:
PageAppearing - raised when a page is about to appear on the screen.
PageDisappearing - raised when a page is about to disappear from the screen.
These events can be used in scenarios where you want to track pages as they appear on screen.

NOTE
The PageAppearing and PageDisappearing events are raised from the Page base class immediately after the
Page.Appearing and Page.Disappearing events, respectively.

Modal navigation events


There are four events on the Application class, each with their own event arguments, that let you respond to
modal pages being shown and dismissed:
ModalPushing - raised when a page is modally pushed.
ModalPushed - raised after a page has been pushed modally.
ModalPopping - raised when a page is modally popped.
ModalPopped - raised after a page has been popped modally.

NOTE
The ModalPopping event arguments, of type ModalPoppingEventArgs , contain a Cancel property. When Cancel is set
to true the modal pop is cancelled.
Application Indexing and Deep Linking
9 minutes to read • Edit Online

Download the sample


Application indexing allows applications that would otherwise be forgotten after a few uses to stay relevant by
appearing in search results. Deep linking allows applications to respond to a search result that contains application
data, typically by navigating to a page referenced from a deep link. This article explains how to use application
indexing and deep linking to make Xamarin.Forms application content searchable on iOS and Android devices.

Deep Linking with Xamarin.Forms and Azure video


Xamarin.Forms application indexing and deep linking provide an API for publishing metadata for application
indexing as users navigate through applications. Indexed content can then be searched for in Spotlight Search, in
Google Search, or in a web search. Tapping on a search result that contains a deep link will fire an event that can be
handled by an application, and is typically used to navigate to the page referenced from the deep link.
The sample application demonstrates a Todo list application where the data is stored in a local SQLite database, as
shown in the following screenshots:

Each TodoItem instance created by the user is indexed. Platform-specific search can then be used to locate indexed
data from the application. When the user taps on a search result item for the application, the application is
launched, the TodoItemPage is navigated to, and the TodoItem referenced from the deep link is displayed.
For more information about using an SQLite database, see Xamarin.Forms Local Databases.
NOTE
Xamarin.Forms application indexing and deep linking functionality is only available on the iOS and Android platforms, and
requires a minimum of iOS 9 and API 23 respectively.

Setup
The following sections provide any additional setup instructions for using this feature on the iOS and Android
platforms.
iOS
On the iOS platform, ensure that your iOS platform project sets the Entitlements.plist file as the custom
entitlements file for signing the bundle.
To use iOS Universal Links:
1. Add an Associated Domains entitlement to your app, with the applinks key, including all the domains your app
will support.
2. Add an Apple App Site Association file to your website.
3. Add the applinks key to the Apple App Site Association file.
For more information, see Allowing Apps and Websites to Link to Your Content on developer.apple.com.
Android
On the Android platform, there are a number of prerequisites that must be met to use application indexing and
deep linking functionality:
1. A version of your application must be live on Google Play.
2. A companion website must be registered against the application in Google's Developer Console. Once the
application is associated with a website, URLs can be indexed that work for both the website and the application,
which can then be served in Search results. For more information, see App Indexing on Google Search on
Google's website.
3. Your application must support HTTP URL intents on the MainActivity class, which tell application indexing
what types of URL data schemes the application can respond to. For more information, see Configuring the
Intent Filter.
Once these prerequisites are met, the following additional setup is required to use Xamarin.Forms application
indexing and deep linking on the Android platform:
1. Install the Xamarin.Forms.AppLinks NuGet package into the Android application project.
2. In the MainActivity.cs file, add a declaration to use the Xamarin.Forms.Platform.Android.AppLinks namespace.
3. In the MainActivity.cs file, add a declaration to use the Firebase namespace.
4. In a web browser, create a new project via the Firebase Console.
5. In the Firebase Console, add Firebase to your Android app, and enter the required data.
6. Download the resulting google-services.json file.
7. Add the google-services.json file to the root directory of the Android project, and set its Build Action to
GoogleServicesJson.
8. In the MainActivity.OnCreate override, add the following line of code underneath Forms.Init(this, bundle) :

FirebaseApp.InitializeApp(this);
AndroidAppLinks.Init(this);
When google-services.json is added to the project (and the GoogleServicesJson* build action is set), the build
process extracts the client ID and API key and then adds these credentials to the generated manifest file.
For more information, see Deep Link Content with Xamarin.Forms URL Navigation on the Xamarin blog.

Indexing a Page
The process for indexing a page and exposing it to Google and Spotlight search is as follows:
1. Create an AppLinkEntry that contains the metadata required to index the page, along with a deep link to return
to the page when the user selects the indexed content in search results.
2. Register the AppLinkEntry instance to index it for searching.

The following code example demonstrates how to create an AppLinkEntry instance:

AppLinkEntry GetAppLink(TodoItem item)


{
var pageType = GetType().ToString();
var pageLink = new AppLinkEntry
{
Title = item.Name,
Description = item.Notes,
AppLinkUri = new Uri($"http://{App.AppName}/{pageType}?id={item.ID}", UriKind.RelativeOrAbsolute),
IsLinkActive = true,
Thumbnail = ImageSource.FromFile("monkey.png")
};

pageLink.KeyValues.Add("contentType", "TodoItemPage");
pageLink.KeyValues.Add("appName", App.AppName);
pageLink.KeyValues.Add("companyName", "Xamarin");

return pageLink;
}

The AppLinkEntry instance contains a number of properties whose values are required to index the page and
create a deep link. The Title , Description , and Thumbnail properties are used to identify the indexed content
when it appears in search results. The IsLinkActive property is set to true to indicate that the indexed content is
currently being viewed. The AppLinkUri property is a Uri that contains the information required to return to the
current page and display the current TodoItem . The following example shows an example Uri for the sample
application:

http://deeplinking/DeepLinking.TodoItemPage?id=2

This contains all the information required to launch the deeplinking app, navigate to the
Uri
DeepLinking.TodoItemPage , and display the TodoItem that has an ID of 2.

Registering Content for Indexing


Once an AppLinkEntry instance has been created, it must be registered for indexing to appear in search results.
This is accomplished with the RegisterLink method, as demonstrated in the following code example:

Application.Current.AppLinks.RegisterLink (appLink);

This adds the AppLinkEntry instance to the application's AppLinks collection.


NOTE
The RegisterLink method can also be used to update the content that's been indexed for a page.

Once an AppLinkEntry instance has been registered for indexing, it can appear in search results. The following
screenshot shows indexed content appearing in search results on the iOS platform:

De-registering Indexed Content


The DeregisterLink method is used to remove indexed content from search results, as demonstrated in the
following code example:

Application.Current.AppLinks.DeregisterLink (appLink);

This removes the AppLinkEntry instance from the application's AppLinks collection.

NOTE
On Android it's not possible to remove indexed content from search results.

Responding to a Deep Link


When indexed content appears in search results and is selected by a user, the App class for the application will
receive a request to handle the Uri contained in the indexed content. This request can be processed in the
OnAppLinkRequestReceived override, as demonstrated in the following code example:
public class App : Application
{
...
protected override async void OnAppLinkRequestReceived(Uri uri)
{
string appDomain = "http://" + App.AppName.ToLowerInvariant() + "/";
if (!uri.ToString().ToLowerInvariant().StartsWith(appDomain, StringComparison.Ordinal))
return;

string pageUrl = uri.ToString().Replace(appDomain, string.Empty).Trim();


var parts = pageUrl.Split('?');
string page = parts[0];
string pageParameter = parts[1].Replace("id=", string.Empty);

var formsPage = Activator.CreateInstance(Type.GetType(page));


var todoItemPage = formsPage as TodoItemPage;
if (todoItemPage != null)
{
var todoItem = await App.Database.GetItemAsync(int.Parse(pageParameter));
todoItemPage.BindingContext = todoItem;
await MainPage.Navigation.PushAsync(formsPage as Page);
}
base.OnAppLinkRequestReceived(uri);
}
}

The OnAppLinkRequestReceived method checks that the received Uri is intended for the application, before parsing
the Uri into the page to be navigated to and the parameter to be passed to the page. An instance of the page to be
navigated to is created, and the TodoItem represented by the page parameter is retrieved. The BindingContext of
the page to be navigated to is then set to the TodoItem . This ensures that when the TodoItemPage is displayed by
the PushAsync method, it will be showing the TodoItem whose ID is contained in the deep link.

Making Content Available for Search Indexing


Each time the page represented by a deep link is displayed, the AppLinkEntry.IsLinkActive property can be set to
true . On iOS and Android this makes the AppLinkEntry instance available for search indexing, and on iOS only, it
also makes the AppLinkEntry instance available for Handoff. For more information about Handoff, see Introduction
to Handoff.
The following code example demonstrates setting the AppLinkEntry.IsLinkActive property to true in the
Page.OnAppearing override:

protected override void OnAppearing()


{
appLink = GetAppLink(BindingContext as TodoItem);
if (appLink != null)
{
appLink.IsLinkActive = true;
}
}

Similarly, when the page represented by a deep link is navigated away from, the AppLinkEntry.IsLinkActive
property can be set to false . On iOS and Android, this stops the AppLinkEntry instance being advertised for
search indexing, and on iOS only, it also stops advertising the AppLinkEntry instance for Handoff. This can be
accomplished in the Page.OnDisappearing override, as demonstrated in the following code example:
protected override void OnDisappearing()
{
if (appLink != null)
{
appLink.IsLinkActive = false;
}
}

Providing Data to Handoff


On iOS, application-specific data can be stored when indexing the page. This is achieved by adding data to the
KeyValues collection, which is a Dictionary<string, string> for storing key-value pairs that are used in Handoff.
Handoff is a way for the user to start an activity on one of their devices and continue that activity on another of
their devices (as identified by the user's iCloud account). The following code shows an example of storing
application-specific key-value pairs:

var pageLink = new AppLinkEntry


{
...
};
pageLink.KeyValues.Add("appName", App.AppName);
pageLink.KeyValues.Add("companyName", "Xamarin");

Values stored in the KeyValues collection will be stored in the metadata for the indexed page, and will be restored
when the user taps on a search result that contains a deep link (or when Handoff is used to view the content on
another signed-in device).
In addition, values for the following keys can be specified:
contentType – a string that specifies the uniform type identifier of the indexed content. The recommended
convention to use for this value is the type name of the page containing the indexed content.
associatedWebPage – a string that represents the web page to visit if the indexed content can also be viewed
on the web, or if the application supports Safari's deep links.
shouldAddToPublicIndex – a string of either true or false that controls whether or not to add the indexed
content to Apple's public cloud index, which can then be presented to users who haven't installed the application
on their iOS device. However, just because content has been set for public indexing, it doesn't mean that it will
be automatically added to Apple's public cloud index. For more information, see Public Search Indexing. Note
that this key should be set to false when adding personal data to the KeyValues collection.

NOTE
The KeyValues collection isn't used on the Android platform.

For more information about Handoff, see Introduction to Handoff.

Summary
This article explained how to use application indexing and deep linking to make Xamarin.Forms application content
searchable on iOS and Android devices. Application indexing allows applications to stay relevant by appearing in
search results that would otherwise be forgotten about after a few uses.

Related Links
Deep Linking (sample)
iOS Search APIs
App-Linking in Android 6.0
AppLinkEntry
IAppLinkEntry
IAppLinks
Xamarin.Forms Behaviors
2 minutes to read • Edit Online

Behaviors lets you add functionality to user interface controls without having to subclass them. Behaviors are
written in code and added to controls in XAML or code.

Introduction to Behaviors
Behaviors enable you to implement code that you would normally have to write as code-behind, because it directly
interacts with the API of the control in such a way that it can be concisely attached to the control. This article
provides an introduction to behaviors.

Attached Behaviors
Attached behaviors are static classes with one or more attached properties. This article demonstrates how to
create and consume attached behaviors.

Xamarin.Forms Behaviors
Xamarin.Forms behaviors are created by deriving from the Behavior or Behavior<T> class. This article
demonstrates how to create and consume Xamarin.Forms behaviors.

Reusable Behaviors
Behaviors are reusable across more than one application. These articles explain how to create useful behaviors to
perform commonly used functionality.
Introduction to Behaviors
2 minutes to read • Edit Online

Behaviors let you add functionality to user interface controls without having to subclass them. Instead, the
functionality is implemented in a behavior class and attached to the control as if it was part of the control itself.
This article provides an introduction to behaviors.
Behaviors enable you to implement code that you would normally have to write as code-behind, because it directly
interacts with the API of the control in such a way that it can be concisely attached to the control and packaged for
reuse across more than one application. They can be used to provide a full range of functionality to controls, such
as:
Adding an email validator to an Entry .
Creating a rating control using a tap gesture recognizer.
Controlling an animation.
Adding an effect to a control.
Behaviors also enable more advanced scenarios. In the context of commanding, behaviors are a useful approach
for connecting a control to a command. In addition, they can be used to associate commands with controls that
were not designed to interact with commands. For example, they can be used to invoke a command in response to
an event firing.
Xamarin.Forms supports two different styles of behaviors:
Xamarin.Forms behaviors – classes that derive from the Behavior or Behavior<T> class, where T is the type
of the control to which the behavior should apply. For more information about Xamarin.Forms behaviors, see
Xamarin.Forms Behaviors and Reusable Behaviors.
Attached behaviors – static classes with one or more attached properties. For more information about
attached behaviors, see Attached Behaviors.
This guide focuses on Xamarin.Forms behaviors because they are the preferred approach to behavior construction.

Related Links
Behavior
Behavior<T>
Attached Behaviors
3 minutes to read • Edit Online

Download the sample


Attached behaviors are static classes with one or more attached properties. This article demonstrates how to
create and consume attached behaviors.

Overview
An attached property is a special type of bindable property. They are defined in one class but attached to other
objects, and they are recognizable in XAML as attributes that contain a class and a property name separated by a
period.
An attached property can define a propertyChanged delegate that will be executed when the value of the property
changes, such as when the property is set on a control. When the propertyChanged delegate executes, it's passed a
reference to the control on which it is being attached, and parameters that contain the old and new values for the
property. This delegate can be used to add new functionality to the control that the property is attached to by
manipulating the reference that is passed in, as follows:
1. The propertyChanged delegate casts the control reference, which is received as a BindableObject , to the control
type that the behavior is designed to enhance.
2. The propertyChanged delegate modifies properties of the control, calls methods of the control, or registers
event handlers for events exposed by the control, to implement the core behavior functionality.
An issue with attached behaviors is that they are defined in a static class, with static properties and methods.
This makes it difficult to create attached behaviors that have state. In addition, Xamarin.Forms behaviors have
replaced attached behaviors as the preferred approach to behavior construction. For more information about
Xamarin.Forms behaviors, see Xamarin.Forms Behaviors and Reusable Behaviors.

Creating an Attached Behavior


The sample application demonstrates a NumericValidationBehavior , which highlights the value entered by the user
into an Entry control in red, if it's not a double . The behavior is shown in the following code example:
public static class NumericValidationBehavior
{
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached (
"AttachBehavior",
typeof(bool),
typeof(NumericValidationBehavior),
false,
propertyChanged:OnAttachBehaviorChanged);

public static bool GetAttachBehavior (BindableObject view)


{
return (bool)view.GetValue (AttachBehaviorProperty);
}

public static void SetAttachBehavior (BindableObject view, bool value)


{
view.SetValue (AttachBehaviorProperty, value);
}

static void OnAttachBehaviorChanged (BindableObject view, object oldValue, object newValue)


{
var entry = view as Entry;
if (entry == null) {
return;
}

bool attachBehavior = (bool)newValue;


if (attachBehavior) {
entry.TextChanged += OnEntryTextChanged;
} else {
entry.TextChanged -= OnEntryTextChanged;
}
}

static void OnEntryTextChanged (object sender, TextChangedEventArgs args)


{
double result;
bool isValid = double.TryParse (args.NewTextValue, out result);
((Entry)sender).TextColor = isValid ? Color.Default : Color.Red;
}
}

The NumericValidationBehavior class contains an attached property named AttachBehavior with a static getter
and setter, which controls the addition or removal of the behavior to the control to which it will be attached. This
attached property registers the OnAttachBehaviorChanged method that will be executed when the value of the
property changes. This method registers or de-registers an event handler for the TextChanged event, based on the
value of the AttachBehavior attached property. The core functionality of the behavior is provided by the
OnEntryTextChanged method, which parses the value entered into the Entry by the user, and sets the TextColor
property to red if the value isn't a double .

Consuming an Attached Behavior


The NumericValidationBehavior class can be consumed by adding the AttachBehavior attached property to an
Entry control, as demonstrated in the following XAML code example:

<ContentPage ... xmlns:local="clr-namespace:WorkingWithBehaviors;assembly=WorkingWithBehaviors" ...>


...
<Entry Placeholder="Enter a System.Double" local:NumericValidationBehavior.AttachBehavior="true" />
...
</ContentPage>
The equivalent Entry in C# is shown in the following code example:

var entry = new Entry { Placeholder = "Enter a System.Double" };


NumericValidationBehavior.SetAttachBehavior (entry, true);

At runtime, the behavior will respond to interaction with the control, according to the behavior implementation.
The following screenshots demonstrate the attached behavior responding to invalid input:

NOTE
Attached behaviors are written for a specific control type (or a superclass that can apply to many controls), and they should
only be added to a compatible control. Attempting to attach a behavior to an incompatible control will result in unknown
behavior, and depends on the behavior implementation.

Removing an Attached Behavior from a Control


The NumericValidationBehavior class can be removed from a control by setting the AttachBehavior attached
property to false , as demonstrated in the following XAML code example:

<Entry Placeholder="Enter a System.Double" local:NumericValidationBehavior.AttachBehavior="false" />

The equivalent Entry in C# is shown in the following code example:

var entry = new Entry { Placeholder = "Enter a System.Double" };


NumericValidationBehavior.SetAttachBehavior (entry, false);

At runtime, the OnAttachBehaviorChanged method will be executed when the value of the AttachBehavior attached
property is set to false . The OnAttachBehaviorChanged method will then de-register the event handler for the
TextChanged event, ensuring that the behavior isn't executed as the user interacts with the control.

Summary
This article demonstrated how to create and consume attached behaviors. Attached behaviors are static classes
with one or more attached properties.
Related Links
Attached Behaviors (sample)
Create Xamarin.Forms behaviors
5 minutes to read • Edit Online

Download the sample


Xamarin.Forms behaviors are created by deriving from the Behavior or Behavior<T> class. This article
demonstrates how to create and consume Xamarin.Forms behaviors.

Overview
The process for creating a Xamarin.Forms behavior is as follows:
1. Create a class that inherits from the Behavior or Behavior<T> class, where T is the type of the control to
which the behavior should apply.
2. Override the OnAttachedTo method to perform any required setup.
3. Override the OnDetachingFrom method to perform any required cleanup.
4. Implement the core functionality of the behavior.
This results in the structure shown in the following code example:

public class CustomBehavior : Behavior<View>


{
protected override void OnAttachedTo (View bindable)
{
base.OnAttachedTo (bindable);
// Perform setup
}

protected override void OnDetachingFrom (View bindable)


{
base.OnDetachingFrom (bindable);
// Perform clean up
}

// Behavior implementation
}

The OnAttachedTo method is fired immediately after the behavior is attached to a control. This method receives a
reference to the control to which it is attached, and can be used to register event handlers or perform other setup
that's required to support the behavior functionality. For example, you could subscribe to an event on a control.
The behavior functionality would then be implemented in the event handler for the event.
The OnDetachingFrom method is fired when the behavior is removed from the control. This method receives a
reference to the control to which it is attached, and is used to perform any required cleanup. For example, you
could unsubscribe from an event on a control to prevent memory leaks.
The behavior can then be consumed by attaching it to the Behaviors collection of the appropriate control.

Creating a Xamarin.Forms Behavior


The sample application demonstrates a NumericValidationBehavior , which highlights the value entered by the user
into an Entry control in red, if it's not a double . The behavior is shown in the following code example:
public class NumericValidationBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}

protected override void OnDetachingFrom(Entry entry)


{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}

void OnEntryTextChanged(object sender, TextChangedEventArgs args)


{
double result;
bool isValid = double.TryParse (args.NewTextValue, out result);
((Entry)sender).TextColor = isValid ? Color.Default : Color.Red;
}
}

The NumericValidationBehavior derives from the Behavior<T> class, where T is an Entry . The OnAttachedTo
method registers an event handler for the TextChanged event, with the OnDetachingFrom method de-registering
the TextChanged event to prevent memory leaks. The core functionality of the behavior is provided by the
OnEntryTextChanged method, which parses the value entered by the user into the Entry , and sets the TextColor
property to red if the value isn't a double .

NOTE
Xamarin.Forms does not set the BindingContext of a behavior, because behaviors can be shared and applied to multiple
controls through styles.

Consuming a Xamarin.Forms Behavior


Every Xamarin.Forms control has a Behaviors collection, to which one or more behaviors can be added, as
demonstrated in the following XAML code example:

<Entry Placeholder="Enter a System.Double">


<Entry.Behaviors>
<local:NumericValidationBehavior />
</Entry.Behaviors>
</Entry>

The equivalent Entry in C# is shown in the following code example:

var entry = new Entry { Placeholder = "Enter a System.Double" };


entry.Behaviors.Add (new NumericValidationBehavior ());

At runtime the behavior will respond to interaction with the control, according to the behavior implementation.
The following screenshots demonstrate the behavior responding to invalid input:
NOTE
Behaviors are written for a specific control type (or a superclass that can apply to many controls), and they should only be
added to a compatible control. Attempting to attach a behavior to an incompatible control will result in an exception being
thrown.

Consuming a Xamarin.Forms Behavior with a Style


Behaviors can also be consumed by an explicit or implicit style. However, creating a style that sets the Behaviors
property of a control is not possible because the property is read-only. The solution is to add an attached property
to the behavior class that controls adding and removing the behavior. The process is as follows:
1. Add an attached property to the behavior class that will be used to control the addition or removal of the
behavior to the control to which the behavior will attached. Ensure that the attached property registers a
propertyChanged delegate that will be executed when the value of the property changes.
2. Create a static getter and setter for the attached property.
3. Implement logic in the propertyChanged delegate to add and remove the behavior.

The following code example shows an attached property that controls adding and removing the
NumericValidationBehavior :
public class NumericValidationBehavior : Behavior<Entry>
{
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached ("AttachBehavior", typeof(bool), typeof(NumericValidationBehavior),
false, propertyChanged: OnAttachBehaviorChanged);

public static bool GetAttachBehavior (BindableObject view)


{
return (bool)view.GetValue (AttachBehaviorProperty);
}

public static void SetAttachBehavior (BindableObject view, bool value)


{
view.SetValue (AttachBehaviorProperty, value);
}

static void OnAttachBehaviorChanged (BindableObject view, object oldValue, object newValue)


{
var entry = view as Entry;
if (entry == null) {
return;
}

bool attachBehavior = (bool)newValue;


if (attachBehavior) {
entry.Behaviors.Add (new NumericValidationBehavior ());
} else {
var toRemove = entry.Behaviors.FirstOrDefault (b => b is NumericValidationBehavior);
if (toRemove != null) {
entry.Behaviors.Remove (toRemove);
}
}
}
...
}

The NumericValidationBehavior class contains an attached property named AttachBehavior with a static getter
and setter, which controls the addition or removal of the behavior to the control to which it will be attached. This
attached property registers the OnAttachBehaviorChanged method that will be executed when the value of the
property changes. This method adds or removes the behavior to the control, based on the value of the
AttachBehavior attached property.

The following code example shows an explicit style for the NumericValidationBehavior that uses the
AttachBehavior attached property, and which can be applied to Entry controls:

<Style x:Key="NumericValidationStyle" TargetType="Entry">


<Style.Setters>
<Setter Property="local:NumericValidationBehavior.AttachBehavior" Value="true" />
</Style.Setters>
</Style>

The can be applied to an Entry control by setting its Style property to the
Style Style instance using the
StaticResource markup extension, as demonstrated in the following code example:

<Entry Placeholder="Enter a System.Double" Style="{StaticResource NumericValidationStyle}">

For more information about styles, see Styles.


NOTE
While you can add bindable properties to a behavior that is set or queried in XAML, if you do create behaviors that have
state they should not be shared between controls in a Style in a ResourceDictionary .

Removing a Behavior from a Control


The OnDetachingFrom method is fired when a behavior is removed from a control, and is used to perform any
required cleanup such as unsubscribing from an event to prevent a memory leak. However, behaviors are not
implicitly removed from controls unless the control's Behaviors collection is modified by a Remove or Clear
method. The following code example demonstrates removing a specific behavior from a control's Behaviors
collection:

var toRemove = entry.Behaviors.FirstOrDefault (b => b is NumericValidationBehavior);


if (toRemove != null) {
entry.Behaviors.Remove (toRemove);
}

Alternatively, the control's Behaviors collection can be cleared, as demonstrated in the following code example:

entry.Behaviors.Clear();

In addition, note that behaviors are not implicitly removed from controls when pages are popped from the
navigation stack. Instead, they must be explicitly removed prior to pages going out of scope.

Summary
This article demonstrated how to create and consume Xamarin.Forms behaviors. Xamarin.Forms behaviors are
created by deriving from the Behavior or Behavior<T> class.

Related Links
Xamarin.Forms Behavior (sample)
Xamarin.Forms Behavior applied with a Style (sample)
Behavior
Behavior<T>
Reusable Behaviors
2 minutes to read • Edit Online

Behaviors are reusable across more than one application. These articles explain how to create useful behaviors to
perform commonly used functionality.

Reusable EffectBehavior
Behaviors are a useful approach for adding an effect to a control, removing boiler-plate effect handling code from
code-behind files. This article demonstrates creating and consuming a Xamarin.Forms behavior to add an effect to
a control.

Reusable EventToCommandBehavior
Behaviors can be used to associate commands with controls that were not designed to interact with commands.
This article demonstrates creating and consuming a Xamarin.Forms behavior to invoke a command when an
event fires.
Reusable EffectBehavior
4 minutes to read • Edit Online

Download the sample


Behaviors are a useful approach for adding an effect to a control, removing boiler-plate effect handling code from
code-behind files. This article demonstrates creating and consuming a Xamarin.Forms behavior to add an effect to
a control.

Overview
The EffectBehavior class is a reusable Xamarin.Forms custom behavior that adds an Effect instance to a control
when the behavior is attached to the control, and removes the Effect instance when the behavior is detached
from the control.
The following behavior properties must be set to use the behavior:
Group – the value of the ResolutionGroupName attribute for the effect class.
Name – the value of the ExportEffect attribute for the effect class.
For more information about effects, see Effects.

NOTE
The EffectBehavior is a custom class that can be located in the Effect Behavior sample, and is not part of Xamarin.Forms.

Creating the Behavior


The EffectBehavior class derives from the Behavior<T> class, where T is a View . This means that the
EffectBehavior class can be attached to any Xamarin.Forms control.
Implementing Bindable Properties
The EffectBehavior class defines two BindableProperty instances, which are used to add an Effect to a control
when the behavior is attached to the control. These properties are shown in the following code example:

public class EffectBehavior : Behavior<View>


{
public static readonly BindableProperty GroupProperty =
BindableProperty.Create ("Group", typeof(string), typeof(EffectBehavior), null);
public static readonly BindableProperty NameProperty =
BindableProperty.Create ("Name", typeof(string), typeof(EffectBehavior), null);

public string Group {


get { return (string)GetValue (GroupProperty); }
set { SetValue (GroupProperty, value); }
}

public string Name {


get { return(string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}
...
}
When the EffectBehavior is consumed, the Group property should be set to the value of the ResolutionGroupName
attribute for the effect. In addition, the Name property should be set to the value of the ExportEffect attribute for
the effect class.
Implementing the Overrides
The EffectBehavior class overrides the OnAttachedTo and OnDetachingFrom methods of the Behavior<T> class, as
shown in the following code example:

public class EffectBehavior : Behavior<View>


{
...
protected override void OnAttachedTo (BindableObject bindable)
{
base.OnAttachedTo (bindable);
AddEffect (bindable as View);
}

protected override void OnDetachingFrom (BindableObject bindable)


{
RemoveEffect (bindable as View);
base.OnDetachingFrom (bindable);
}
...
}

The OnAttachedTo method performs setup by calling the AddEffect method, passing in the attached control as a
parameter. The OnDetachingFrom method performs cleanup by calling the RemoveEffect method, passing in the
attached control as a parameter.
Implementing the Behavior Functionality
The purpose of the behavior is to add the Effect defined in the Group and Name properties to a control when the
behavior is attached to the control, and remove the Effect when the behavior is detached from the control. The
core behavior functionality is shown in the following code example:

public class EffectBehavior : Behavior<View>


{
...
void AddEffect (View view)
{
var effect = GetEffect ();
if (effect != null) {
view.Effects.Add (GetEffect ());
}
}

void RemoveEffect (View view)


{
var effect = GetEffect ();
if (effect != null) {
view.Effects.Remove (GetEffect ());
}
}

Effect GetEffect ()
{
if (!string.IsNullOrWhiteSpace (Group) && !string.IsNullOrWhiteSpace (Name)) {
return Effect.Resolve (string.Format ("{0}.{1}", Group, Name));
}
return null;
}
}
The AddEffect method is executed in response to the EffectBehavior being attached to a control, and it receives
the attached control as a parameter. The method then adds the retrieved effect to the control's Effects collection.
The RemoveEffect method is executed in response to the EffectBehavior being detached from a control, and it
receives the attached control as a parameter. The method then removes the effect from the control's Effects
collection.
The GetEffect method uses the Effect.Resolve method to retrieve the Effect . The effect is located through a
concatenation of the Group and Name property values. If a platform doesn't provide the effect, the Effect.Resolve
method will return a non- null value.

Consuming the Behavior


The EffectBehavior class can be attached to the Behaviors collection of a control, as demonstrated in the
following XAML code example:

<Label Text="Label Shadow Effect" ...>


<Label.Behaviors>
<local:EffectBehavior Group="Xamarin" Name="LabelShadowEffect" />
</Label.Behaviors>
</Label>

The equivalent C# code is shown in the following code example:

var label = new Label {


Text = "Label Shadow Effect",
...
};
label.Behaviors.Add (new EffectBehavior {
Group = "Xamarin",
Name = "LabelShadowEffect"
});

The Groupand Name properties of the behavior are set to the values of the ResolutionGroupName and
ExportEffect attributes for the effect class in each platform -specific project.

At runtime, when the behavior is attached to the Label control, the Xamarin.LabelShadowEffect will be added to
the control's Effects collection. This results in a shadow being added to the text displayed by the Label control,
as shown in the following screenshots:

The advantage of using this behavior to add and remove effects from controls is that boiler-plate effect-handling
code can be removed from code-behind files.

Summary
This article demonstrated using a behavior to add an effect to a control. The EffectBehavior class is a reusable
Xamarin.Forms custom behavior that adds an Effect instance to a control when the behavior is attached to the
control, and removes the Effect instance when the behavior is detached from the control.
Related Links
Effects
Effect Behavior (sample)
Behavior
Behavior<T>
Reusable EventToCommandBehavior
6 minutes to read • Edit Online

Download the sample


Behaviors can be used to associate commands with controls that were not designed to interact with commands.
This article demonstrates creating and consuming a Xamarin.Forms behavior to invoke a command when an
event fires.

Overview
The EventToCommandBehavior class is a reusable Xamarin.Forms custom behavior that executes a command in
response to any event firing. By default, the event arguments for the event will be passed to the command, and can
be optionally converted by an IValueConverter implementation.
The following behavior properties must be set to use the behavior:
EventName – the name of the event the behavior listens to.
Command – the ICommand to be executed. The behavior expects to find the ICommand instance on the
BindingContext of the attached control, which may be inherited from a parent element.

The following optional behavior properties can also be set:


CommandParameter – an object that will be passed to the command.
Converter – an IValueConverter implementation that will change the format of the event argument data as it's
passed between source and target by the binding engine.

NOTE
The EventToCommandBehavior is a custom class that can be located in the EventToCommand Behavior sample, and is not
part of Xamarin.Forms.

Creating the Behavior


The EventToCommandBehavior class derives from the BehaviorBase<T> class, which in turn derives from the
Behavior<T> class. The purpose of the BehaviorBase<T> class is to provide a base class for any Xamarin.Forms
behaviors that require the BindingContext of the behavior to be set to the attached control. This ensures that the
behavior can bind to and execute the ICommand specified by the Command property when the behavior is
consumed.
The BehaviorBase<T> class provides an overridable OnAttachedTo method that sets the BindingContext of the
behavior and an overridable OnDetachingFrom method that cleans up the BindingContext . In addition, the class
stores a reference to the attached control in the AssociatedObject property.
Implementing Bindable Properties
The EventToCommandBehavior class defines four BindableProperty instances, that execute a user defined command
when an event fires. These properties are shown in the following code example:
public class EventToCommandBehavior : BehaviorBase<View>
{
public static readonly BindableProperty EventNameProperty =
BindableProperty.Create ("EventName", typeof(string), typeof(EventToCommandBehavior), null,
propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty =
BindableProperty.Create ("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty CommandParameterProperty =
BindableProperty.Create ("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty InputConverterProperty =
BindableProperty.Create ("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);

public string EventName { ... }


public ICommand Command { ... }
public object CommandParameter { ... }
public IValueConverter Converter { ... }
...
}

When the EventToCommandBehavior class is consumed, the Command property should be data bound to an ICommand
to be executed in response to the event firing that's defined in the EventName property. The behavior will expect to
find the ICommand on the BindingContext of the attached control.
By default, the event arguments for the event will be passed to the command. This data can be optionally
converted as it's passed between source and target by the binding engine, by specifying an IValueConverter
implementation as the Converter property value. Alternatively, a parameter can be passed to the command by
specifying the CommandParameter property value.
Implementing the Overrides
The EventToCommandBehavior class overrides the OnAttachedTo and OnDetachingFrom methods of the
BehaviorBase<T> class, as shown in the following code example:

public class EventToCommandBehavior : BehaviorBase<View>


{
...
protected override void OnAttachedTo (View bindable)
{
base.OnAttachedTo (bindable);
RegisterEvent (EventName);
}

protected override void OnDetachingFrom (View bindable)


{
DeregisterEvent (EventName);
base.OnDetachingFrom (bindable);
}
...
}

The method performs setup by calling the RegisterEvent method, passing in the value of the
OnAttachedTo
EventName property as a parameter. The OnDetachingFrom method performs cleanup by calling the
DeregisterEvent method, passing in the value of the EventName property as a parameter.

Implementing the Behavior Functionality


The purpose of the behavior is to execute the command defined by the Command property in response to the event
firing that's defined by the EventName property. The core behavior functionality is shown in the following code
example:
public class EventToCommandBehavior : BehaviorBase<View>
{
...
void RegisterEvent (string name)
{
if (string.IsNullOrWhiteSpace (name)) {
return;
}

EventInfo eventInfo = AssociatedObject.GetType ().GetRuntimeEvent (name);


if (eventInfo == null) {
throw new ArgumentException (string.Format ("EventToCommandBehavior: Can't register the '{0}' event.",
EventName));
}
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo ().GetDeclaredMethod ("OnEvent");
eventHandler = methodInfo.CreateDelegate (eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler (AssociatedObject, eventHandler);
}

void OnEvent (object sender, object eventArgs)


{
if (Command == null) {
return;
}

object resolvedParameter;
if (CommandParameter != null) {
resolvedParameter = CommandParameter;
} else if (Converter != null) {
resolvedParameter = Converter.Convert (eventArgs, typeof(object), null, null);
} else {
resolvedParameter = eventArgs;
}

if (Command.CanExecute (resolvedParameter)) {
Command.Execute (resolvedParameter);
}
}
...
}

The RegisterEvent method is executed in response to the EventToCommandBehavior being attached to a control, and
it receives the value of the EventName property as a parameter. The method then attempts to locate the event
defined in the EventName property, on the attached control. Provided that the event can be located, the OnEvent
method is registered to be the handler method for the event.
The OnEvent method is executed in response to the event firing that's defined in the EventName property. Provided
that the Command property references a valid ICommand , the method attempts to retrieve a parameter to pass to the
ICommand as follows:

If the CommandParameter property defines a parameter, it is retrieved.


Otherwise, if the Converter property defines an IValueConverter implementation, the converter is executed
and converts the event argument data as it's passed between source and target by the binding engine.
Otherwise, the event arguments are assumed to be the parameter.
The data bound ICommand is then executed, passing in the parameter to the command, provided that the
CanExecute method returns true .

Although not shown here, the EventToCommandBehavior also includes a DeregisterEvent method that's executed by
the OnDetachingFrom method. The DeregisterEvent method is used to locate and deregister the event defined in
the EventName property, to cleanup any potential memory leaks.
Consuming the Behavior
The EventToCommandBehavior class can be attached to the Behaviors collection of a control, as demonstrated in the
following XAML code example:

<ListView ItemsSource="{Binding People}">


<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<local:EventToCommandBehavior EventName="ItemSelected" Command="{Binding OutputAgeCommand}"
Converter="{StaticResource SelectedItemConverter}" />
</ListView.Behaviors>
</ListView>
<Label Text="{Binding SelectedItemText}" />

The equivalent C# code is shown in the following code example:

var listView = new ListView();


listView.SetBinding(ItemsView<Cell>.ItemsSourceProperty, "People");
listView.ItemTemplate = new DataTemplate(() =>
{
var textCell = new TextCell();
textCell.SetBinding(TextCell.TextProperty, "Name");
return textCell;
});
listView.Behaviors.Add(new EventToCommandBehavior
{
EventName = "ItemSelected",
Command = ((HomePageViewModel)BindingContext).OutputAgeCommand,
Converter = new SelectedItemEventArgsToSelectedItemConverter()
});

var selectedItemLabel = new Label();


selectedItemLabel.SetBinding(Label.TextProperty, "SelectedItemText");

The Command property of the behavior is data bound to the OutputAgeCommand property of the associated
ViewModel, while the Converter property is set to the SelectedItemConverter instance, which returns the
SelectedItem of the ListView from the SelectedItemChangedEventArgs .

At runtime, the behavior will respond to interaction with the control. When an item is selected in the ListView , the
ItemSelected event will fire, which will execute the OutputAgeCommand in the ViewModel. In turn this updates the
ViewModel SelectedItemText property that the Label binds to, as shown in the following screenshots:
The advantage of using this behavior to execute a command when an event fires, is that commands can be
associated with controls that weren't designed to interact with commands. In addition, this removes boiler-plate
event handling code from code-behind files.

Summary
This article demonstrated using a Xamarin.Forms behavior to invoke a command when an event fires. Behaviors
can be used to associate commands with controls that were not designed to interact with commands.

Related Links
EventToCommand Behavior (sample)
Behavior
Behavior<T>
Xamarin.Forms Custom Renderers
2 minutes to read • Edit Online

Xamarin.Forms user interfaces are rendered using the native controls of the target platform, allowing
Xamarin.Forms applications to retain the appropriate look and feel for each platform. Custom Renderers let
developers override this process to customize the appearance and behavior of Xamarin.Forms controls on each
platform.

Introduction to custom renderers


Custom renderers provide a powerful approach for customizing the appearance and behavior of Xamarin.Forms
controls. They can be used for small styling changes or sophisticated platform-specific layout and behavior
customization. This article provides an introduction to custom renderers, and outlines the process for creating a
custom renderer.

Renderer base classes and native controls


Every Xamarin.Forms control has an accompanying renderer for each platform that creates an instance of a
native control. This article lists the renderer and native control classes that implement each Xamarin.Forms page,
layout, view, and cell.

Customizing an Entry
The Xamarin.Forms Entry control allows a single line of text to be edited. This article demonstrates how to
create a custom renderer for the Entry control, enabling developers to override the default native rendering
with their own platform-specific customization.

Customizing a ContentPage
A ContentPage is a visual element that displays a single view and occupies most of the screen. This article
demonstrates how to create a custom renderer for the ContentPage page, enabling developers to override the
default native rendering with their own platform-specific customization.

Customizing a Map
Xamarin.Forms.Maps provides a cross-platform abstraction for displaying maps that use the native map APIs on
each platform, to provide a fast and familiar map experience for users. This topic demonstrates how to create
custom renderers for the Map control, enabling developers to override the default native rendering with their
own platform-specific customization.

Customizing a ListView
A Xamarin.Forms ListView is a view that displays a collection of data as a vertical list. This article demonstrates
how to create a custom renderer that encapsulates platform-specific list controls and native cell layouts, allowing
more control over native list control performance.

Customizing a ViewCell
A Xamarin.Forms ViewCell is a cell that can be added to a ListView or TableView , which contains a developer-
defined view. This article demonstrates how to create a custom renderer for a ViewCell that's hosted inside a
Xamarin.Forms ListView control. This stops the Xamarin.Forms layout calculations from being repeatedly called
during ListView scrolling.

Customizing a WebView
A Xamarin.Forms WebView is a view that displays web and HTML content in your app. This article explains how
to create a custom renderer that extends the WebView to allow C# code to be invoked from JavaScript.

Implementing a View
Xamarin.Forms custom user interfaces controls should derive from the View class, which is used to place
layouts and controls on the screen. This article demonstrates how to create a custom renderer for a
Xamarin.Forms custom control that's used to display a preview video stream from the device's camera.

Implementing a video player


This article shows how to write renderers to implement a custom VideoPlayer control that can play videos from
the web, videos embedded as application resources, or videos stored in the video library on the user's device.
Several techniques are demonstrated, including implementing methods and read-only bindable properties.
Introduction to Custom Renderers
4 minutes to read • Edit Online

Custom renderers provide a powerful approach for customizing the appearance and behavior of Xamarin.Forms
controls. They can be used for small styling changes or sophisticated platform -specific layout and behavior
customization. This article provides an introduction to custom renderers, and outlines the process for creating a
custom renderer.
Xamarin.Forms Pages, Layouts and Controls present a common API to describe cross-platform mobile user
interfaces. Each page, layout, and control is rendered differently on each platform, using a Renderer class that in
turn creates a native control (corresponding to the Xamarin.Forms representation), arranges it on the screen, and
adds the behavior specified in the shared code.
Developers can implement their own custom Renderer classes to customize the appearance and/or behavior of a
control. Custom renderers for a given type can be added to one application project to customize the control in one
place while allowing the default behavior on other platforms; or different custom renderers can be added to each
application project to create a different look and feel on iOS, Android, and the Universal Windows Platform
(UWP ). However, implementing a custom renderer class to perform a simple control customization is often a
heavy-weight response. Effects simplify this process, and are typically used for small styling changes. For more
information, see Effects.

Examining Why Custom Renderers are Necessary


Changing the appearance of a Xamarin.Forms control, without using a custom renderer, is a two-step process that
involves creating a custom control through subclassing, and then consuming the custom control in place of the
original control. The following code example shows an example of subclassing the Entry control:

public class MyEntry : Entry


{
public MyEntry ()
{
BackgroundColor = Color.Gray;
}
}

The MyEntry control is an Entry control where the BackgroundColor is set to gray, and can be referenced in Xaml
by declaring a namespace for its location and using the namespace prefix on the control element. The following
code example shows how the MyEntry custom control can be consumed by a ContentPage :

<ContentPage
...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<local:MyEntry Text="In Shared Code" />
...
</ContentPage>

The local namespace prefix can be anything. However, the namespace and assembly values must match the
details of the custom control. Once the namespace is declared, the prefix is used to reference the custom control.
NOTE
Defining the xmlns is much simpler in .NET Standard library projects than Shared Projects. A .NET Standard library is
compiled into an assembly so it's easy to determine what the assembly=CustomRenderer value should be. When using
Shared Projects, all the shared assets (including the XAML) are compiled into each of the referencing projects, which means
that if the iOS, Android, and UWP projects have their own assembly names it is impossible to write the xmlns declaration
because the value needs to be different for each application. Custom controls in XAML for Shared Projects will require every
application project to be configured with the same assembly name.

The MyEntry custom control is then rendered on each platform, with a gray background, as shown in the following
screenshots:

Changing the background color of the control on each platform has been accomplished purely through
subclassing the control. However, this technique is limited in what it can achieve as it is not possible to take
advantage of platform-specific enhancements and customizations. When they are required, custom renderers must
be implemented.

Creating a Custom Renderer Class


The process for creating a custom renderer class is as follows:
1. Create a subclass of the renderer class that renders the native control.
2. Override the method that renders the native control and write logic to customize the control. Often, the
OnElementChanged method is used to render the native control, which is called when the corresponding
Xamarin.Forms control is created.
3. Add an ExportRenderer attribute to the custom renderer class to specify that it will be used to render the
Xamarin.Forms control. This attribute is used to register the custom renderer with Xamarin.Forms.

NOTE
For most Xamarin.Forms elements, it is optional to provide a custom renderer in each platform project. If a custom renderer
isn't registered, then the default renderer for the control's base class will be used. However, custom renderers are required in
each platform project when rendering a View or ViewCell element.

The topics in this series will provide demonstrations and explanations of this process for different Xamarin.Forms
elements.

Troubleshooting
If a custom control is contained in a .NET Standard library project that's been added to the solution (i.e. not the
.NET Standard library created by the Visual Studio for Mac/Visual Studio Xamarin.Forms App project template), an
exception may occur in iOS when attempting to access the custom control. If this issue occurs it can be resolved by
creating a reference to the custom control from the AppDelegate class:

var temp = new ClassInPCL(); // in AppDelegate, but temp not used anywhere

This forces the compiler to recognize the ClassInPCL type by resolving it. Alternatively, the Preserve attribute can
be added to the AppDelegate class to achieve the same result:

[assembly: Preserve (typeof (ClassInPCL))]

This creates a reference to the ClassInPCL type, indicating that it's required at runtime. For more information, see
Preserving Code.

Summary
This article has provided an introduction to custom renderers, and has outlined the process for creating a custom
renderer. Custom renderers provide a powerful approach for customizing the appearance and behavior of
Xamarin.Forms controls. They can be used for small styling changes or sophisticated platform-specific layout and
behavior customization.

Related Links
Effects
Renderer Base Classes and Native Controls
2 minutes to read • Edit Online

Every Xamarin.Forms control has an accompanying renderer for each platform that creates an instance of a
native control. This article lists the renderer and native control classes that implement each Xamarin.Forms page,
layout, view, and cell.
With the exception of the MapRenderer class, the platform-specific renderers can be found in the following
namespaces:
iOS – Xamarin.Forms.Platform.iOS
Android – Xamarin.Forms.Platform.Android
Android (AppCompat) – Xamarin.Forms.Platform.Android.AppCompat
Universal Windows Platform (UWP ) – Xamarin.Forms.Platform.UWP
The MapRenderer class can be found in the following namespaces:
iOS – Xamarin.Forms.Maps.iOS
Android – Xamarin.Forms.Maps.Android
Universal Windows Platform (UWP ) – Xamarin.Forms.Maps.UWP

NOTE
For information about creating custom renderers for Shell applications, see Xamarin.Forms Shell Custom Renderers.

Pages
The following table lists the renderer and native control classes that implement each Xamarin.Forms Page type:

ANDROID
PAGE RENDERER IOS ANDROID (APPCOMPAT) UWP

ContentPage PageRenderer UIViewController ViewGroup FrameworkEleme


nt

MasterDetailPage PhoneMasterDet UIViewController DrawerLayout DrawerLayout FrameworkEleme


ailRenderer (iOS (Phone), (v4) (v4) nt (Custom
– Phone), UISplitViewContr Control)
TabletMasterDet oller (Tablet)
ailPageRenderer
(iOS – Tablet),
MasterDetailRen
derer (Android),
MasterDetailPag
eRenderer
(Android
AppCompat),
MasterDetailPag
eRenderer (UWP)
ANDROID
PAGE RENDERER IOS ANDROID (APPCOMPAT) UWP

NavigationPage NavigationRende UIToolbar ViewGroup ViewGroup FrameworkEleme


rer (iOS and nt (Custom
Android), Control)
NavigationPageR
enderer (Android
AppCompat),
NavigationPageR
enderer (UWP)

TabbedPage TabbedRenderer UIView ViewPager ViewPager FrameworkEleme


(iOS and nt (Pivot)
Android),
TabbedPageRend
erer (Android
AppCompat),
TabbedPageRend
erer (UWP)

TemplatedPage PageRenderer UIViewController ViewGroup FrameworkEleme


nt

CarouselPage CarouselPageRen UIScrollView ViewPager ViewPager FrameworkEleme


derer nt (FlipView)

Layouts
The following table lists the renderer and native control classes that implement each Xamarin.Forms Layout type:

LAYOUT RENDERER IOS ANDROID UWP

ContentPresenter ViewRenderer UIView View FrameworkElement

ContentView ViewRenderer UIView View FrameworkElement

FlexLayout ViewRenderer UIView View FrameworkElement

Frame FrameRenderer UIView ViewGroup Border

ScrollView ScrollViewRenderer UIScrollView ScrollView ScrollViewer

TemplatedView ViewRenderer UIView View FrameworkElement

AbsoluteLayout ViewRenderer UIView View FrameworkElement

Grid ViewRenderer UIView View FrameworkElement

RelativeLayout ViewRenderer UIView View FrameworkElement

StackLayout ViewRenderer UIView View FrameworkElement

Views
The following table lists the renderer and native control classes that implement each Xamarin.Forms View type:

ANDROID
VIEWS RENDERER IOS ANDROID (APPCOMPAT) UWP

ActivityIndicator ActivityIndicatorR UIActivityIndicat ProgressBar ProgressBar


enderer or

BoxView BoxRenderer (iOS UIView ViewGroup Rectangle


and Android),
BoxViewRenderer
(UWP)

Button ButtonRenderer UIButton Button AppCompatButto Button


n

CarouselView CarouselViewRen UICollectionView RecyclerView ListViewBase


derer

CheckBox CheckBoxRender UIButton AppCompatChec CheckBox


er kBox

CollectionView CollectionViewRe UICollectionView RecyclerView ListViewBase


nderer

DatePicker DatePickerRende UITextField EditText DatePicker


rer

Editor EditorRenderer UITextView EditText TextBox

Entry EntryRenderer UITextField EditText TextBox

Image ImageRenderer UIImageView ImageView Image

ImageButton ImageButtonRen UIButton AppCompatImag Button


derer eButton

IndicatorView IndicatorViewRen UIPageControl LinearLayout


derer

Label LabelRenderer UILabel TextView TextBlock

ListView ListViewRenderer UITableView ListView ListView

Map MapRenderer MKMapView MapView MapControl

Picker PickerRenderer UITextField EditText EditText ComboBox

ProgressBar ProgressBarRend UIProgressView ProgressBar ProgressBar


erer

RefreshView RefreshViewRend UIView SwipeRefreshLay RefreshContainer


erer out
ANDROID
VIEWS RENDERER IOS ANDROID (APPCOMPAT) UWP

SearchBar SearchBarRender UISearchBar SearchView AutoSuggestBox


er

Slider SliderRenderer UISlider SeekBar Slider

Stepper StepperRenderer UIStepper LinearLayout Control

SwipeView SwipeViewRender UIView View SwipeControl


er

Switch SwitchRenderer UISwitch Switch SwitchCompat ToggleSwitch

TableView TableViewRender UITableView ListView ListView


er

TimePicker TimePickerRende UITextField EditText TimePicker


rer

WebView WkWebViewRen WkWebView WebView WebView


derer (iOS),
WebViewRendere
r (Android and
UWP)

Cells
The following table lists the renderer and native control classes that implement each Xamarin.Forms Cell type:

CELLS RENDERER IOS ANDROID UWP

EntryCell EntryCellRenderer UITableViewCell with LinearLayout with a DataTemplate with a


a UITextField TextView and EditText TextBox

SwitchCell SwitchCellRenderer UITableViewCell with Switch DataTemplate with a


a UISwitch Grid containing a
TextBlock and
ToggleSwitch

TextCell TextCellRenderer UITableViewCell LinearLayout with DataTemplate with a


two TextViews StackPanel containing
two TextBlocks

ImageCell ImageCellRenderer UITableViewCell with LinearLayout with DataTemplate with a


a UIImage two TextViews and an Grid containing an
ImageView Image and two
TextBlocks

ViewCell ViewCellRenderer UITableViewCell View DataTemplate with a


ContentPresenter

Summary
This article has listed the renderer and native control classes that implement each Xamarin.Forms page, layout,
view, and cell. Every Xamarin.Forms control has an accompanying renderer for each platform that creates an
instance of a native control.
Customizing an Entry
6 minutes to read • Edit Online

Download the sample


The Xamarin.Forms Entry control allows a single line of text to be edited. This article demonstrates how to create a
custom renderer for the Entry control, enabling developers to override the default native rendering with their own
platform -specific customization.
Every Xamarin.Forms control has an accompanying renderer for each platform that creates an instance of a native
control. When an Entry control is rendered by a Xamarin.Forms application, in iOS the EntryRenderer class is
instantiated, which in turns instantiates a native UITextField control. On the Android platform, the EntryRenderer
class instantiates an EditText control. On the Universal Windows Platform (UWP ), the EntryRenderer class
instantiates a TextBox control. For more information about the renderer and native control classes that
Xamarin.Forms controls map to, see Renderer Base Classes and Native Controls.
The following diagram illustrates the relationship between the Entry control and the corresponding native
controls that implement it:

The rendering process can be taken advantage of to implement platform-specific customizations by creating a
custom renderer for the Entry control on each platform. The process for doing this is as follows:
1. Create a Xamarin.Forms custom control.
2. Consume the custom control from Xamarin.Forms.
3. Create the custom renderer for the control on each platform.
Each item will now be discussed in turn, to implement an Entry control that has a different background color on
each platform.

IMPORTANT
This article explains how to create a simple custom renderer. However, it's not necessary to create a custom renderer to
implement an Entry that has a different background color on each platform. This can be more easily accomplished by
using the Device class, or the OnPlatform markup extension, to provide platform-specific values. For more information,
see Providing Platform-Specific Values and OnPlatform Markup Extension.

Creating the Custom Entry Control


A custom Entry control can be created by subclassing the Entry control, as shown in the following code
example:

public class MyEntry : Entry


{
}

The MyEntry control is created in the .NET Standard library project and is simply an Entry control. Customization
of the control will be carried out in the custom renderer, so no additional implementation is required in the
MyEntry control.

Consuming the Custom Control


The MyEntry control can be referenced in XAML in the .NET Standard library project by declaring a namespace
for its location and using the namespace prefix on the control element. The following code example shows how the
MyEntry control can be consumed by a XAML page:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<local:MyEntry Text="In Shared Code" />
...
</ContentPage>

The local namespace prefix can be named anything. However, the clr-namespace and assembly values must
match the details of the custom control. Once the namespace is declared the prefix is used to reference the custom
control.
The following code example shows how the MyEntry control can be consumed by a C# page:

public class MainPage : ContentPage


{
public MainPage ()
{
Content = new StackLayout {
Children = {
new Label {
Text = "Hello, Custom Renderer !",
},
new MyEntry {
Text = "In Shared Code",
}
},
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
}
}

This code instantiates a new ContentPage object that will display a Label and MyEntry control centered both
vertically and horizontally on the page.
A custom renderer can now be added to each application project to customize the control's appearance on each
platform.

Creating the Custom Renderer on each Platform


The process for creating the custom renderer class is as follows:
1. Create a subclass of the EntryRenderer class that renders the native control.
2. Override the OnElementChanged method that renders the native control and write logic to customize the control.
This method is called when the corresponding Xamarin.Forms control is created.
3. Add an ExportRenderer attribute to the custom renderer class to specify that it will be used to render the
Xamarin.Forms control. This attribute is used to register the custom renderer with Xamarin.Forms.

NOTE
It is optional to provide a custom renderer in each platform project. If a custom renderer isn't registered, then the default
renderer for the control's base class will be used.

The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationships between them:

The MyEntry control is rendered by platform-specific MyEntryRenderer classes, which all derive from the
EntryRenderer class for each platform. This results in each MyEntry control being rendered with a platform -
specific background color, as shown in the following screenshots:

The EntryRenderer class exposes the OnElementChanged method, which is called when the Xamarin.Forms control
is created to render the corresponding native control. This method takes an ElementChangedEventArgs parameter
that contains OldElement and NewElement properties. These properties represent the Xamarin.Forms element that
the renderer was attached to, and the Xamarin.Forms element that the renderer is attached to, respectively. In the
sample application the OldElement property will be null and the NewElement property will contain a reference to
the MyEntry control.
An overridden version of the OnElementChanged method in the MyEntryRenderer class is the place to perform the
native control customization. A typed reference to the native control being used on the platform can be accessed
through the Control property. In addition, a reference to the Xamarin.Forms control that's being rendered can be
obtained through the Element property, although it's not used in the sample application.
Each custom renderer class is decorated with an ExportRenderer attribute that registers the renderer with
Xamarin.Forms. The attribute takes two parameters – the type name of the Xamarin.Forms control being rendered,
and the type name of the custom renderer. The assembly prefix to the attribute specifies that the attribute applies
to the entire assembly.
The following sections discuss the implementation of each platform-specific MyEntryRenderer custom renderer
class.
Creating the Custom Renderer on iOS
The following code example shows the custom renderer for the iOS platform:

using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer (typeof(MyEntry), typeof(MyEntryRenderer))]


namespace CustomRenderer.iOS
{
public class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged (ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged (e);

if (Control != null) {
// do whatever you want to the UITextField here!
Control.BackgroundColor = UIColor.FromRGB (204, 153, 255);
Control.BorderStyle = UITextBorderStyle.Line;
}
}
}
}

The call to the base class's OnElementChanged method instantiates an iOS UITextField control, with a reference to
the control being assigned to the renderer's Control property. The background color is then set to light purple
with the UIColor.FromRGB method.
Creating the Custom Renderer on Android
The following code example shows the custom renderer for the Android platform:

using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]


namespace CustomRenderer.Android
{
class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context)
{
}

protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)


{
base.OnElementChanged(e);

if (Control != null)
{
Control.SetBackgroundColor(global::Android.Graphics.Color.LightGreen);
}
}
}
}

The call to the base class's OnElementChanged method instantiates an Android EditText control, with a reference to
the control being assigned to the renderer's Control property. The background color is then set to light green
with the Control.SetBackgroundColor method.
Creating the Custom Renderer on UWP
The following code example shows the custom renderer for UWP:

[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]


namespace CustomRenderer.UWP
{
public class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);

if (Control != null)
{
Control.Background = new SolidColorBrush(Colors.Cyan);
}
}
}
}

The call to the base class's OnElementChanged method instantiates a TextBox control, with a reference to the
control being assigned to the renderer's Control property. The background color is then set to cyan by creating a
SolidColorBrush instance.

Summary
This article has demonstrated how to create a custom control renderer for the Xamarin.Forms Entry control,
enabling developers to override the default native rendering with their own platform-specific rendering. Custom
renderers provide a powerful approach to customizing the appearance of Xamarin.Forms controls. They can be
used for small styling changes or sophisticated platform-specific layout and behavior customization.

Related Links
CustomRendererEntry (sample)
Customizing a ContentPage
7 minutes to read • Edit Online

Download the sample


A ContentPage is a visual element that displays a single view and occupies most of the screen. This article
demonstrates how to create a custom renderer for the ContentPage page, enabling developers to override the
default native rendering with their own platform -specific customization.
Every Xamarin.Forms control has an accompanying renderer for each platform that creates an instance of a native
control. When a ContentPage is rendered by a Xamarin.Forms application, in iOS the PageRenderer class is
instantiated, which in turn instantiates a native UIViewController control. On the Android platform, the
PageRenderer class instantiates a ViewGroup control. On the Universal Windows Platform ( UWP ), the
PageRenderer class instantiates a FrameworkElement control. For more information about the renderer and native
control classes that Xamarin.Forms controls map to, see Renderer Base Classes and Native Controls.
The following diagram illustrates the relationship between the ContentPage and the corresponding native controls
that implement it:

The rendering process can be taken advantage of to implement platform-specific customizations by creating a
custom renderer for a ContentPage on each platform. The process for doing this is as follows:
1. Create a Xamarin.Forms page.
2. Consume the page from Xamarin.Forms.
3. Create the custom renderer for the page on each platform.
Each item will now be discussed in turn, to implement a CameraPage that provides a live camera feed and the
ability to capture a photo.

Creating the Xamarin.Forms Page


An unaltered ContentPage can be added to the shared Xamarin.Forms project, as shown in the following XAML
code example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CustomRenderer.CameraPage">
<ContentPage.Content>
</ContentPage.Content>
</ContentPage>

Similarly, the code-behind file for the ContentPage should also remain unaltered, as shown in the following code
example:

public partial class CameraPage : ContentPage


{
public CameraPage ()
{
// A custom renderer is used to display the camera UI
InitializeComponent ();
}
}

The following code example shows how the page can be created in C#:

public class CameraPageCS : ContentPage


{
public CameraPageCS ()
{
}
}

An instance of the CameraPage will be used to display the live camera feed on each platform. Customization of the
control will be carried out in the custom renderer, so no additional implementation is required in the CameraPage
class.

Consuming the Xamarin.Forms Page


The empty CameraPage must be displayed by the Xamarin.Forms application. This occurs when a button on the
MainPage instance is tapped, which in turn executes the OnTakePhotoButtonClicked method, as shown in the
following code example:

async void OnTakePhotoButtonClicked (object sender, EventArgs e)


{
await Navigation.PushAsync (new CameraPage ());
}

This code simply navigates to the CameraPage , on which custom renderers will customize the page's appearance on
each platform.

Creating the Page Renderer on each Platform


The process for creating the custom renderer class is as follows:
1. Create a subclass of the PageRenderer class.
2. Override the OnElementChanged method that renders the native page and write logic to customize the page. The
OnElementChanged method is called when the corresponding Xamarin.Forms control is created.
3. Add an ExportRenderer attribute to the page renderer class to specify that it will be used to render the
Xamarin.Forms page. This attribute is used to register the custom renderer with Xamarin.Forms.
NOTE
It is optional to provide a page renderer in each platform project. If a page renderer isn't registered, then the default renderer
for the page will be used.

The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationship between them:

The CameraPage instance is rendered by platform-specific CameraPageRenderer classes, which all derive from the
PageRenderer class for that platform. This results in each CameraPage instance being rendered with a live camera
feed, as shown in the following screenshots:

The PageRenderer class exposes the OnElementChanged method, which is called when the Xamarin.Forms page is
created to render the corresponding native control. This method takes an ElementChangedEventArgs parameter that
contains OldElement and NewElement properties. These properties represent the Xamarin.Forms element that the
renderer was attached to, and the Xamarin.Forms element that the renderer is attached to, respectively. In the
sample application the OldElement property will be null and the NewElement property will contain a reference to
the CameraPage instance.
An overridden version of the OnElementChanged method in the CameraPageRenderer class is the place to perform the
native page customization. A reference to the Xamarin.Forms page instance that's being rendered can be obtained
through the Element property.
Each custom renderer class is decorated with an ExportRenderer attribute that registers the renderer with
Xamarin.Forms. The attribute takes two parameters – the type name of the Xamarin.Forms page being rendered,
and the type name of the custom renderer. The assembly prefix to the attribute specifies that the attribute applies
to the entire assembly.
The following sections discuss the implementation of the CameraPageRenderer custom renderer for each platform.
Creating the Page Renderer on iOS
The following code example shows the page renderer for the iOS platform:

[assembly:ExportRenderer (typeof(CameraPage), typeof(CameraPageRenderer))]


namespace CustomRenderer.iOS
{
public class CameraPageRenderer : PageRenderer
{
...

protected override void OnElementChanged (VisualElementChangedEventArgs e)


{
base.OnElementChanged (e);

if (e.OldElement != null || Element == null) {


return;
}

try {
SetupUserInterface ();
SetupEventHandlers ();
SetupLiveCameraStream ();
AuthorizeCameraUse ();
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (@" ERROR: ", ex.Message);
}
}
...
}
}

The call to the base class's OnElementChanged method instantiates an iOS UIViewController control. The live
camera stream is only rendered provided that the renderer isn't already attached to an existing Xamarin.Forms
element, and provided that a page instance exists that is being rendered by the custom renderer.
The page is then customized by a series of methods that use the AVCapture APIs to provide the live stream from
the camera and the ability to capture a photo.
Creating the Page Renderer on Android
The following code example shows the page renderer for the Android platform:
[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.Droid
{
public class CameraPageRenderer : PageRenderer, TextureView.ISurfaceTextureListener
{
...
public CameraPageRenderer(Context context) : base(context)
{
}

protected override void OnElementChanged(ElementChangedEventArgs<Page> e)


{
base.OnElementChanged(e);

if (e.OldElement != null || Element == null)


{
return;
}

try
{
SetupUserInterface();
SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
}
}
...
}
}

The call to the base class's OnElementChanged method instantiates an Android ViewGroup control, which is a group
of views. The live camera stream is only rendered provided that the renderer isn't already attached to an existing
Xamarin.Forms element, and provided that a page instance exists that is being rendered by the custom renderer.
The page is then customized by invoking a series of methods that use the Camera API to provide the live stream
from the camera and the ability to capture a photo, before the AddView method is invoked to add the live camera
stream UI to the ViewGroup . Note that on Android it's also necessary to override the OnLayout method to perform
measure and layout operations on the view. For more information, see the ContentPage renderer sample.
Creating the Page Renderer on UWP
The following code example shows the page renderer for UWP:
[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.UWP
{
public class CameraPageRenderer : PageRenderer
{
...
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
{
base.OnElementChanged(e);

if (e.OldElement != null || Element == null)


{
return;
}

try
{
...
SetupUserInterface();
SetupBasedOnStateAsync();

this.Children.Add(page);
}
...
}

protected override Size ArrangeOverride(Size finalSize)


{
page.Arrange(new Windows.Foundation.Rect(0, 0, finalSize.Width, finalSize.Height));
return finalSize;
}
...
}
}

The call to the base class's OnElementChanged method instantiates a FrameworkElement control, on which the page is
rendered. The live camera stream is only rendered provided that the renderer isn't already attached to an existing
Xamarin.Forms element, and provided that a page instance exists that is being rendered by the custom renderer.
The page is then customized by invoking a series of methods that use the MediaCapture API to provide the live
stream from the camera and the ability to capture a photo before the customized page is added to the Children
collection for display.
When implementing a custom renderer that derives from PageRenderer on UWP, the ArrangeOverride method
should also be implemented to arrange the page controls, because the base renderer doesn't know what to do with
them. Otherwise, a blank page results. Therefore, in this example the ArrangeOverride method calls the Arrange
method on the Page instance.

NOTE
It's important to stop and dispose of the objects that provide access to the camera in a UWP application. Failure to do so
can interfere with other applications that attempt to access the device's camera. For more information, see Display the
camera preview.

Summary
This article has demonstrated how to create a custom renderer for the ContentPage page, enabling developers to
override the default native rendering with their own platform-specific customization. A ContentPage is a visual
element that displays a single view and occupies most of the screen.
Related Links
CustomRendererContentPage (sample)
Customizing a Xamarin.Forms Map
2 minutes to read • Edit Online

Xamarin.Forms.Maps provides a cross-platform abstraction for displaying maps that use the native map APIs on
each platform, to provide a fast and familiar map experience for users.

Customizing a Map Pin


This article explains how to create a custom renderer for the Map control, which displays a native map with a
customized pin and a customized view of the pin data on each platform.

Highlighting a Circular Area on a Map


This article explains how to add a circular overlay to a map, to highlight a circular area of the map.

Highlighting a Region on a Map


This article explains how to add a polygon overlay to a map, to highlight a region on the map. Polygons are a
closed shape and have their interiors filled in.

Highlighting a Route on a Map


This article explains how to add a polyline overlay to a map. A polyline overlay is a series of connected line
segments that are typically used to show a route on a map, or form any shape that's required.
Customizing a Map Pin
20 minutes to read • Edit Online

Download the sample


This article demonstrates how to create a custom renderer for the Map control, which displays a native map with a
customized pin and a customized view of the pin data on each platform.
Every Xamarin.Forms view has an accompanying renderer for each platform that creates an instance of a native
control. When a Map is rendered by a Xamarin.Forms application in iOS, the MapRenderer class is instantiated,
which in turn instantiates a native MKMapView control. On the Android platform, the MapRenderer class instantiates
a native MapView control. On the Universal Windows Platform (UWP ), the MapRenderer class instantiates a native
MapControl . For more information about the renderer and native control classes that Xamarin.Forms controls map
to, see Renderer Base Classes and Native Controls.
The following diagram illustrates the relationship between the Map and the corresponding native controls that
implement it:

The rendering process can be used to implement platform-specific customizations by creating a custom renderer
for a Map on each platform. The process for doing this is as follows:
1. Create a Xamarin.Forms custom map.
2. Consume the custom map from Xamarin.Forms.
3. Create the custom renderer for the map on each platform.
Each item will now be discussed in turn, to implement a CustomMap renderer that displays a native map with a
customized pin and a customized view of the pin data on each platform.

NOTE
Xamarin.Forms.Maps must be initialized and configured before use. For more information, see Maps Control .

Creating the Custom Map


A custom map control can be created by subclassing the Map class, as shown in the following code example:
public class CustomMap : Map
{
public List<CustomPin> CustomPins { get; set; }
}

The CustomMap control is created in the .NET Standard library project and defines the API for the custom map. The
custom map exposes the CustomPins property that represents the collection of CustomPin objects that will be
rendered by the native map control on each platform. The CustomPin class is shown in the following code
example:

public class CustomPin : Pin


{
public string Name { get; set; }
public string Url { get; set; }
}

This class defines a CustomPin as inheriting the properties of the Pin class, and adding Name and Url
properties.

Consuming the Custom Map


The CustomMap control can be referenced in XAML in the .NET Standard library project by declaring a namespace
for its location and using the namespace prefix on the custom map control. The following code example shows
how the CustomMap control can be consumed by a XAML page:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer">
<local:CustomMap x:Name="customMap"
MapType="Street" />
</ContentPage>

The local namespace prefix can be named anything. However, the clr-namespace and assembly values must
match the details of the custom map. Once the namespace is declared, the prefix is used to reference the custom
map.
The following code example shows how the CustomMap control can be consumed by a C# page:

public class MapPageCS : ContentPage


{
public MapPageCS()
{
CustomMap customMap = new CustomMap
{
MapType = MapType.Street
};
// ...
Content = customMap;
}
}

The CustomMap instance will be used to display the native map on each platform. It's MapType property sets the
display style of the Map , with the possible values being defined in the MapType enumeration.
The location of the map, and the pins it contains, are initialized as shown in the following code example:
public MapPage()
{
// ...
CustomPin pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(37.79752, -122.40183),
Label = "Xamarin San Francisco Office",
Address = "394 Pacific Ave, San Francisco CA",
Name = "Xamarin",
Url = "http://xamarin.com/about/"
};
customMap.CustomPins = new List<CustomPin> { pin };
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183),
Distance.FromMiles(1.0)));
}

This initialization adds a custom pin and positions the map's view with the MoveToRegion method, which changes
the position and zoom level of the map by creating a MapSpan from a Position and a Distance .
A custom renderer can now be added to each application project to customize the native map controls.

Creating the Custom Renderer on each Platform


The process for creating the custom renderer class is as follows:
1. Create a subclass of the MapRenderer class that renders the custom map.
2. Override the OnElementChanged method that renders the custom map and write logic to customize it. This
method is called when the corresponding Xamarin.Forms custom map is created.
3. Add an ExportRenderer attribute to the custom renderer class to specify that it will be used to render the
Xamarin.Forms custom map. This attribute is used to register the custom renderer with Xamarin.Forms.

NOTE
It is optional to provide a custom renderer in each platform project. If a custom renderer isn't registered, then the default
renderer for the control's base class will be used.

The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationships between them:

The CustomMap control is rendered by platform-specific renderer classes, which derive from the MapRenderer class
for each platform. This results in each CustomMap control being rendered with platform-specific controls, as shown
in the following screenshots:
The MapRenderer class exposes the OnElementChanged method, which is called when the Xamarin.Forms custom
map is created to render the corresponding native control. This method takes an ElementChangedEventArgs
parameter that contains OldElement and NewElement properties. These properties represent the Xamarin.Forms
element that the renderer was attached to, and the Xamarin.Forms element that the renderer is attached to,
respectively. In the sample application the OldElement property will be null and the NewElement property will
contain a reference to the CustomMap instance.
An overridden version of the OnElementChanged method, in each platform-specific renderer class, is the place to
perform the native control customization. A typed reference to the native control being used on the platform can
be accessed through the Control property. In addition, a reference to the Xamarin.Forms control that's being
rendered can be obtained through the Element property.
Care must be taken when subscribing to event handlers in the OnElementChanged method, as demonstrated in the
following code example:

protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.View> e)


{
base.OnElementChanged (e);

if (e.OldElement != null)
{
// Unsubscribe from event handlers
}

if (e.NewElement != null)
{
// Configure the native control and subscribe to event handlers
}
}

The native control should be configured and event handlers subscribed to only when the custom renderer is
attached to a new Xamarin.Forms element. Similarly, any event handlers that were subscribed to should be
unsubscribed from only when the element that the renderer is attached to changes. Adopting this approach will
help to create a custom renderer that doesn't suffer from memory leaks.
Each custom renderer class is decorated with an ExportRenderer attribute that registers the renderer with
Xamarin.Forms. The attribute takes two parameters – the type name of the Xamarin.Forms custom control being
rendered, and the type name of the custom renderer. The assembly prefix to the attribute specifies that the
attribute applies to the entire assembly.
The following sections discuss the implementation of each platform-specific custom renderer class.
Creating the Custom Renderer on iOS
The following screenshots show the map, before and after customization:
On iOS the pin is called an annotation, and can be either a custom image or a system-defined pin of various
colors. Annotations can optionally show a callout, which is displayed in response to the user selecting the
annotation. The callout displays the Label and Address properties of the Pin instance, with optional left and
right accessory views. In the screenshot above, the left accessory view is the image of a monkey, with the right
accessory view being the Information button.
The following code example shows the custom renderer for the iOS platform:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]


namespace CustomRenderer.iOS
{
public class CustomMapRenderer : MapRenderer
{
UIView customPinView;
List<CustomPin> customPins;

protected override void OnElementChanged(ElementChangedEventArgs<View> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
var nativeMap = Control as MKMapView;
if (nativeMap != null)
{
nativeMap.RemoveAnnotations(nativeMap.Annotations);
nativeMap.GetViewForAnnotation = null;
nativeMap.CalloutAccessoryControlTapped -= OnCalloutAccessoryControlTapped;
nativeMap.DidSelectAnnotationView -= OnDidSelectAnnotationView;
nativeMap.DidDeselectAnnotationView -= OnDidDeselectAnnotationView;
}
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
customPins = formsMap.CustomPins;

nativeMap.GetViewForAnnotation = GetViewForAnnotation;
nativeMap.CalloutAccessoryControlTapped += OnCalloutAccessoryControlTapped;
nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;
}
}
// ...
}
}

The OnElementChanged method performs the following configuration of the MKMapView instance, provided that the
custom renderer is attached to a new Xamarin.Forms element:
The GetViewForAnnotation property is set to the GetViewForAnnotation method. This method is called when the
location of the annotation becomes visible on the map, and is used to customize the annotation prior to display.
Event handlers for the CalloutAccessoryControlTapped , DidSelectAnnotationView , and
DidDeselectAnnotationView events are registered. These events fire when the user taps the right accessory in
the callout, and when the user selects and deselects the annotation, respectively. The events are unsubscribed
from only when the element the renderer is attached to changes.
Displaying the Annotation
The GetViewForAnnotation method is called when the location of the annotation becomes visible on the map, and
is used to customize the annotation prior to display. An annotation has two parts:
– includes the title, subtitle, and location of the annotation.
MkAnnotation
MkAnnotationView – contains the image to represent the annotation, and optionally, a callout that is shown
when the user taps the annotation.
The GetViewForAnnotation method accepts an IMKAnnotation that contains the annotation's data and returns an
MKAnnotationView for display on the map, and is shown in the following code example:

protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)


{
MKAnnotationView annotationView = null;

if (annotation is MKUserLocation)
return null;

var customPin = GetCustomPin(annotation as MKPointAnnotation);


if (customPin == null)
{
throw new Exception("Custom pin not found");
}

annotationView = mapView.DequeueReusableAnnotation(customPin.Name);
if (annotationView == null)
{
annotationView = new CustomMKAnnotationView(annotation, customPin.Name);
annotationView.Image = UIImage.FromFile("pin.png");
annotationView.CalloutOffset = new CGPoint(0, 0);
annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
((CustomMKAnnotationView)annotationView).Name = customPin.Name;
((CustomMKAnnotationView)annotationView).Url = customPin.Url;
}
annotationView.CanShowCallout = true;

return annotationView;
}

This method ensures that the annotation will be displayed as a custom image, rather than as system-defined pin,
and that when the annotation is tapped a callout will be displayed that includes additional content to the left and
right of the annotation title and address. This is accomplished as follows:
1. The GetCustomPin method is called to return the custom pin data for the annotation.
2. To conserve memory, the annotation's view is pooled for reuse with the call to DequeueReusableAnnotation .
3. The CustomMKAnnotationView class extends the MKAnnotationView class with Name and Url properties that
correspond to identical properties in the CustomPin instance. A new instance of the CustomMKAnnotationView is
created, provided that the annotation is null :
The CustomMKAnnotationView.Image property is set to the image that will represent the annotation on the
map.
The CustomMKAnnotationView.CalloutOffset property is set to a CGPoint that specifies that the callout will
be centered above the annotation.
The CustomMKAnnotationView.LeftCalloutAccessoryView property is set to an image of a monkey that will
appear to the left of the annotation title and address.
The CustomMKAnnotationView.RightCalloutAccessoryView property is set to an Information button that will
appear to the right of the annotation title and address.
The CustomMKAnnotationView.Name property is set to the CustomPin.Name property returned by the
GetCustomPin method. This enables the annotation to be identified so that it's callout can be further
customized, if desired.
The CustomMKAnnotationView.Url property is set to the CustomPin.Url property returned by the
GetCustomPin method. The URL will be navigated to when the user taps the button displayed in the right
callout accessory view.
4. The MKAnnotationView.CanShowCallout property is set to true so that the callout is displayed when the
annotation is tapped.
5. The annotation is returned for display on the map.
Selecting the Annotation
When the user taps on the annotation, the DidSelectAnnotationView event fires, which in turn executes the
OnDidSelectAnnotationView method:

void OnDidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)


{
CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
customPinView = new UIView();

if (customView.Name.Equals("Xamarin"))
{
customPinView.Frame = new CGRect(0, 0, 200, 84);
var image = new UIImageView(new CGRect(0, 0, 200, 84));
image.Image = UIImage.FromFile("xamarin.png");
customPinView.AddSubview(image);
customPinView.Center = new CGPoint(0, -(e.View.Frame.Height + 75));
e.View.AddSubview(customPinView);
}
}

This method extends the existing callout (that contains left and right accessory views) by adding a UIView instance
to it that contains an image of the Xamarin logo, provided that the selected annotation has its Name property set
to Xamarin . This allows for scenarios where different callouts can be displayed for different annotations. The
UIView instance will be displayed centered above the existing callout.

Tapping on the Right Callout Accessory View


When the user taps on the Information button in the right callout accessory view, the
CalloutAccessoryControlTapped event fires, which in turn executes the OnCalloutAccessoryControlTapped method:

void OnCalloutAccessoryControlTapped(object sender, MKMapViewAccessoryTappedEventArgs e)


{
CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
if (!string.IsNullOrWhiteSpace(customView.Url))
{
UIApplication.SharedApplication.OpenUrl(new Foundation.NSUrl(customView.Url));
}
}

This method opens a web browser and navigates to the address stored in the CustomMKAnnotationView.Url
property. Note that the address was defined when creating the CustomPin collection in the .NET Standard library
project.
Deselecting the Annotation
When the annotation is displayed and the user taps on the map, the DidDeselectAnnotationView event fires, which
in turn executes the OnDidDeselectAnnotationView method:

void OnDidDeselectAnnotationView(object sender, MKAnnotationViewEventArgs e)


{
if (!e.View.Selected)
{
customPinView.RemoveFromSuperview();
customPinView.Dispose();
customPinView = null;
}
}

This method ensures that when the existing callout is not selected, the extended part of the callout (the image of
the Xamarin logo) will also stop being displayed, and its resources will be released.
For more information about customizing a MKMapView instance, see iOS Maps.
Creating the Custom Renderer on Android
The following screenshots show the map, before and after customization:

On Android the pin is called a marker, and can either be a custom image or a system-defined marker of various
colors. Markers can show an info window, which is displayed in response to the user tapping on the marker. The
info window displays the Label and Address properties of the Pin instance, and can be customized to include
other content. However, only one info window can be shown at once.
The following code example shows the custom renderer for the Android platform:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.Droid
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter
{
List<CustomPin> customPins;

public CustomMapRenderer(Context context) : base(context)


{
}

protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map>


e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
}
}

protected override void OnMapReady(GoogleMap map)


{
base.OnMapReady(map);

NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
...
}
}

Provided that the custom renderer is attached to a new Xamarin.Forms element, the OnElementChanged method
retrieves the list of custom pins from the control. Once the GoogleMap instance is available, the OnMapReady
override will be invoked. This method registers an event handler for the InfoWindowClick event, which fires when
the info window is clicked, and is unsubscribed from only when the element the renderer is attached to changes.
The OnMapReady override also calls the SetInfoWindowAdapter method to specify that the CustomMapRenderer class
instance will provide the methods to customize the info window.
The CustomMapRenderer class implements the GoogleMap.IInfoWindowAdapter interface to customize the info
window. This interface specifies that the following methods must be implemented:
public Android.Views.View GetInfoWindow(Marker marker) – This method is called to return a custom info
window for a marker. If it returns null , then the default window rendering will be used. If it returns a View ,
then that View will be placed inside the info window frame.
public Android.Views.View GetInfoContents(Marker marker) – This method is called to return a View containing
the content of the info window, and will only be called if the GetInfoWindow method returns null . If it returns
null , then the default rendering of the info window content will be used.

In the sample application, only the info window content is customized, and so the GetInfoWindow method returns
null to enable this.

Customizing the Marker


The icon used to represent a marker can be customized by calling the MarkerOptions.SetIcon method. This can be
accomplished by overriding the CreateMarker method, which is invoked for each Pin that's added to the map:

protected override MarkerOptions CreateMarker(Pin pin)


{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
marker.SetTitle(pin.Label);
marker.SetSnippet(pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
return marker;
}

This method creates a new MarkerOption instance for each Pin instance. After setting the position, label, and
address of the marker, its icon is set with the SetIcon method. This method takes a BitmapDescriptor object
containing the data necessary to render the icon, with the BitmapDescriptorFactory class providing helper
methods to simplify the creation of the BitmapDescriptor . For more information about using the
BitmapDescriptorFactory class to customize a marker, see Customizing a Marker.

NOTE
If required, the GetMarkerForPin method can be invoked in your map renderer to retrieve a Marker from a Pin .

Customizing the Info Window


When a user taps on the marker, the GetInfoContents method is executed, provided that the GetInfoWindow
method returns null . The following code example shows the GetInfoContents method:
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as
Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;

var customPin = GetCustomPin(marker);


if (customPin == null)
{
throw new Exception("Custom pin not found");
}

if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}

var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);


var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);

if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}

return view;
}
return null;
}

This method returns a View containing the contents of the info window. This is accomplished as follows:
A LayoutInflater instance is retrieved. This is used to instantiate a layout XML file into its corresponding
View .
The GetCustomPinmethod is called to return the custom pin data for the info window.
The XamarinMapInfoWindow layout is inflated if the CustomPin.Name property is equal to Xamarin . Otherwise, the
MapInfoWindow layout is inflated. This allows for scenarios where different info window layouts can be
displayed for different markers.
The InfoWindowTitle and InfoWindowSubtitle resources are retrieved from the inflated layout, and their Text
properties are set to the corresponding data from the Marker instance, provided that the resources are not
null .
The View instance is returned for display on the map.

NOTE
An info window is not a live View . Instead, Android will convert the View to a static bitmap and display that as an image.
This means that while an info window can respond to a click event, it cannot respond to any touch events or gestures, and
the individual controls in the info window cannot respond to their own click events.

Clicking on the Info Window


When the user clicks on the info window, the InfoWindowClick event fires, which in turn executes the
OnInfoWindowClick method:

void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)


{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}

if (!string.IsNullOrWhiteSpace(customPin.Url))
{
var url = Android.Net.Uri.Parse(customPin.Url);
var intent = new Intent(Intent.ActionView, url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}

This method opens a web browser and navigates to the address stored in the Url property of the retrieved
CustomPin instance for the Marker . Note that the address was defined when creating the CustomPin collection in
the .NET Standard library project.
For more information about customizing a MapView instance, see Maps API.
Creating the Custom Renderer on the Universal Windows Platform
The following screenshots show the map, before and after customization:

On UWP the pin is called a map icon, and can either be a custom image or the system-defined default image. A
map icon can show a UserControl , which is displayed in response to the user tapping on the map icon. The
UserControl can display any content, including the Label and Address properties of the Pin instance.

The following code example shows the UWP custom renderer:


[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.UWP
{
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
List<CustomPin> customPins;
XamarinMapOverlay mapOverlay;
bool xamarinOverlayShown = false;

protected override void OnElementChanged(ElementChangedEventArgs<Map> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
nativeMap.MapElementClick -= OnMapElementClick;
nativeMap.Children.Clear();
mapOverlay = null;
nativeMap = null;
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
nativeMap = Control as MapControl;
customPins = formsMap.CustomPins;

nativeMap.Children.Clear();
nativeMap.MapElementClick += OnMapElementClick;

foreach (var pin in customPins)


{
var snPosition = new BasicGeoposition { Latitude = pin.Pin.Position.Latitude, Longitude =
pin.Pin.Position.Longitude };
var snPoint = new Geopoint(snPosition);

var mapIcon = new MapIcon();


mapIcon.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///pin.png"));
mapIcon.CollisionBehaviorDesired = MapElementCollisionBehavior.RemainVisible;
mapIcon.Location = snPoint;
mapIcon.NormalizedAnchorPoint = new Windows.Foundation.Point(0.5, 1.0);

nativeMap.MapElements.Add(mapIcon);
}
}
}
...
}
}

The OnElementChanged method performs the following operations, provided that the custom renderer is attached
to a new Xamarin.Forms element:
It clears the MapControl.Children collection to remove any existing user interface elements from the map,
before registering an event handler for the MapElementClick event. This event fires when the user taps or clicks
on a MapElement on the MapControl , and is unsubscribed from only when the element the renderer is attached
to changes.
Each pin in the customPins collection is displayed at the correct geographic location on the map as follows:
The location for the pin is created as a Geopoint instance.
A MapIcon instance is created to represent the pin.
The image used to represent the MapIcon is specified by setting the MapIcon.Image property. However,
the map icon's image is not always guaranteed to be shown, as it may be obscured by other elements on
the map. Therefore, the map icon's CollisionBehaviorDesired property is set to
MapElementCollisionBehavior.RemainVisible , to ensure that it remains visible.
The location of the MapIcon is specified by setting the MapIcon.Location property.
The MapIcon.NormalizedAnchorPoint property is set to the approximate location of the pointer on the
image. If this property retains its default value of (0,0), which represents the upper left corner of the
image, changes in the zoom level of the map may result in the image pointing to a different location.
The MapIcon instance is added to the MapControl.MapElements collection. This results in the map icon
being displayed on the MapControl .

NOTE
When using the same image for multiple map icons, the RandomAccessStreamReference instance should be declared at the
page or application level for best performance.

Displaying the UserControl


When a user taps on the map icon, the OnMapElementClick method is executed. The following code example shows
this method:

private void OnMapElementClick(MapControl sender, MapElementClickEventArgs args)


{
var mapIcon = args.MapElements.FirstOrDefault(x => x is MapIcon) as MapIcon;
if (mapIcon != null)
{
if (!xamarinOverlayShown)
{
var customPin = GetCustomPin(mapIcon.Location.Position);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}

if (customPin.Name.Equals("Xamarin"))
{
if (mapOverlay == null)
{
mapOverlay = new XamarinMapOverlay(customPin);
}

var snPosition = new BasicGeoposition { Latitude = customPin.Position.Latitude, Longitude =


customPin.Position.Longitude };
var snPoint = new Geopoint(snPosition);

nativeMap.Children.Add(mapOverlay);
MapControl.SetLocation(mapOverlay, snPoint);
MapControl.SetNormalizedAnchorPoint(mapOverlay, new Windows.Foundation.Point(0.5, 1.0));
xamarinOverlayShown = true;
}
}
else
{
nativeMap.Children.Remove(mapOverlay);
xamarinOverlayShown = false;
}
}
}

This method creates a UserControl instance that displays information about the pin. This is accomplished as
follows:
The MapIcon instance is retrieved.
The GetCustomPin method is called to return the custom pin data that will be displayed.
A XamarinMapOverlay instance is created to display the custom pin data. This class is a user control.
The geographic location at which to display the XamarinMapOverlay instance on the MapControl is created as a
Geopoint instance.
The XamarinMapOverlay instance is added to the MapControl.Children collection. This collection contains XAML
user interface elements that will be displayed on the map.
The geographic location of the XamarinMapOverlay instance on the map is set by calling the SetLocation
method.
The relative location on the XamarinMapOverlay instance, that corresponds to the specified location, is set by
calling the SetNormalizedAnchorPoint method. This ensures that changes in the zoom level of the map result in
the XamarinMapOverlay instance always being displayed at the correct location.

Alternatively, if information about the pin is already being displayed on the map, tapping on the map removes the
XamarinMapOverlay instance from the MapControl.Children collection.

Tapping on the Information Button


When the user taps on the Information button in the XamarinMapOverlay user control, the Tapped event fires,
which in turn executes the OnInfoButtonTapped method:

private async void OnInfoButtonTapped(object sender, TappedRoutedEventArgs e)


{
await Launcher.LaunchUriAsync(new Uri(customPin.Url));
}

This method opens a web browser and navigates to the address stored in the Url property of the CustomPin
instance. Note that the address was defined when creating the CustomPin collection in the .NET Standard library
project.
For more information about customizing a MapControl instance, see Maps and Location Overview on MSDN.

Related Links
Maps Control
iOS Maps
Maps API
Customized Pin (sample)
Highlighting a Circular Area on a Map
6 minutes to read • Edit Online

Download the sample


This article explains how to add a circular overlay to a map, to highlight a circular area of the map.

Overview
An overlay is a layered graphic on a map. Overlays support drawing graphical content that scales with the map as
it is zoomed. The following screenshots show the result of adding a circular overlay to a map:

When a Map control is rendered by a Xamarin.Forms application, in iOS the MapRenderer class is instantiated,
which in turn instantiates a native MKMapView control. On the Android platform, the MapRenderer class instantiates
a native MapView control. On the Universal Windows Platform (UWP ), the MapRenderer class instantiates a native
MapControl . The rendering process can be taken advantage of to implement platform -specific map customizations
by creating a custom renderer for a Map on each platform. The process for doing this is as follows:
1. Create a Xamarin.Forms custom map.
2. Consume the custom map from Xamarin.Forms.
3. Customize the map by creating a custom renderer for the map on each platform.

NOTE
Xamarin.Forms.Maps must be initialized and configured before use. For more information, see Maps Control

For information about customizing a map using a custom renderer, see Customizing a Map Pin.
Creating the Custom Map
Create a CustomCircle class that has Position and Radius properties:
public class CustomCircle
{
public Position Position { get; set; }
public double Radius { get; set; }
}

Then, create a subclass of the Map class, that adds a property of type CustomCircle :

public class CustomMap : Map


{
public CustomCircle Circle { get; set; }
}

Consuming the Custom Map


Consume the CustomMap control by declaring an instance of it in the XAML page instance:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MapOverlay;assembly=MapOverlay"
x:Class="MapOverlay.MapPage">
<ContentPage.Content>
<local:CustomMap x:Name="customMap" MapType="Street" WidthRequest="{x:Static local:App.ScreenWidth}"
HeightRequest="{x:Static local:App.ScreenHeight}" />
</ContentPage.Content>
</ContentPage>

Alternatively, consume the CustomMap control by declaring an instance of it in the C# page instance:

public class MapPageCS : ContentPage


{
public MapPageCS ()
{
var customMap = new CustomMap {
MapType = MapType.Street,
WidthRequest = App.ScreenWidth,
HeightRequest = App.ScreenHeight
};
...
Content = customMap;
}
}

Initialize the CustomMap control as required:


public partial class MapPage : ContentPage
{
public MapPage ()
{
...
var pin = new Pin {
Type = PinType.Place,
Position = new Position (37.79752, -122.40183),
Label = "Xamarin San Francisco Office",
Address = "394 Pacific Ave, San Francisco CA"
};

var position = new Position (37.79752, -122.40183);


customMap.Circle = new CustomCircle {
Position = position,
Radius = 1000
};

customMap.Pins.Add (pin);
customMap.MoveToRegion (MapSpan.FromCenterAndRadius (position, Distance.FromMiles (1.0)));
}
}

This initialization adds Pin and CustomCircle instances to the custom map, and positions the map's view with the
MoveToRegion method, which changes the position and zoom level of the map by creating a MapSpan from a
Position and a Distance .

Customizing the Map


A custom renderer must now be added to each application project to add the circular overlay to the map.
Creating the Custom Renderer on iOS
Create a subclass of the MapRenderer class and override its OnElementChanged method to add the circular overlay:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.iOS
{
public class CustomMapRenderer : MapRenderer
{
MKCircleRenderer circleRenderer;

protected override void OnElementChanged(ElementChangedEventArgs<View> e)


{
base.OnElementChanged(e);

if (e.OldElement != null) {
var nativeMap = Control as MKMapView;
if (nativeMap != null) {
nativeMap.RemoveOverlays(nativeMap.Overlays);
nativeMap.OverlayRenderer = null;
circleRenderer = null;
}
}

if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
var circle = formsMap.Circle;

nativeMap.OverlayRenderer = GetOverlayRenderer;

var circleOverlay = MKCircle.Circle(new


CoreLocation.CLLocationCoordinate2D(circle.Position.Latitude, circle.Position.Longitude), circle.Radius);
nativeMap.AddOverlay(circleOverlay);
}
}
...
}
}

This method performs the following configuration, provided that the custom renderer is attached to a new
Xamarin.Forms element:
The MKMapView.OverlayRenderer property is set to a corresponding delegate.
The circle is created by setting a static MKCircle object that specifies the center of the circle, and the radius of
the circle in meters.
The circle is added to the map by calling the MKMapView.AddOverlay method.

Then, implement the GetOverlayRenderer method to customize the rendering of the overlay:
public class CustomMapRenderer : MapRenderer
{
MKCircleRenderer circleRenderer;
...

MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlayWrapper)


{
if (circleRenderer == null && !Equals(overlayWrapper, null)) {
var overlay = Runtime.GetNSObject(overlayWrapper.Handle) as IMKOverlay;
circleRenderer = new MKCircleRenderer(overlay as MKCircle) {
FillColor = UIColor.Red,
Alpha = 0.4f
};
}
return circleRenderer;
}
}

Creating the Custom Renderer on Android


Create a subclass of the MapRenderer class and override its OnElementChanged and OnMapReady methods to add the
circular overlay:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.Droid
{
public class CustomMapRenderer : MapRenderer
{
CustomCircle circle;

public CustomMapRenderer(Context context) : base(context)


{
}

protected override void


OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.Maps.Map> e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
circle = formsMap.Circle;
}
}

protected override void OnMapReady(Android.Gms.Maps.GoogleMap map)


{
base.OnMapReady(map);

var circleOptions = new CircleOptions();


circleOptions.InvokeCenter(new LatLng(circle.Position.Latitude, circle.Position.Longitude));
circleOptions.InvokeRadius(circle.Radius);
circleOptions.InvokeFillColor(0X66FF0000);
circleOptions.InvokeStrokeColor(0X66FF0000);
circleOptions.InvokeStrokeWidth(0);

NativeMap.AddCircle(circleOptions);
}
}
}

The OnElementChanged method retrieves the custom circle data, provided that the custom renderer is attached to a
new Xamarin.Forms element. Once the GoogleMap instance is available, the OnMapReady method will be invoked,
where the circle is created by instantiating a CircleOptions object that specifies the center of the circle, and the
radius of the circle in meters. The circle is then added to the map by calling the NativeMap.AddCircle method.
Creating the Custom Renderer on the Universal Windows Platform
Create a subclass of the MapRenderer class and override its OnElementChanged method to add the circular overlay:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.UWP
{
public class CustomMapRenderer : MapRenderer
{
const int EarthRadiusInMeteres = 6371000;

protected override void OnElementChanged(ElementChangedEventArgs<Map> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MapControl;
var circle = formsMap.Circle;

var coordinates = new List<BasicGeoposition>();


var positions = GenerateCircleCoordinates(circle.Position, circle.Radius);
foreach (var position in positions)
{
coordinates.Add(new BasicGeoposition { Latitude = position.Latitude, Longitude =
position.Longitude });
}

var polygon = new MapPolygon();


polygon.FillColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polygon.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polygon.StrokeThickness = 5;
polygon.Path = new Geopath(coordinates);
nativeMap.MapElements.Add(polygon);
}
}
// GenerateCircleCoordinates helper method (below)
}
}

This method performs the following operations, provided that the custom renderer is attached to a new
Xamarin.Forms element:
The circle position and radius are retrieved from the CustomMap.Circle property and passed to the
GenerateCircleCoordinates method, which generates latitude and longitude coordinates for the circle perimeter.
The code for this helper method is shown below.
The circle perimeter coordinates are converted into a List of BasicGeoposition coordinates.
The circle is created by instantiating a MapPolygon object. The MapPolygon class is used to display a multi-point
shape on the map by setting its Path property to a Geopath object that contains the shape coordinates.
The polygon is rendered on the map by adding it to the MapControl.MapElements collection.
List<Position> GenerateCircleCoordinates(Position position, double radius)
{
double latitude = position.Latitude.ToRadians();
double longitude = position.Longitude.ToRadians();
double distance = radius / EarthRadiusInMeteres;
var positions = new List<Position>();

for (int angle = 0; angle <=360; angle++)


{
double angleInRadians = ((double)angle).ToRadians();
double latitudeInRadians = Math.Asin(Math.Sin(latitude) * Math.Cos(distance) + Math.Cos(latitude) *
Math.Sin(distance) * Math.Cos(angleInRadians));
double longitudeInRadians = longitude + Math.Atan2(Math.Sin(angleInRadians) * Math.Sin(distance) *
Math.Cos(latitude), Math.Cos(distance) - Math.Sin(latitude) * Math.Sin(latitudeInRadians));

var pos = new Position(latitudeInRadians.ToDegrees(), longitudeInRadians.ToDegrees());


positions.Add(pos);
}

return positions;
}

Summary
This article explained how to add a circular overlay to a map, to highlight a circular area of the map.

Related Links
Circular Map Ovlerlay (sample)
Customizing a Map Pin
Xamarin.Forms.Maps
Customizing a ListView
16 minutes to read • Edit Online

Download the sample


A Xamarin.Forms ListView is a view that displays a collection of data as a vertical list. This article demonstrates
how to create a custom renderer that encapsulates platform -specific list controls and native cell layouts, allowing
more control over native list control performance.
Every Xamarin.Forms view has an accompanying renderer for each platform that creates an instance of a native
control. When a ListView is rendered by a Xamarin.Forms application, in iOS the ListViewRenderer class is
instantiated, which in turn instantiates a native UITableView control. On the Android platform, the
ListViewRenderer class instantiates a native ListView control. On the Universal Windows Platform ( UWP ), the
ListViewRenderer class instantiates a native ListView control. For more information about the renderer and
native control classes that Xamarin.Forms controls map to, see Renderer Base Classes and Native Controls.
The following diagram illustrates the relationship between the ListView control and the corresponding native
controls that implement it:

The rendering process can be taken advantage of to implement platform-specific customizations by creating a
custom renderer for a ListView on each platform. The process for doing this is as follows:
1. Create a Xamarin.Forms custom control.
2. Consume the custom control from Xamarin.Forms.
3. Create the custom renderer for the control on each platform.
Each item will now be discussed in turn, to implement a NativeListView renderer that takes advantage of
platform-specific list controls and native cell layouts. This scenario is useful when porting an existing native app
that contains list and cell code that can be re-used. In addition, it allows detailed customization of list control
features that can affect performance, such as data virtualization.

Creating the Custom ListView Control


A custom ListView control can be created by subclassing the ListView class, as shown in the following code
example:
public class NativeListView : ListView
{
public static readonly BindableProperty ItemsProperty =
BindableProperty.Create ("Items", typeof(IEnumerable<DataSource>), typeof(NativeListView), new
List<DataSource> ());

public IEnumerable<DataSource> Items {


get { return (IEnumerable<DataSource>)GetValue (ItemsProperty); }
set { SetValue (ItemsProperty, value); }
}

public event EventHandler<SelectedItemChangedEventArgs> ItemSelected;

public void NotifyItemSelected (object item)


{
if (ItemSelected != null) {
ItemSelected (this, new SelectedItemChangedEventArgs (item));
}
}
}

The NativeListView is created in the .NET Standard library project and defines the API for the custom control.
This control exposes an Items property that is used for populating the ListView with data, and which can be data
bound to for display purposes. It also exposes an ItemSelected event that will be fired whenever an item is
selected in a platform-specific native list control. For more information about data binding, see Data Binding
Basics.

Consuming the Custom Control


The NativeListView custom control can be referenced in Xaml in the .NET Standard library project by declaring a
namespace for its location and using the namespace prefix on the control. The following code example shows how
the NativeListView custom control can be consumed by a XAML page:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="{x:Static local:App.Description}" HorizontalTextAlignment="Center" />
<local:NativeListView Grid.Row="1" x:Name="nativeListView" ItemSelected="OnItemSelected"
VerticalOptions="FillAndExpand" />
</Grid>
</ContentPage.Content>
</ContentPage>

The local namespace prefix can be named anything. However, the clr-namespace and assembly values must
match the details of the custom control. Once the namespace is declared, the prefix is used to reference the custom
control.
The following code example shows how the NativeListView custom control can be consumed by a C# page:
public class MainPageCS : ContentPage
{
NativeListView nativeListView;

public MainPageCS()
{
nativeListView = new NativeListView
{
Items = DataSource.GetList(),
VerticalOptions = LayoutOptions.FillAndExpand
};

switch (Device.RuntimePlatform)
{
case Device.iOS:
Padding = new Thickness(0, 20, 0, 0);
break;
case Device.Android:
case Device.UWP:
Padding = new Thickness(0);
break;
}

Content = new Grid


{
RowDefinitions = {
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = new GridLength (1, GridUnitType.Star) }
},
Children = {
new Label { Text = App.Description, HorizontalTextAlignment = TextAlignment.Center },
nativeListView
}
};
nativeListView.ItemSelected += OnItemSelected;
}
...
}

The NativeListView custom control uses platform-specific custom renderers to display a list of data, which is
populated through the Items property. Each row in the list contains three items of data – a name, a category, and
an image filename. The layout of each row in the list is defined by the platform-specific custom renderer.

NOTE
Because the NativeListView custom control will be rendered using platform-specific list controls that include scrolling
ability, the custom control should not be hosted in scrollable layout controls such as the ScrollView .

A custom renderer can now be added to each application project to create platform-specific list controls and native
cell layouts.

Creating the Custom Renderer on each Platform


The process for creating the custom renderer class is as follows:
1. Create a subclass of the ListViewRenderer class that renders the custom control.
2. Override the OnElementChanged method that renders the custom control and write logic to customize it. This
method is called when the corresponding Xamarin.Forms ListView is created.
3. Add an ExportRenderer attribute to the custom renderer class to specify that it will be used to render the
Xamarin.Forms custom control. This attribute is used to register the custom renderer with Xamarin.Forms.
NOTE
It is optional to provide a custom renderer in each platform project. If a custom renderer isn't registered, then the default
renderer for the cell's base class will be used.

The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationships between them:

The NativeListView custom control is rendered by platform-specific renderer classes, which all derive from the
ListViewRenderer class for each platform. This results in each NativeListView custom control being rendered with
platform-specific list controls and native cell layouts, as shown in the following screenshots:

The ListViewRenderer class exposes the OnElementChanged method, which is called when the Xamarin.Forms
custom control is created to render the corresponding native control. This method takes an
ElementChangedEventArgs parameter, that contains OldElement and NewElement properties. These properties
represent the Xamarin.Forms element that the renderer was attached to, and the Xamarin.Forms element that the
renderer is attached to, respectively. In the sample application, the OldElement property will be null and the
NewElement property will contain a reference to the NativeListView instance.

An overridden version of the OnElementChanged method, in each platform-specific renderer class, is the place to
perform the native control customization. A typed reference to the native control being used on the platform can
be accessed through the Control property. In addition, a reference to the Xamarin.Forms control that's being
rendered can be obtained through the Element property.
Care must be taken when subscribing to event handlers in the OnElementChanged method, as demonstrated in the
following code example:
protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.ListView> e)
{
base.OnElementChanged (e);

if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}

if (e.NewElement != null) {
// Configure the native control and subscribe to event handlers
}
}

The native control should only be configured and event handlers subscribed to when the custom renderer is
attached to a new Xamarin.Forms element. Similarly, any event handlers that were subscribed to should be
unsubscribed from only when the element the renderer is attached to changes. Adopting this approach will help to
create a custom renderer that doesn't suffer from memory leaks.
An overridden version of the OnElementPropertyChanged method, in each platform-specific renderer class, is the
place to respond to bindable property changes on the Xamarin.Forms custom control. A check for the property
that's changed should always be made, as this override can be called many times.
Each custom renderer class is decorated with an ExportRenderer attribute that registers the renderer with
Xamarin.Forms. The attribute takes two parameters – the type name of the Xamarin.Forms custom control being
rendered, and the type name of the custom renderer. The assembly prefix to the attribute specifies that the
attribute applies to the entire assembly.
The following sections discuss the implementation of each platform-specific custom renderer class.
Creating the Custom Renderer on iOS
The following code example shows the custom renderer for the iOS platform:

[assembly: ExportRenderer (typeof(NativeListView), typeof(NativeiOSListViewRenderer))]


namespace CustomRenderer.iOS
{
public class NativeiOSListViewRenderer : ListViewRenderer
{
protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.ListView> e)
{
base.OnElementChanged (e);

if (e.OldElement != null) {
// Unsubscribe
}

if (e.NewElement != null) {
Control.Source = new NativeiOSListViewSource (e.NewElement as NativeListView);
}
}
}
}

The UITableView control is configured by creating an instance of the NativeiOSListViewSource class, provided that
the custom renderer is attached to a new Xamarin.Forms element. This class provides data to the UITableView
control by overriding the RowsInSection and GetCell methods from the UITableViewSource class, and by
exposing an Items property that contains the list of data to be displayed. The class also provides a RowSelected
method override that invokes the ItemSelected event provided by the NativeListView custom control. For more
information about the method overrides, see Subclassing UITableViewSource. The GetCell method returns a
UITableCellView that's populated with data for each row in the list, and is shown in the following code example:
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
// request a recycled cell to save memory
NativeiOSListViewCell cell = tableView.DequeueReusableCell (cellIdentifier) as NativeiOSListViewCell;

// if there are no cells to reuse, create a new one


if (cell == null) {
cell = new NativeiOSListViewCell (cellIdentifier);
}

if (String.IsNullOrWhiteSpace (tableItems [indexPath.Row].ImageFilename)) {


cell.UpdateCell (tableItems [indexPath.Row].Name
, tableItems [indexPath.Row].Category
, null);
} else {
cell.UpdateCell (tableItems [indexPath.Row].Name
, tableItems [indexPath.Row].Category
, UIImage.FromFile ("Images/" + tableItems [indexPath.Row].ImageFilename + ".jpg"));
}

return cell;
}

This method creates a NativeiOSListViewCell instance for each row of data that will be displayed on the screen.
The NativeiOSCell instance defines the layout of each cell and the cell's data. When a cell disappears from the
screen due to scrolling, the cell will be made available for reuse. This avoids wasting memory by ensuring that
there are only NativeiOSCell instances for the data being displayed on the screen, rather than all of the data in the
list. For more information about cell reuse, see Cell Reuse. The GetCell method also reads the ImageFilename
property of each row of data, provided that it exists, and reads the image and stores it as a UIImage instance,
before updating the NativeiOSListViewCell instance with the data (name, category, and image) for the row.
The NativeiOSListViewCell class defines the layout for each cell, and is shown in the following code example:
public class NativeiOSListViewCell : UITableViewCell
{
UILabel headingLabel, subheadingLabel;
UIImageView imageView;

public NativeiOSListViewCell (NSString cellId) : base (UITableViewCellStyle.Default, cellId)


{
SelectionStyle = UITableViewCellSelectionStyle.Gray;

ContentView.BackgroundColor = UIColor.FromRGB (218, 255, 127);

imageView = new UIImageView ();

headingLabel = new UILabel () {


Font = UIFont.FromName ("Cochin-BoldItalic", 22f),
TextColor = UIColor.FromRGB (127, 51, 0),
BackgroundColor = UIColor.Clear
};

subheadingLabel = new UILabel () {


Font = UIFont.FromName ("AmericanTypewriter", 12f),
TextColor = UIColor.FromRGB (38, 127, 0),
TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.Clear
};

ContentView.Add (headingLabel);
ContentView.Add (subheadingLabel);
ContentView.Add (imageView);
}

public void UpdateCell (string caption, string subtitle, UIImage image)


{
headingLabel.Text = caption;
subheadingLabel.Text = subtitle;
imageView.Image = image;
}

public override void LayoutSubviews ()


{
base.LayoutSubviews ();

headingLabel.Frame = new CoreGraphics.CGRect (5, 4, ContentView.Bounds.Width - 63, 25);


subheadingLabel.Frame = new CoreGraphics.CGRect (100, 18, 100, 20);
imageView.Frame = new CoreGraphics.CGRect (ContentView.Bounds.Width - 63, 5, 33, 33);
}
}

This class defines the controls used to render the cell's contents, and their layout. The NativeiOSListViewCell
constructor creates instances of UILabel and UIImageView controls, and initializes their appearance. These
controls are used to display each row's data, with the UpdateCell method being used to set this data on the
UILabel and UIImageView instances. The location of these instances is set by the overridden LayoutSubviews
method, by specifying their coordinates within the cell.
Responding to a Property Change on the Custom Control
If the NativeListView.Items property changes, due to items being added to or removed from the list, the custom
renderer needs to respond by displaying the changes. This can be accomplished by overriding the
OnElementPropertyChanged method, which is shown in the following code example:
protected override void OnElementPropertyChanged (object sender,
System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged (sender, e);

if (e.PropertyName == NativeListView.ItemsProperty.PropertyName) {
Control.Source = new NativeiOSListViewSource (Element as NativeListView);
}
}

The method creates a new instance of the NativeiOSListViewSource class that provides data to the UITableView
control, provided that the bindable NativeListView.Items property has changed.
Creating the Custom Renderer on Android
The following code example shows the custom renderer for the Android platform:

[assembly: ExportRenderer(typeof(NativeListView), typeof(NativeAndroidListViewRenderer))]


namespace CustomRenderer.Droid
{
public class NativeAndroidListViewRenderer : ListViewRenderer
{
Context _context;

public NativeAndroidListViewRenderer(Context context) : base(context)


{
_context = context;
}

protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// unsubscribe
Control.ItemClick -= OnItemClick;
}

if (e.NewElement != null)
{
// subscribe
Control.Adapter = new NativeAndroidListViewAdapter(_context as Android.App.Activity,
e.NewElement as NativeListView);
Control.ItemClick += OnItemClick;
}
}
...

void OnItemClick(object sender, Android.Widget.AdapterView.ItemClickEventArgs e)


{
((NativeListView)Element).NotifyItemSelected(((NativeListView)Element).Items.ToList()[e.Position -
1]);
}
}
}

The native ListView control is configured provided that the custom renderer is attached to a new Xamarin.Forms
element. This configuration involves creating an instance of the NativeAndroidListViewAdapter class that provides
data to the native ListView control, and registering an event handler to process the ItemClick event. In turn, this
handler will invoke the ItemSelected event provided by the NativeListView custom control. The ItemClick event
is unsubscribed from if the Xamarin.Forms element the renderer is attached to changes.
The NativeAndroidListViewAdapter derives from the BaseAdapter class and exposes an Items property that
contains the list of data to be displayed, as well as overriding the Count , GetView , GetItemId , and this[int]
methods. For more information about these method overrides, see Implementing a ListAdapter. The GetView
method returns a view for each row, populated with data, and is shown in the following code example:

public override View GetView (int position, View convertView, ViewGroup parent)
{
var item = tableItems [position];

var view = convertView;


if (view == null) {
// no view to re-use, create new
view = context.LayoutInflater.Inflate (Resource.Layout.NativeAndroidListViewCell, null);
}
view.FindViewById<TextView> (Resource.Id.Text1).Text = item.Name;
view.FindViewById<TextView> (Resource.Id.Text2).Text = item.Category;

// grab the old image and dispose of it


if (view.FindViewById<ImageView> (Resource.Id.Image).Drawable != null) {
using (var image = view.FindViewById<ImageView> (Resource.Id.Image).Drawable as BitmapDrawable) {
if (image != null) {
if (image.Bitmap != null) {
//image.Bitmap.Recycle ();
image.Bitmap.Dispose ();
}
}
}
}

// If a new image is required, display it


if (!String.IsNullOrWhiteSpace (item.ImageFilename)) {
context.Resources.GetBitmapAsync (item.ImageFilename).ContinueWith ((t) => {
var bitmap = t.Result;
if (bitmap != null) {
view.FindViewById<ImageView> (Resource.Id.Image).SetImageBitmap (bitmap);
bitmap.Dispose ();
}
}, TaskScheduler.FromCurrentSynchronizationContext ());
} else {
// clear the image
view.FindViewById<ImageView> (Resource.Id.Image).SetImageBitmap (null);
}

return view;
}

The GetView method is called to return the cell to be rendered, as a View , for each row of data in the list. It
creates a View instance for each row of data that will be displayed on the screen, with the appearance of the View
instance being defined in a layout file. When a cell disappears from the screen due to scrolling, the cell will be
made available for reuse. This avoids wasting memory by ensuring that there are only View instances for the data
being displayed on the screen, rather than all of the data in the list. For more information about view reuse, see
Row View Re-use.
The GetView method also populates the View instance with data, including reading the image data from the
filename specified in the ImageFilename property.
The layout of each cell dispayed by the native ListView is defined in the NativeAndroidListViewCell.axml layout
file, which is inflated by the LayoutInflater.Inflate method. The following code example shows the layout
definition:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/CustomSelector">
<LinearLayout
android:id="@+id/Text"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dip">
<TextView
android:id="@+id/Text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF7F3300"
android:textSize="20dip"
android:textStyle="italic" />
<TextView
android:id="@+id/Text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dip"
android:textColor="#FF267F00"
android:paddingLeft="100dip" />
</LinearLayout>
<ImageView
android:id="@+id/Image"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="5dp"
android:src="@drawable/icon"
android:layout_alignParentRight="true" />
</RelativeLayout>

This layout specifies that two TextView controls and an ImageView control are used to display the cell's content.
The two TextView controls are vertically oriented within a LinearLayout control, with all the controls being
contained within a RelativeLayout .
Responding to a Property Change on the Custom Control
If the NativeListView.Items property changes, due to items being added to or removed from the list, the custom
renderer needs to respond by displaying the changes. This can be accomplished by overriding the
OnElementPropertyChanged method, which is shown in the following code example:

protected override void OnElementPropertyChanged (object sender,


System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged (sender, e);

if (e.PropertyName == NativeListView.ItemsProperty.PropertyName) {
Control.Adapter = new NativeAndroidListViewAdapter (_context as Android.App.Activity, Element as
NativeListView);
}
}

The method creates a new instance of the NativeAndroidListViewAdapter class that provides data to the native
ListView control, provided that the bindable NativeListView.Items property has changed.

Creating the Custom Renderer on UWP


The following code example shows the custom renderer for UWP:
[assembly: ExportRenderer(typeof(NativeListView), typeof(NativeUWPListViewRenderer))]
namespace CustomRenderer.UWP
{
public class NativeUWPListViewRenderer : ListViewRenderer
{
ListView listView;

protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)


{
base.OnElementChanged(e);

listView = Control as ListView;

if (e.OldElement != null)
{
// Unsubscribe
listView.SelectionChanged -= OnSelectedItemChanged;
}

if (e.NewElement != null)
{
listView.SelectionMode = ListViewSelectionMode.Single;
listView.IsItemClickEnabled = false;
listView.ItemsSource = ((NativeListView)e.NewElement).Items;
listView.ItemTemplate = App.Current.Resources["ListViewItemTemplate"] as
Windows.UI.Xaml.DataTemplate;
// Subscribe
listView.SelectionChanged += OnSelectedItemChanged;
}
}

void OnSelectedItemChanged(object sender, SelectionChangedEventArgs e)


{
((NativeListView)Element).NotifyItemSelected(listView.SelectedItem);
}
}
}

The native ListView control is configured provided that the custom renderer is attached to a new Xamarin.Forms
element. This configuration involves setting how the native ListView control will respond to items being selected,
populating the data displayed by the control, defining the appearance and contents of each cell, and registering an
event handler to process the SelectionChanged event. In turn, this handler will invoke the ItemSelected event
provided by the NativeListView custom control. The SelectionChanged event is unsubscribed from if the
Xamarin.Forms element the renderer is attached to changes.
The appearance and contents of each native ListView cell are defined by a DataTemplate named
ListViewItemTemplate . This DataTemplate is stored in the application-level resource dictionary, and is shown in the
following code example:
<DataTemplate x:Key="ListViewItemTemplate">
<Grid Background="#DAFF7F">
<Grid.Resources>
<local:ConcatImageExtensionConverter x:Name="ConcatImageExtensionConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.40*" />
<ColumnDefinition Width="0.40*"/>
<ColumnDefinition Width="0.20*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="2" Foreground="#7F3300" FontStyle="Italic" FontSize="22"
VerticalAlignment="Top" Text="{Binding Name}" />
<TextBlock Grid.RowSpan="2" Grid.Column="1" Foreground="#267F00" FontWeight="Bold" FontSize="12"
VerticalAlignment="Bottom" Text="{Binding Category}" />
<Image Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center" Source="
{Binding ImageFilename, Converter={StaticResource ConcatImageExtensionConverter}}" Width="50" Height="50" />
<Line Grid.Row="1" Grid.ColumnSpan="3" X1="0" X2="1" Margin="30,20,0,0" StrokeThickness="1"
Stroke="LightGray" Stretch="Fill" VerticalAlignment="Bottom" />
</Grid>
</DataTemplate>

The DataTemplate specifies the controls used to display the contents of the cell, and their layout and appearance.
Two TextBlock controls and an Image control are used to display the cell's content through data binding. In
addition, an instance of the ConcatImageExtensionConverter is used to concatenate the .jpg file extension to each
image file name. This ensures that the Image control can load and render the image when it's Source property is
set.
Responding to a Property Change on the Custom Control
If the NativeListView.Items property changes, due to items being added to or removed from the list, the custom
renderer needs to respond by displaying the changes. This can be accomplished by overriding the
OnElementPropertyChanged method, which is shown in the following code example:

protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs


e)
{
base.OnElementPropertyChanged(sender, e);

if (e.PropertyName == NativeListView.ItemsProperty.PropertyName)
{
listView.ItemsSource = ((NativeListView)Element).Items;
}
}

The method re-populates the native ListView control with the changed data, provided that the bindable
NativeListView.Items property has changed.

Summary
This article has demonstrated how to create a custom renderer that encapsulates platform-specific list controls
and native cell layouts, allowing more control over native list control performance.

Related Links
CustomRendererListView (sample)
Customizing a ViewCell
14 minutes to read • Edit Online

Download the sample


A Xamarin.Forms ViewCell is a cell that can be added to a ListView or TableView, which contains a developer-
defined view. This article demonstrates how to create a custom renderer for a ViewCell that's hosted inside a
Xamarin.Forms ListView control. This stops the Xamarin.Forms layout calculations from being repeatedly called
during ListView scrolling.
Every Xamarin.Forms cell has an accompanying renderer for each platform that creates an instance of a native
control. When a ViewCell is rendered by a Xamarin.Forms application, in iOS the ViewCellRenderer class is
instantiated, which in turn instantiates a native UITableViewCell control. On the Android platform, the
ViewCellRenderer class instantiates a native View control. On the Universal Windows Platform ( UWP ), the
ViewCellRenderer class instantiates a native DataTemplate . For more information about the renderer and native
control classes that Xamarin.Forms controls map to, see Renderer Base Classes and Native Controls.
The following diagram illustrates the relationship between the ViewCell and the corresponding native controls
that implement it:

The rendering process can be taken advantage of to implement platform-specific customizations by creating a
custom renderer for a ViewCell on each platform. The process for doing this is as follows:
1. Create a Xamarin.Forms custom cell.
2. Consume the custom cell from Xamarin.Forms.
3. Create the custom renderer for the cell on each platform.
Each item will now be discussed in turn, to implement a NativeCell renderer that takes advantage of a platform-
specific layout for each cell hosted inside a Xamarin.Forms ListView control. This stops the Xamarin.Forms layout
calculations from being repeatedly called during ListView scrolling.

Creating the Custom Cell


A custom cell control can be created by subclassing the ViewCell class, as shown in the following code example:
public class NativeCell : ViewCell
{
public static readonly BindableProperty NameProperty =
BindableProperty.Create ("Name", typeof(string), typeof(NativeCell), "");

public string Name {


get { return (string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}

public static readonly BindableProperty CategoryProperty =


BindableProperty.Create ("Category", typeof(string), typeof(NativeCell), "");

public string Category {


get { return (string)GetValue (CategoryProperty); }
set { SetValue (CategoryProperty, value); }
}

public static readonly BindableProperty ImageFilenameProperty =


BindableProperty.Create ("ImageFilename", typeof(string), typeof(NativeCell), "");

public string ImageFilename {


get { return (string)GetValue (ImageFilenameProperty); }
set { SetValue (ImageFilenameProperty, value); }
}
}

The NativeCell class is created in the .NET Standard library project and defines the API for the custom cell. The
custom cell exposes Name , Category , and ImageFilename properties that can be displayed through data binding.
For more information about data binding, see Data Binding Basics.

Consuming the Custom Cell


The NativeCell custom cell can be referenced in Xaml in the .NET Standard library project by declaring a
namespace for its location and using the namespace prefix on the custom cell element. The following code
example shows how the NativeCell custom cell can be consumed by a XAML page:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<ContentPage.Content>
<StackLayout>
<Label Text="Xamarin.Forms native cell" HorizontalTextAlignment="Center" />
<ListView x:Name="listView" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<local:NativeCell Name="{Binding Name}" Category="{Binding Category}"
ImageFilename="{Binding ImageFilename}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>

The local namespace prefix can be named anything. However, the clr-namespace and assembly values must
match the details of the custom control. Once the namespace is declared, the prefix is used to reference the
custom cell.
The following code example shows how the NativeCell custom cell can be consumed by a C# page:
public class NativeCellPageCS : ContentPage
{
ListView listView;

public NativeCellPageCS()
{
listView = new ListView(ListViewCachingStrategy.RecycleElement)
{
ItemsSource = DataSource.GetList(),
ItemTemplate = new DataTemplate(() =>
{
var nativeCell = new NativeCell();
nativeCell.SetBinding(NativeCell.NameProperty, "Name");
nativeCell.SetBinding(NativeCell.CategoryProperty, "Category");
nativeCell.SetBinding(NativeCell.ImageFilenameProperty, "ImageFilename");

return nativeCell;
})
};

switch (Device.RuntimePlatform)
{
case Device.iOS:
Padding = new Thickness(0, 20, 0, 0);
break;
case Device.Android:
case Device.UWP:
Padding = new Thickness(0);
break;
}

Content = new StackLayout


{
Children = {
new Label { Text = "Xamarin.Forms native cell", HorizontalTextAlignment = TextAlignment.Center
},
listView
}
};
listView.ItemSelected += OnItemSelected;
}
...
}

A Xamarin.Forms ListView control is used to display a list of data, which is populated through the ItemSource
property. The RecycleElement caching strategy attempts to minimize the ListView memory footprint and
execution speed by recycling list cells. For more information, see Caching Strategy.
Each row in the list contains three items of data – a name, a category, and an image filename. The layout of each
row in the list is defined by the DataTemplate that's referenced through the ListView.ItemTemplate bindable
property. The DataTemplate defines that each row of data in the list will be a NativeCell that displays its Name ,
Category , and ImageFilename properties through data binding. For more information about the ListView control,
see ListView.
A custom renderer can now be added to each application project to customize the platform-specific layout for
each cell.

Creating the Custom Renderer on each Platform


The process for creating the custom renderer class is as follows:
1. Create a subclass of the ViewCellRenderer class that renders the custom cell.
2. Override the platform-specific method that renders the custom cell and write logic to customize it.
3. Add an ExportRenderer attribute to the custom renderer class to specify that it will be used to render the
Xamarin.Forms custom cell. This attribute is used to register the custom renderer with Xamarin.Forms.

NOTE
For most Xamarin.Forms elements, it is optional to provide a custom renderer in each platform project. If a custom renderer
isn't registered, then the default renderer for the control's base class will be used. However, custom renderers are required in
each platform project when rendering a ViewCell element.

The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationships between them:

The NativeCell custom cell is rendered by platform-specific renderer classes, which all derive from the
ViewCellRenderer class for each platform. This results in each NativeCell custom cell being rendered with
platform-specific layout, as shown in the following screenshots:

The ViewCellRenderer class exposes platform-specific methods for rendering the custom cell. This is the GetCell
method on the iOS platform, the GetCellCore method on the Android platform, and the GetTemplate method on
UWP.
Each custom renderer class is decorated with an ExportRenderer attribute that registers the renderer with
Xamarin.Forms. The attribute takes two parameters – the type name of the Xamarin.Forms cell being rendered,
and the type name of the custom renderer. The assembly prefix to the attribute specifies that the attribute applies
to the entire assembly.
The following sections discuss the implementation of each platform-specific custom renderer class.
Creating the Custom Renderer on iOS
The following code example shows the custom renderer for the iOS platform:

[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeiOSCellRenderer))]


namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
NativeiOSCell cell;

public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)


{
var nativeCell = (NativeCell)item;

cell = reusableCell as NativeiOSCell;


if (cell == null)
cell = new NativeiOSCell(item.GetType().FullName, nativeCell);
else
cell.NativeCell.PropertyChanged -= OnNativeCellPropertyChanged;

nativeCell.PropertyChanged += OnNativeCellPropertyChanged;
cell.UpdateCell(nativeCell);
return cell;
}
...
}
}

The GetCell method is called to build each cell to be displayed. Each cell is a NativeiOSCell instance, which
defines the layout of the cell and its data. The operation of the GetCell method is dependent upon the ListView
caching strategy:
When the caching strategy is RetainElement , the GetCell method will be invoked for each cell. A
ListView
NativeiOSCell instance will be created for each NativeCell instance that's initially displayed on the screen.
As the user scrolls through the ListView , NativeiOSCell instances will be re-used. For more information
about iOS cell re-use, see Cell Reuse.

NOTE
This custom renderer code will perform some cell re-use even when the ListView is set to retain cells.

The data displayed by each NativeiOSCell instance, whether newly created or re-used, will be updated with
the data from each NativeCell instance by the UpdateCell method.

NOTE
The OnNativeCellPropertyChanged method will never be invoked when the ListView caching strategy is set to
retain cells.

When the ListView caching strategy is RecycleElement , the GetCell method will be invoked for each cell
that's initially displayed on the screen. A NativeiOSCell instance will be created for each NativeCell
instance that's initially displayed on the screen. The data displayed by each NativeiOSCell instance will be
updated with the data from the NativeCell instance by the UpdateCell method. However, the GetCell
method won't be invoked as the user scrolls through the ListView . Instead, the NativeiOSCell instances
will be re-used. PropertyChanged events will be raised on the NativeCell instance when its data changes,
and the OnNativeCellPropertyChanged event handler will update the data in each re-used NativeiOSCell
instance.
The following code example shows the OnNativeCellPropertyChanged method that's invoked when a
PropertyChanged event is raised:

namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
...

void OnNativeCellPropertyChanged(object sender, PropertyChangedEventArgs e)


{
var nativeCell = (NativeCell)sender;
if (e.PropertyName == NativeCell.NameProperty.PropertyName)
{
cell.HeadingLabel.Text = nativeCell.Name;
}
else if (e.PropertyName == NativeCell.CategoryProperty.PropertyName)
{
cell.SubheadingLabel.Text = nativeCell.Category;
}
else if (e.PropertyName == NativeCell.ImageFilenameProperty.PropertyName)
{
cell.CellImageView.Image = cell.GetImage(nativeCell.ImageFilename);
}
}
}
}

This method updates the data being displayed by re-used NativeiOSCell instances. A check for the property that's
changed is made, as the method can be called multiple times.
The NativeiOSCell class defines the layout for each cell, and is shown in the following code example:
internal class NativeiOSCell : UITableViewCell, INativeElementView
{
public UILabel HeadingLabel { get; set; }
public UILabel SubheadingLabel { get; set; }
public UIImageView CellImageView { get; set; }

public NativeCell NativeCell { get; private set; }


public Element Element => NativeCell;

public NativeiOSCell(string cellId, NativeCell cell) : base(UITableViewCellStyle.Default, cellId)


{
NativeCell = cell;

SelectionStyle = UITableViewCellSelectionStyle.Gray;
ContentView.BackgroundColor = UIColor.FromRGB(255, 255, 224);
CellImageView = new UIImageView();

HeadingLabel = new UILabel()


{
Font = UIFont.FromName("Cochin-BoldItalic", 22f),
TextColor = UIColor.FromRGB(127, 51, 0),
BackgroundColor = UIColor.Clear
};

SubheadingLabel = new UILabel()


{
Font = UIFont.FromName("AmericanTypewriter", 12f),
TextColor = UIColor.FromRGB(38, 127, 0),
TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.Clear
};

ContentView.Add(HeadingLabel);
ContentView.Add(SubheadingLabel);
ContentView.Add(CellImageView);
}

public void UpdateCell(NativeCell cell)


{
HeadingLabel.Text = cell.Name;
SubheadingLabel.Text = cell.Category;
CellImageView.Image = GetImage(cell.ImageFilename);
}

public UIImage GetImage(string filename)


{
return (!string.IsNullOrWhiteSpace(filename)) ? UIImage.FromFile("Images/" + filename + ".jpg") : null;
}

public override void LayoutSubviews()


{
base.LayoutSubviews();

HeadingLabel.Frame = new CGRect(5, 4, ContentView.Bounds.Width - 63, 25);


SubheadingLabel.Frame = new CGRect(100, 18, 100, 20);
CellImageView.Frame = new CGRect(ContentView.Bounds.Width - 63, 5, 33, 33);
}
}

This class defines the controls used to render the cell's contents, and their layout. The class implements the
INativeElementView interface, which is required when the ListView uses the RecycleElement caching strategy.
This interface specifies that the class must implement the Element property, which should return the custom cell
data for recycled cells.
The NativeiOSCell constructor initializes the appearance of the HeadingLabel , SubheadingLabel , and
CellImageView properties. These properties are used to display the data stored in the NativeCell instance, with
the UpdateCell method being called to set the value of each property. In addition, when the ListView uses the
RecycleElement caching strategy, the data displayed by the HeadingLabel , SubheadingLabel , and CellImageView
properties can be updated by the OnNativeCellPropertyChanged method in the custom renderer.
Cell layout is performed by the LayoutSubviews override, which sets the coordinates of HeadingLabel ,
SubheadingLabel , and CellImageView within the cell.

Creating the Custom Renderer on Android


The following code example shows the custom renderer for the Android platform:

[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeAndroidCellRenderer))]


namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
NativeAndroidCell cell;

protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, ViewGroup


parent, Context context)
{
var nativeCell = (NativeCell)item;
Console.WriteLine("\t\t" + nativeCell.Name);

cell = convertView as NativeAndroidCell;


if (cell == null)
{
cell = new NativeAndroidCell(context, nativeCell);
}
else
{
cell.NativeCell.PropertyChanged -= OnNativeCellPropertyChanged;
}

nativeCell.PropertyChanged += OnNativeCellPropertyChanged;

cell.UpdateCell(nativeCell);
return cell;
}
...
}
}

The GetCellCore method is called to build each cell to be displayed. Each cell is a NativeAndroidCell instance,
which defines the layout of the cell and its data. The operation of the GetCellCore method is dependent upon the
ListView caching strategy:

When the ListView caching strategy is RetainElement , the GetCellCore method will be invoked for each
cell. A NativeAndroidCell will be created for each NativeCell instance that's initially displayed on the
screen. As the user scrolls through the ListView , NativeAndroidCell instances will be re-used. For more
information about Android cell re-use, see Row View Re-use.

NOTE
Note that this custom renderer code will perform some cell re-use even when the ListView is set to retain cells.

The data displayed by each NativeAndroidCell instance, whether newly created or re-used, will be updated
with the data from each NativeCell instance by the UpdateCell method.
NOTE
Note that while the OnNativeCellPropertyChanged method will be invoked when the ListView is set to retain
cells, it will not update the NativeAndroidCell property values.

When the ListView caching strategy is RecycleElement , the GetCellCore method will be invoked for each
cell that's initially displayed on the screen. A NativeAndroidCell instance will be created for each
NativeCell instance that's initially displayed on the screen. The data displayed by each NativeAndroidCell
instance will be updated with the data from the NativeCell instance by the UpdateCell method. However,
the GetCellCore method won't be invoked as the user scrolls through the ListView . Instead, the
NativeAndroidCell instances will be re-used. PropertyChanged events will be raised on the NativeCell
instance when its data changes, and the OnNativeCellPropertyChanged event handler will update the data in
each re-used NativeAndroidCell instance.

The following code example shows the OnNativeCellPropertyChanged method that's invoked when a
PropertyChanged event is raised:

namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
...

void OnNativeCellPropertyChanged(object sender, PropertyChangedEventArgs e)


{
var nativeCell = (NativeCell)sender;
if (e.PropertyName == NativeCell.NameProperty.PropertyName)
{
cell.HeadingTextView.Text = nativeCell.Name;
}
else if (e.PropertyName == NativeCell.CategoryProperty.PropertyName)
{
cell.SubheadingTextView.Text = nativeCell.Category;
}
else if (e.PropertyName == NativeCell.ImageFilenameProperty.PropertyName)
{
cell.SetImage(nativeCell.ImageFilename);
}
}
}
}

This method updates the data being displayed by re-used NativeAndroidCell instances. A check for the property
that's changed is made, as the method can be called multiple times.
The NativeAndroidCell class defines the layout for each cell, and is shown in the following code example:
internal class NativeAndroidCell : LinearLayout, INativeElementView
{
public TextView HeadingTextView { get; set; }
public TextView SubheadingTextView { get; set; }
public ImageView ImageView { get; set; }

public NativeCell NativeCell { get; private set; }


public Element Element => NativeCell;

public NativeAndroidCell(Context context, NativeCell cell) : base(context)


{
NativeCell = cell;

var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.NativeAndroidCell, null);


HeadingTextView = view.FindViewById<TextView>(Resource.Id.HeadingText);
SubheadingTextView = view.FindViewById<TextView>(Resource.Id.SubheadingText);
ImageView = view.FindViewById<ImageView>(Resource.Id.Image);

AddView(view);
}

public void UpdateCell(NativeCell cell)


{
HeadingTextView.Text = cell.Name;
SubheadingTextView.Text = cell.Category;

// Dispose of the old image


if (ImageView.Drawable != null)
{
using (var image = ImageView.Drawable as BitmapDrawable)
{
if (image != null)
{
if (image.Bitmap != null)
{
image.Bitmap.Dispose();
}
}
}
}

SetImage(cell.ImageFilename);
}

public void SetImage(string filename)


{
if (!string.IsNullOrWhiteSpace(filename))
{
// Display new image
Context.Resources.GetBitmapAsync(filename).ContinueWith((t) =>
{
var bitmap = t.Result;
if (bitmap != null)
{
ImageView.SetImageBitmap(bitmap);
bitmap.Dispose();
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
// Clear the image
ImageView.SetImageBitmap(null);
}
}
}
This class defines the controls used to render the cell's contents, and their layout. The class implements the
INativeElementView interface, which is required when the ListView uses the RecycleElement caching strategy.
This interface specifies that the class must implement the Element property, which should return the custom cell
data for recycled cells.
The NativeAndroidCell constructor inflates the NativeAndroidCell layout, and initializes the HeadingTextView ,
SubheadingTextView , and ImageView properties to the controls in the inflated layout. These properties are used to
display the data stored in the NativeCell instance, with the UpdateCell method being called to set the value of
each property. In addition, when the ListView uses the RecycleElement caching strategy, the data displayed by
the HeadingTextView , SubheadingTextView , and ImageView properties can be updated by the
OnNativeCellPropertyChanged method in the custom renderer.

The following code example shows the layout definition for the NativeAndroidCell.axml layout file:

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/CustomSelector">
<LinearLayout
android:id="@+id/Text"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dip">
<TextView
android:id="@+id/HeadingText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF7F3300"
android:textSize="20dip"
android:textStyle="italic" />
<TextView
android:id="@+id/SubheadingText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dip"
android:textColor="#FF267F00"
android:paddingLeft="100dip" />
</LinearLayout>
<ImageView
android:id="@+id/Image"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="5dp"
android:src="@drawable/icon"
android:layout_alignParentRight="true" />
</RelativeLayout>

This layout specifies that two TextView controls and an ImageView control are used to display the cell's content.
The two TextView controls are vertically oriented within a LinearLayout control, with all the controls being
contained within a RelativeLayout .
Creating the Custom Renderer on UWP
The following code example shows the custom renderer for UWP:
[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeUWPCellRenderer))]
namespace CustomRenderer.UWP
{
public class NativeUWPCellRenderer : ViewCellRenderer
{
public override Windows.UI.Xaml.DataTemplate GetTemplate(Cell cell)
{
return App.Current.Resources["ListViewItemTemplate"] as Windows.UI.Xaml.DataTemplate;
}
}
}

The GetTemplate method is called to return the cell to be rendered for each row of data in the list. It creates a
DataTemplate for each NativeCell instance that will be displayed on the screen, with the DataTemplate defining
the appearance and contents of the cell.
The DataTemplate is stored in the application-level resource dictionary, and is shown in the following code
example:

<DataTemplate x:Key="ListViewItemTemplate">
<Grid Background="LightYellow">
<Grid.Resources>
<local:ConcatImageExtensionConverter x:Name="ConcatImageExtensionConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.40*" />
<ColumnDefinition Width="0.40*"/>
<ColumnDefinition Width="0.20*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="2" Foreground="#7F3300" FontStyle="Italic" FontSize="22"
VerticalAlignment="Top" Text="{Binding Name}" />
<TextBlock Grid.RowSpan="2" Grid.Column="1" Foreground="#267F00" FontWeight="Bold" FontSize="12"
VerticalAlignment="Bottom" Text="{Binding Category}" />
<Image Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center" Source="
{Binding ImageFilename, Converter={StaticResource ConcatImageExtensionConverter}}" Width="50" Height="50" />
<Line Grid.Row="1" Grid.ColumnSpan="3" X1="0" X2="1" Margin="30,20,0,0" StrokeThickness="1"
Stroke="LightGray" Stretch="Fill" VerticalAlignment="Bottom" />
</Grid>
</DataTemplate>

The DataTemplate specifies the controls used to display the contents of the cell, and their layout and appearance.
Two TextBlock controls and an Image control are used to display the cell's content through data binding. In
addition, an instance of the ConcatImageExtensionConverter is used to concatenate the .jpg file extension to each
image file name. This ensures that the Image control can load and render the image when it's Source property is
set.

Summary
This article has demonstrated how to create a custom renderer for a ViewCell that's hosted inside a
Xamarin.Forms ListView control. This stops the Xamarin.Forms layout calculations from being repeatedly called
during ListView scrolling.

Related Links
ListView Performance
CustomRendererViewCell (sample)
Customizing a WebView
14 minutes to read • Edit Online

Download the sample


A Xamarin.Forms WebView is a view that displays web and HTML content in your app. This article explains how to
create a custom renderer that extends the WebView to allow C# code to be invoked from JavaScript.
Every Xamarin.Forms view has an accompanying renderer for each platform that creates an instance of a native
control. When a WebView is rendered by a Xamarin.Forms application on iOS, the WkWebViewRenderer class is
instantiated, which in turn instantiates a native WkWebView control. On the Android platform, the WebViewRenderer
class instantiates a native WebView control. On the Universal Windows Platform (UWP ), the WebViewRenderer class
instantiates a native WebView control. For more information about the renderer and native control classes that
Xamarin.Forms controls map to, see Renderer Base Classes and Native Controls.
The following diagram illustrates the relationship between the View and the corresponding native controls that
implement it:

The rendering process can be used to implement platform customizations by creating a custom renderer for a
WebView on each platform. The process for doing this is as follows:

1. Create the HybridWebView custom control.


2. Consume the HybridWebView from Xamarin.Forms.
3. Create the custom renderer for the HybridWebView on each platform.
Each item will now be discussed in turn to implement a HybridWebView renderer that enhances the Xamarin.Forms
WebView to allow C# code to be invoked from JavaScript. The HybridWebView instance will be used to display an
HTML page that asks the user to enter their name. Then, when the user clicks an HTML button, a JavaScript
function will invoke a C# Action that displays a pop-up containing the users name.
For more information about the process for invoking C# from JavaScript, see Invoke C# from JavaScript. For more
information about the HTML page, see Create the Web Page.

NOTE
A WebView can invoke a JavaScript function from C#, and return any result to the calling C# code. For more information, see
Invoking JavaScript.
Create the HybridWebView
The HybridWebView custom control can be created by subclassing the WebView class:

public class HybridWebView : WebView


{
Action<string> action;

public static readonly BindableProperty UriProperty = BindableProperty.Create(


propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));

public string Uri


{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}

public void RegisterAction(Action<string> callback)


{
action = callback;
}

public void Cleanup()


{
action = null;
}

public void InvokeAction(string data)


{
if (action == null || data == null)
{
return;
}
action.Invoke(data);
}
}

The HybridWebView custom control is created in the .NET Standard library project and defines the following API for
the control:
A Uri property that specifies the address of the web page to be loaded.
A RegisterAction method that registers an Action with the control. The registered action will be invoked from
JavaScript contained in the HTML file referenced through the Uri property.
A CleanUp method that removes the reference to the registered Action .
An InvokeAction method that invokes the registered Action . This method will be called from a custom
renderer in each platform project.

Consume the HybridWebView


The HybridWebView custom control can be referenced in XAML in the .NET Standard library project by declaring a
namespace for its location and using the namespace prefix on the custom control. The following code example
shows how the HybridWebView custom control can be consumed by a XAML page:
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
x:Class="CustomRenderer.HybridWebViewPage"
Padding="0,40,0,0">
<local:HybridWebView x:Name="hybridWebView"
Uri="index.html" />
</ContentPage>

The local namespace prefix can be named anything. However, the clr-namespace and assembly values must
match the details of the custom control. Once the namespace is declared, the prefix is used to reference the custom
control.
The following code example shows how the HybridWebView custom control can be consumed by a C# page:

public HybridWebViewPageCS()
{
var hybridWebView = new HybridWebView
{
Uri = "index.html"
};
// ...
Padding = new Thickness(0, 40, 0, 0);
Content = hybridWebView;
}

The HybridWebView instance will be used to display a native web control on each platform. It's Uri property is set
to an HTML file that is stored in each platform project, and which will be displayed by the native web control. The
rendered HTML asks the user to enter their name, with a JavaScript function invoking a C# Action in response to
an HTML button click.
The HybridWebViewPage registers the action to be invoked from JavaScript, as shown in the following code example:

public partial class HybridWebViewPage : ContentPage


{
public HybridWebViewPage()
{
// ...
hybridWebView.RegisterAction(data => DisplayAlert("Alert", "Hello " + data, "OK"));
}
}

This action calls the DisplayAlert method to display a modal pop-up that presents the name entered in the HTML
page displayed by the HybridWebView instance.
A custom renderer can now be added to each application project to enhance the platform web controls by allowing
C# code to be invoked from JavaScript.

Create the custom renderer on each platform


The process for creating the custom renderer class is as follows:
1. Create a subclass of the WkWebViewRenderer class on iOS, and the WebViewRenderer class on Android and UWP,
that renders the custom control.
2. Override the OnElementChanged method that renders the WebView and write logic to customize it. This method is
called when a HybridWebView object is created.
3. Add an ExportRenderer attribute to the custom renderer class or AssemblyInfo.cs, to specify that it will be used
to render the Xamarin.Forms custom control. This attribute is used to register the custom renderer with
Xamarin.Forms.

NOTE
For most Xamarin.Forms elements, it is optional to provide a custom renderer in each platform project. If a custom renderer
isn't registered, then the default renderer for the control's base class will be used. However, custom renderers are required in
each platform project when rendering a View element.

The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationships between them:

The custom control is rendered by platform renderer classes, which derive from the
HybridWebView
WkWebViewRenderer class on iOS, and from the WebViewRenderer class on Android and UWP. This results in each
HybridWebView custom control being rendered with native web controls, as shown in the following screenshots:

The WkWebViewRenderer and WebViewRenderer classes expose the OnElementChanged method, which is called when
the Xamarin.Forms custom control is created to render the corresponding native web control. This method takes a
VisualElementChangedEventArgs parameter that contains OldElement and NewElement properties. These properties
represent the Xamarin.Forms element that the renderer was attached to, and the Xamarin.Forms element that the
renderer is attached to, respectively. In the sample application the OldElement property will be null and the
NewElement property will contain a reference to the HybridWebView instance.

An overridden version of the OnElementChanged method, in each platform renderer class, is the place to perform the
native web control customization. A reference to the Xamarin.Forms control that's being rendered can be obtained
through the Element property.
Each custom renderer class is decorated with an ExportRenderer attribute that registers the renderer with
Xamarin.Forms. The attribute takes two parameters – the type name of the Xamarin.Forms custom control being
rendered, and the type name of the custom renderer. The assembly prefix to the attribute specifies that the
attribute applies to the entire assembly.
The following sections discuss the structure of the web page loaded by each native web control, the process for
invoking C# from JavaScript, and the implementation of this in each platform custom renderer class.
Create the web page
The following code example shows the web page that will be displayed by the HybridWebView custom control:

<html>
<body>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<h1>HybridWebView Test</h1>
<br />
Enter name: <input type="text" id="name">
<br />
<br />
<button type="button" onclick="javascript: invokeCSCode($('#name').val());">Invoke C# Code</button>
<br />
<p id="result">Result:</p>
<script type="text/javascript">function log(str) {
$('#result').text($('#result').text() + " " + str);
}

function invokeCSCode(data) {
try {
log("Sending Data:" + data);
invokeCSharpAction(data);
}
catch (err) {
log(err);
}
}</script>
</body>
</html>

The web page allows a user to enter their name in an input element, and provides a button element that will
invoke C# code when clicked. The process for achieving this is as follows:
When the user clicks on the button element, the invokeCSCode JavaScript function is called, with the value of
the input element being passed to the function.
The invokeCSCode function calls the log function to display the data it is sending to the C# Action . It then
calls the invokeCSharpAction method to invoke the C# Action , passing the parameter received from the input
element.
The invokeCSharpAction JavaScript function is not defined in the web page, and will be injected into it by each
custom renderer.
On iOS, this HTML file resides in the Content folder of the platform project, with a build action of
BundleResource. On Android, this HTML file resides in the Assets/Content folder of the platform project, with a
build action of AndroidAsset.
Invoke C# from JavaScript
The process for invoking C# from JavaScript is identical on each platform:
The custom renderer creates a native web control and loads the HTML file specified by the HybridWebView.Uri
property.
Once the web page is loaded, the custom renderer injects the invokeCSharpAction JavaScript function into the
web page.
When the user enters their name and clicks on the HTML button element, the invokeCSCode function is
invoked, which in turn invokes the invokeCSharpAction function.
The invokeCSharpAction function invokes a method in the custom renderer, which in turn invokes the
HybridWebView.InvokeAction method.
The HybridWebView.InvokeAction method invokes the registered Action .

The following sections will discuss how this process is implemented on each platform.
Create the custom renderer on iOS
The following code example shows the custom renderer for the iOS platform:

[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]


namespace CustomRenderer.iOS
{
public class HybridWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler
{
const string JavaScriptFunction = "function invokeCSharpAction(data)
{window.webkit.messageHandlers.invokeAction.postMessage(data);}";
WKUserContentController userController;

public HybridWebViewRenderer() : this(new WKWebViewConfiguration())


{
}

public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)


{
userController = config.UserContentController;
var script = new WKUserScript(new NSString(JavaScriptFunction),
WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript(script);
userController.AddScriptMessageHandler(this, "invokeAction");
}

protected override void OnElementChanged(VisualElementChangedEventArgs e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
userController.RemoveAllUserScripts();
userController.RemoveScriptMessageHandler("invokeAction");
HybridWebView hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}

if (e.NewElement != null)
{
string filename = Path.Combine(NSBundle.MainBundle.BundlePath,
$"Content/{((HybridWebView)Element).Uri}");
LoadRequest(new NSUrlRequest(new NSUrl(filename, false)));
}
}

public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage


message)
{
((HybridWebView)Element).InvokeAction(message.Body.ToString());
}
}
}

The HybridWebViewRenderer class loads the web page specified in the HybridWebView.Uri property into a native
WKWebView control, and the invokeCSharpAction JavaScript function is injected into the web page. Once the user
enters their name and clicks the HTML button element, the invokeCSharpAction JavaScript function is executed,
with the DidReceiveScriptMessage method being called after a message is received from the web page. In turn, this
method invokes the HybridWebView.InvokeAction method, which will invoke the registered action to display the
pop-up.
This functionality is achieved as follows:
The renderer constructor creates a WkWebViewConfiguration object, and retrieves its WKUserContentController
object. The WkUserContentController object allows posting messages and injecting user scripts into a web page.
The renderer constructor creates a WKUserScript object, which injects the invokeCSharpAction JavaScript
function into the web page after the web page is loaded.
The renderer constructor calls the WKUserContentController.AddUserScript method to add the WKUserScript
object to the content controller.
The renderer constructor calls the WKUserContentController.AddScriptMessageHandler method to add a script
message handler named invokeAction to the WKUserContentController object, which will cause the JavaScript
function window.webkit.messageHandlers.invokeAction.postMessage(data) to be defined in all frames in all
WebView instances that use the WKUserContentController object.
Provided that the custom renderer is attached to a new Xamarin.Forms element:
The WKWebView.LoadRequest method loads the HTML file that's specified by the HybridWebView.Uri
property. The code specifies that the file is stored in the Content folder of the project. Once the web
page is displayed, the invokeCSharpAction JavaScript function will be injected into the web page.
When the element the renderer is attached to changes:
Resources are released.

NOTE
The WKWebView class is only supported in iOS 8 and later.

In addition, Info.plist must be updated to include the following values:

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

Create the custom renderer on android


The following code example shows the custom renderer for the Android platform:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.Droid
{
public class HybridWebViewRenderer : WebViewRenderer
{
const string JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
Context _context;

public HybridWebViewRenderer(Context context) : base(context)


{
_context = context;
}

protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
((HybridWebView)Element).Cleanup();
}
if (e.NewElement != null)
{
Control.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
Control.LoadUrl($"file:///android_asset/Content/{((HybridWebView)Element).Uri}");
}
}
}
}

The HybridWebViewRenderer class loads the web page specified in the HybridWebView.Uri property into a native
WebView control, and the invokeCSharpAction JavaScript function is injected into the web page, after the web page
has finished loading, with the OnPageFinished override in the JavascriptWebViewClient class:

public class JavascriptWebViewClient : WebViewClient


{
string _javascript;

public JavascriptWebViewClient(string javascript)


{
_javascript = javascript;
}

public override void OnPageFinished(WebView view, string url)


{
base.OnPageFinished(view, url);
view.EvaluateJavascript(_javascript, null);
}
}

Once the user enters their name and clicks the HTML button element, the invokeCSharpAction JavaScript function
is executed. This functionality is achieved as follows:
Provided that the custom renderer is attached to a new Xamarin.Forms element:
The SetWebViewClient method sets a new JavascriptWebViewClient object as the implementation of
WebViewClient .
The WebView.AddJavascriptInterface method injects a new JSBridge instance into the main frame of the
WebView's JavaScript context, naming it jsBridge . This allows methods in the JSBridge class to be
accessed from JavaScript.
The WebView.LoadUrl method loads the HTML file that's specified by the HybridWebView.Uri property.
The code specifies that the file is stored in the Content folder of the project.
In the JavascriptWebViewClient class, the invokeCSharpAction JavaScript function is injected into the web
page once the page has finished loading.
When the element the renderer is attached to changes:
Resources are released.
When the invokeCSharpAction JavaScript function is executed, it in turn invokes the JSBridge.InvokeAction
method, which is shown in the following code example:

public class JSBridge : Java.Lang.Object


{
readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;

public JSBridge(HybridWebViewRenderer hybridRenderer)


{
hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
}

[JavascriptInterface]
[Export("invokeAction")]
public void InvokeAction(string data)
{
HybridWebViewRenderer hybridRenderer;

if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer))


{
((HybridWebView)hybridRenderer.Element).InvokeAction(data);
}
}
}

The class must derive from Java.Lang.Object , and methods that are exposed to JavaScript must be decorated with
the [JavascriptInterface] and [Export] attributes. Therefore, when the invokeCSharpAction JavaScript function
is injected into the web page and is executed, it will call the JSBridge.InvokeAction method due to being decorated
with the [JavascriptInterface] and [Export("invokeAction")] attributes. In turn, the InvokeAction method
invokes the HybridWebView.InvokeAction method, which will invoke the registered action to display the pop-up.

IMPORTANT
Android projects that use the [Export] attribute must include a reference to Mono.Android.Export , or a compiler error
will result.

Note that the JSBridge class maintains a WeakReference to the HybridWebViewRenderer class. This is to avoid
creating a circular reference between the two classes. For more information see Weak References.
Create the custom renderer on UWP
The following code example shows the custom renderer for UWP:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.UWP
{
public class HybridWebViewRenderer : WebViewRenderer
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.external.notify(data);}";

protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
Control.NavigationCompleted -= OnWebViewNavigationCompleted;
Control.ScriptNotify -= OnWebViewScriptNotify;
}
if (e.NewElement != null)
{
Control.NavigationCompleted += OnWebViewNavigationCompleted;
Control.ScriptNotify += OnWebViewScriptNotify;
Control.Source = new Uri($"ms-appx-web:///Content//{((HybridWebView)Element).Uri}");
}
}

async void OnWebViewNavigationCompleted(Windows.UI.Xaml.Controls.WebView sender,


WebViewNavigationCompletedEventArgs args)
{
if (args.IsSuccess)
{
// Inject JS script
await Control.InvokeScriptAsync("eval", new[] { JavaScriptFunction });
}
}

void OnWebViewScriptNotify(object sender, NotifyEventArgs e)


{
((HybridWebView)Element).InvokeAction(e.Value);
}
}
}

The HybridWebViewRenderer class loads the web page specified in the HybridWebView.Uri property into a native
WebView control, and the invokeCSharpAction JavaScript function is injected into the web page, after the web page
has loaded, with the WebView.InvokeScriptAsync method. Once the user enters their name and clicks the HTML
button element, the invokeCSharpAction JavaScript function is executed, with the OnWebViewScriptNotify method
being called after a notification is received from the web page. In turn, this method invokes the
HybridWebView.InvokeAction method, which will invoke the registered action to display the pop-up.

This functionality is achieved as follows:


Provided that the custom renderer is attached to a new Xamarin.Forms element:
Event handlers for the NavigationCompleted and ScriptNotify events are registered. The
NavigationCompleted event fires when either the native WebView control has finished loading the current
content or if navigation has failed. The ScriptNotify event fires when the content in the native WebView
control uses JavaScript to pass a string to the application. The web page fires the ScriptNotify event by
calling window.external.notify while passing a string parameter.
The WebView.Source property is set to the URI of the HTML file that's specified by the HybridWebView.Uri
property. The code assumes that the file is stored in the Content folder of the project. Once the web
page is displayed, the NavigationCompleted event will fire and the OnWebViewNavigationCompleted method
will be invoked. The invokeCSharpAction JavaScript function will then be injected into the web page with
the WebView.InvokeScriptAsync method, provided that the navigation completed successfully.
When the element the renderer is attached to changes:
Events are unsubscribed from.

Related links
HybridWebView (sample)
Implementing a View
9 minutes to read • Edit Online

Download the sample


Xamarin.Forms custom user interface controls should derive from the View class, which is used to place layouts
and controls on the screen. This article demonstrates how to create a custom renderer for a Xamarin.Forms custom
control that's used to display a preview video stream from the device's camera.
Every Xamarin.Forms view has an accompanying renderer for each platform that creates an instance of a native
control. When a View is rendered by a Xamarin.Forms application in iOS, the ViewRenderer class is instantiated,
which in turn instantiates a native UIView control. On the Android platform, the ViewRenderer class instantiates a
native View control. On the Universal Windows Platform (UWP ), the ViewRenderer class instantiates a native
FrameworkElement control. For more information about the renderer and native control classes that Xamarin.Forms
controls map to, see Renderer Base Classes and Native Controls.
The following diagram illustrates the relationship between the View and the corresponding native controls that
implement it:

The rendering process can be used to implement platform-specific customizations by creating a custom renderer
for a View on each platform. The process for doing this is as follows:
1. Create a Xamarin.Forms custom control.
2. Consume the custom control from Xamarin.Forms.
3. Create the custom renderer for the control on each platform.
Each item will now be discussed in turn, to implement a CameraPreview renderer that displays a preview video
stream from the device's camera. Tapping on the video stream will stop and start it.

Creating the Custom Control


A custom control can be created by subclassing the View class, as shown in the following code example:
public class CameraPreview : View
{
public static readonly BindableProperty CameraProperty = BindableProperty.Create (
propertyName: "Camera",
returnType: typeof(CameraOptions),
declaringType: typeof(CameraPreview),
defaultValue: CameraOptions.Rear);

public CameraOptions Camera {


get { return (CameraOptions)GetValue (CameraProperty); }
set { SetValue (CameraProperty, value); }
}
}

The CameraPreview custom control is created in the .NET Standard library project and defines the API for the
control. The custom control exposes a Camera property that's used for controlling whether the video stream
should be displayed from the front or rear camera on the device. If a value isn't specified for the Camera property
when the control is created, it defaults to specifying the rear camera.

Consuming the Custom Control


The CameraPreview custom control can be referenced in XAML in the .NET Standard library project by declaring a
namespace for its location and using the namespace prefix on the custom control element. The following code
example shows how the CameraPreview custom control can be consumed by a XAML page:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
<ContentPage.Content>
<StackLayout>
<Label Text="Camera Preview:" />
<local:CameraPreview Camera="Rear"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

The local namespace prefix can be named anything. However, the clr-namespace and assembly values must
match the details of the custom control. Once the namespace is declared, the prefix is used to reference the custom
control.
The following code example shows how the CameraPreview custom control can be consumed by a C# page:
public class MainPageCS : ContentPage
{
public MainPageCS ()
{
...
Content = new StackLayout {
Children = {
new Label { Text = "Camera Preview:" },
new CameraPreview {
Camera = CameraOptions.Rear,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
}
}
};
}
}

An instance of the CameraPreview custom control will be used to display the preview video stream from the
device's camera. Aside from optionally specifying a value for the Camera property, customization of the control will
be carried out in the custom renderer.
A custom renderer can now be added to each application project to create platform-specific camera preview
controls.

Creating the Custom Renderer on each Platform


The process for creating the custom renderer class is as follows:
1. Create a subclass of the ViewRenderer<T1,T2> class that renders the custom control. The first type argument
should be the custom control the renderer is for, in this case CameraPreview . The second type argument should
be the native control that will implement the custom control.
2. Override the OnElementChanged method that renders the custom control and write logic to customize it. This
method is called when the corresponding Xamarin.Forms control is created.
3. Add an ExportRenderer attribute to the custom renderer class to specify that it will be used to render the
Xamarin.Forms custom control. This attribute is used to register the custom renderer with Xamarin.Forms.

NOTE
For most Xamarin.Forms elements, it is optional to provide a custom renderer in each platform project. If a custom renderer
isn't registered, then the default renderer for the control's base class will be used. However, custom renderers are required in
each platform project when rendering a View element.

The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationships between them:

The CameraPreview custom control is rendered by platform-specific renderer classes, which all derive from the
ViewRenderer class for each platform. This results in each CameraPreview custom control being rendered with
platform-specific controls, as shown in the following screenshots:

The ViewRenderer class exposes the OnElementChanged method, which is called when the Xamarin.Forms custom
control is created to render the corresponding native control. This method takes an ElementChangedEventArgs
parameter that contains OldElement and NewElement properties. These properties represent the Xamarin.Forms
element that the renderer was attached to, and the Xamarin.Forms element that the renderer is attached to,
respectively. In the sample application, the OldElement property will be null and the NewElement property will
contain a reference to the CameraPreview instance.
An overridden version of the OnElementChanged method, in each platform-specific renderer class, is the place to
perform the native control instantiation and customization. The SetNativeControl method should be used to
instantiate the native control, and this method will also assign the control reference to the Control property. In
addition, a reference to the Xamarin.Forms control that's being rendered can be obtained through the Element
property.
In some circumstances, the OnElementChanged method can be called multiple times. Therefore, to prevent memory
leaks, care must be taken when instantiating a new native control. The approach to use when instantiating a new
native control in a custom renderer is shown in the following code example:

protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)


{
base.OnElementChanged (e);

if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}

if (e.NewElement != null) {
if (Control == null) {
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
}
// Configure the control and subscribe to event handlers
}
}

A new native control should only be instantiated once, when the Control property is null . In addition, the control
should only be created, configured, and event handlers subscribed to when the custom renderer is attached to a
new Xamarin.Forms element. Similarly, any event handlers that were subscribed to should only be unsubscribed
from when the element that the renderer is attached to changes. Adopting this approach will help to create a
performant custom renderer that doesn't suffer from memory leaks.

IMPORTANT
The SetNativeControl method should only be called if e.NewElement is not null .

Each custom renderer class is decorated with an ExportRenderer attribute that registers the renderer with
Xamarin.Forms. The attribute takes two parameters – the type name of the Xamarin.Forms custom control being
rendered, and the type name of the custom renderer. The assembly prefix to the attribute specifies that the
attribute applies to the entire assembly.
The following sections discuss the implementation of each platform-specific custom renderer class.
Creating the Custom Renderer on iOS
The following code example shows the custom renderer for the iOS platform:

[assembly: ExportRenderer (typeof(CameraPreview), typeof(CameraPreviewRenderer))]


namespace CustomRenderer.iOS
{
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, UICameraPreview>
{
UICameraPreview uiCameraPreview;

protected override void OnElementChanged (ElementChangedEventArgs<CameraPreview> e)


{
base.OnElementChanged (e);

if (e.OldElement != null) {
// Unsubscribe
uiCameraPreview.Tapped -= OnCameraPreviewTapped;
}
if (e.NewElement != null) {
if (Control == null) {
uiCameraPreview = new UICameraPreview (e.NewElement.Camera);
SetNativeControl (uiCameraPreview);
}
// Subscribe
uiCameraPreview.Tapped += OnCameraPreviewTapped;
}
}

void OnCameraPreviewTapped (object sender, EventArgs e)


{
if (uiCameraPreview.IsPreviewing) {
uiCameraPreview.CaptureSession.StopRunning ();
uiCameraPreview.IsPreviewing = false;
} else {
uiCameraPreview.CaptureSession.StartRunning ();
uiCameraPreview.IsPreviewing = true;
}
}
...
}
}

Provided that the Controlproperty is null , the SetNativeControl method is called to instantiate a new
UICameraPreview control and to assign a reference to it to the Control property. The UICameraPreview control is a
platform-specific custom control that uses the AVCapture APIs to provide the preview stream from the camera. It
exposes a Tapped event that's handled by the OnCameraPreviewTapped method to stop and start the video preview
when it's tapped. The Tapped event is subscribed to when the custom renderer is attached to a new
Xamarin.Forms element, and unsubscribed from only when the element the renderer is attached to changes.
Creating the Custom Renderer on Android
The following code example shows the custom renderer for the Android platform:

[assembly: ExportRenderer(typeof(CustomRenderer.CameraPreview), typeof(CameraPreviewRenderer))]


namespace CustomRenderer.Droid
{
public class CameraPreviewRenderer : ViewRenderer<CustomRenderer.CameraPreview,
CustomRenderer.Droid.CameraPreview>
{
CameraPreview cameraPreview;

public CameraPreviewRenderer(Context context) : base(context)


{
}

protected override void OnElementChanged(ElementChangedEventArgs<CustomRenderer.CameraPreview> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
cameraPreview.Click -= OnCameraPreviewClicked;
}
if (e.NewElement != null)
{
if (Control == null)
{
cameraPreview = new CameraPreview(Context);
SetNativeControl(cameraPreview);
}
Control.Preview = Camera.Open((int)e.NewElement.Camera);

// Subscribe
cameraPreview.Click += OnCameraPreviewClicked;
}
}

void OnCameraPreviewClicked(object sender, EventArgs e)


{
if (cameraPreview.IsPreviewing)
{
cameraPreview.Preview.StopPreview();
cameraPreview.IsPreviewing = false;
}
else
{
cameraPreview.Preview.StartPreview();
cameraPreview.IsPreviewing = true;
}
}
...
}
}

Provided that the Control property is null , the SetNativeControl method is called to instantiate a new
CameraPreview control and assign a reference to it to the Control property. The CameraPreview control is a
platform-specific custom control that uses the Camera API to provide the preview stream from the camera. The
CameraPreview control is then configured, provided that the custom renderer is attached to a new Xamarin.Forms
element. This configuration involves creating a new native Camera object to access a particular hardware camera,
and registering an event handler to process the Click event. In turn this handler will stop and start the video
preview when it's tapped. The Click event is unsubscribed from if the Xamarin.Forms element the renderer is
attached to changes.
Creating the Custom Renderer on UWP
The following code example shows the custom renderer for UWP:

[assembly: ExportRenderer(typeof(CameraPreview), typeof(CameraPreviewRenderer))]


namespace CustomRenderer.UWP
{
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, Windows.UI.Xaml.Controls.CaptureElement>
{
...
CaptureElement _captureElement;
bool _isPreviewing;

protected override void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
Tapped -= OnCameraPreviewTapped;
...
}
if (e.NewElement != null)
{
if (Control == null)
{
...
_captureElement = new CaptureElement();
_captureElement.Stretch = Stretch.UniformToFill;

SetupCamera();
SetNativeControl(_captureElement);
}
// Subscribe
Tapped += OnCameraPreviewTapped;
}
}

async void OnCameraPreviewTapped(object sender, TappedRoutedEventArgs e)


{
if (_isPreviewing)
{
await StopPreviewAsync();
}
else
{
await StartPreviewAsync();
}
}
...
}
}

Provided that the Control property is null , a new CaptureElement is instantiated and the SetupCamera method is
called, which uses the MediaCapture API to provide the preview stream from the camera. The SetNativeControl
method is then called to assign a reference to the CaptureElement instance to the Control property. The
CaptureElement control exposes a Tapped event that's handled by the OnCameraPreviewTapped method to stop and
start the video preview when it's tapped. The Tapped event is subscribed to when the custom renderer is attached
to a new Xamarin.Forms element, and unsubscribed from only when the element the renderer is attached to
changes.
NOTE
It's important to stop and dispose of the objects that provide access to the camera in a UWP application. Failure to do so can
interfere with other applications that attempt to access the device's camera. For more information, see Display the camera
preview.

Summary
This article has demonstrated how to create a custom renderer for a Xamarin.Forms custom control that's used to
display a preview video stream from the device's camera. Xamarin.Forms custom user interface controls should
derive from the View class, which is used to place layouts and controls on the screen.

Related Links
CustomRendererView (sample)
Implementing a video player
2 minutes to read • Edit Online

Download the sample


It is sometimes desirable to play video files in a Xamarin.Forms application. This series of articles discusses how to
write custom renderers for iOS, Android, and the Universal Windows Platform (UWP ) for a Xamarin.Forms class
named VideoPlayer .
In the VideoPlayerDemos sample, all the files that implement and support VideoPlayer are in folders named
FormsVideoLibrary and identified with the namespace FormsVideoLibrary or namespaces that begin
FormsVideoLibrary . This organization and naming should make it easy to copy the video player files into your own
Xamarin.Forms solution.
VideoPlayer can play video files from three types of sources:
The Internet using a URL
A resource embedded in the platform application
The device's video library
Video players require transport controls, which are buttons for playing and pausing the video, and a positioning
bar that shows the progress through the video and allows the user to skip quickly to a different location.
VideoPlayer can use either the transport controls and positioning bar provided by the platform (as shown below ),
or you can supply custom transport controls and a positioning bar. Here's the program running under iOS,
Android, and the Universal Windows Platform:

Of course, you can turn the phone sideways for a larger view.
A more sophisticated video player would have some additional features, such as volume control, a mechanism to
interrupt the video when a telephone call comes through, and a way of keeping the screen active during playback.
The following series of articles progressively shows how the platform renderers and supporting classes are built:

Creating the platform video players


Each platform requires a VideoPlayerRenderer class that creates and maintains a video player control supported by
the platform. This article shows the structure of the renderer classes, and how the players are created.

Playing a Web video


Probably the most common source of videos for a video player is the Internet. This article describes how a Web
video can be referenced and used as a source for the video player.

Binding video sources to the player


This article uses a ListView to present a collection of videos to play. One program shows how the code-behind
file can set the video source of the video player, but a second program shows how you can use data binding
between the ListView and the video player.

Loading application resource videos


Videos can be embedded as resources in the platform projects. This article shows how to store those resources
and later load them into the program to be played by the video player.

Accessing the device's video library


When a video is created using the device's camera, the video file is stored in the device's image library. This article
shows how to access the device's image picker to select the video, and then play it using the video player.

Custom video transport controls


Although the video players on each platform provide their own transport controls in the form of buttons for Play
and Pause, you can suppress the display of those buttons and supply your own. This article shows you how.

Custom video positioning


Each of the platform video players has a position bar that shows the progress of the video and allows you to skip
ahead or back to a particular position. This article demonstrates how you can replace that position bar with a
custom control.

Related Links
Video Player Demos (sample)
Creating the platform video players
8 minutes to read • Edit Online

Download the sample


The VideoPlayerDemos solution contains all the code to implement a video player for Xamarin.Forms. It also
includes a series of pages that demonstrates how to use the video player within an application. All the VideoPlayer
code and its platform renderers reside in project folders named FormsVideoLibrary , and also use the namespace
FormsVideoLibrary . This should make it easy to copy the files into your own application and reference the classes.

The video player


The VideoPlayer class is part of the VideoPlayerDemos .NET Standard library that is shared among the
platforms. It derives from View :

using System;
using Xamarin.Forms;

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
}
}

The members of this class (and the IVideoPlayerController interface) are described in the articles that follow.
Each of the platforms contains a class named VideoPlayerRenderer that contains the platform-specific code to
implement a video player. The primary task of this renderer is to create a video player for that platform.
The iOS player view controller
Several classes are involved when implementing a video player in iOS. The application first creates an
AVPlayerViewController and then sets the Player property to an object of type AVPlayer . Additional classes are
required when the player is assigned a video source.
Like all renderers, the iOS VideoPlayerRenderer contains an ExportRenderer attribute that identifies the
VideoPlayer view with the renderer:
using System;
using System.ComponentModel;
using System.IO;

using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using UIKit;

using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(FormsVideoLibrary.VideoPlayer),
typeof(FormsVideoLibrary.iOS.VideoPlayerRenderer))]

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
}
}

Generally a renderer that sets a platform control derives from the ViewRenderer<View, NativeView> class, where
View is the Xamarin.Forms View derivative (in this case, VideoPlayer ) and NativeView is an iOS UIView
derivative for the renderer class. For this renderer, that generic argument is simply set to UIView , for reasons you'll
see shortly.
When a renderer is based on a UIViewController derivative (as this one is), then the class should override the
ViewController property and return the view controller, in this case AVPlayerViewController . That is the purpose of
the _playerViewController field:
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
AVPlayer player;
AVPlayerItem playerItem;
AVPlayerViewController _playerViewController; // solely for ViewController property

public override UIViewController ViewController => _playerViewController;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)


{
base.OnElementChanged(args);

if (args.NewElement != null)
{
if (Control == null)
{
// Create AVPlayerViewController
_playerViewController = new AVPlayerViewController();

// Set Player property to AVPlayer


player = new AVPlayer();
_playerViewController.Player = player;

// Use the View from the controller as the native control


SetNativeControl(_playerViewController.View);
}
···
}
}
···
}
}

The primary responsibility of the OnElementChanged override is to check if the Control property is null and, if so,
create a platform control, and pass it to the SetNativeControl method. In this case, that object is only available
from the View property of the AVPlayerViewController . That UIView derivative happens to be a private class
named AVPlayerView , but because it's private, it cannot be explicitly specified as the second generic argument to
ViewRenderer .

Generally the Control property of the renderer class thereafter refers to the UIView used to implement the
renderer, but in this case the Control property is not used elsewhere.
The Android video view
The Android renderer for VideoPlayer is based on the Android VideoView class. However, if VideoView is used by
itself to play a video in a Xamarin.Forms application, the video fills the area alloted for the VideoPlayer without
maintaining the correct aspect ratio. For this reason (as you'll see shortly), the VideoView is made a child of an
Android RelativeLayout . A using directive defines ARelativeLayout to distinguish it from the Xamarin.Forms
RelativeLayout , and that's the second generic argument in the ViewRenderer :
using System;
using System.ComponentModel;
using System.IO;

using Android.Content;
using Android.Media;
using Android.Widget;
using ARelativeLayout = Android.Widget.RelativeLayout;

using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(FormsVideoLibrary.VideoPlayer),
typeof(FormsVideoLibrary.Droid.VideoPlayerRenderer))]

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
public VideoPlayerRenderer(Context context) : base(context)
{
}
···
}
}

Beginning in Xamarin.Forms 2.5, Android renderers should include a constructor with a Context argument.
The OnElementChanged override creates both the VideoView and RelativeLayout and sets the layout parameters for
the VideoView to center it within the RelativeLayout .
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
MediaController mediaController; // Used to display transport controls
bool isPrepared;
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
base.OnElementChanged(args);

if (args.NewElement != null)
{
if (Control == null)
{
// Save the VideoView for future reference
videoView = new VideoView(Context);

// Put the VideoView in a RelativeLayout


ARelativeLayout relativeLayout = new ARelativeLayout(Context);
relativeLayout.AddView(videoView);

// Center the VideoView in the RelativeLayout


ARelativeLayout.LayoutParams layoutParams =
new ARelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent);
layoutParams.AddRule(LayoutRules.CenterInParent);
videoView.LayoutParameters = layoutParams;

// Handle a VideoView event


videoView.Prepared += OnVideoViewPrepared;

// Use the RelativeLayout as the native control


SetNativeControl(relativeLayout);
}
···
}
···
}

protected override void Dispose(bool disposing)


{
if (Control != null && videoView != null)
{
videoView.Prepared -= OnVideoViewPrepared;
}
base.Dispose(disposing);
}

void OnVideoViewPrepared(object sender, EventArgs args)


{
isPrepared = true;
···
}
···
}
}

A handler for the Prepared event is attached in this method and detached in the Dispose method. This event is
fired when the VideoView has sufficient information to begin playing a video file.
The UWP media element
In the Universal Windows Platform (UWP ), the most common video player is MediaElement . That documentation
of MediaElement indicates that the MediaPlayerElement should be used instead when it's only necessary to support
versions of Windows 10 beginning with build 1607.
The OnElementChanged override needs to create a MediaElement , set a couple of event handlers, and pass the
MediaElement object to SetNativeControl :

using System;
using System.ComponentModel;

using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;

[assembly: ExportRenderer(typeof(FormsVideoLibrary.VideoPlayer),
typeof(FormsVideoLibrary.UWP.VideoPlayerRenderer))]

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
base.OnElementChanged(args);

if (args.NewElement != null)
{
if (Control == null)
{
MediaElement mediaElement = new MediaElement();
SetNativeControl(mediaElement);

mediaElement.MediaOpened += OnMediaElementMediaOpened;
mediaElement.CurrentStateChanged += OnMediaElementCurrentStateChanged;
}
···
}
···
}

protected override void Dispose(bool disposing)


{
if (Control != null)
{
Control.MediaOpened -= OnMediaElementMediaOpened;
Control.CurrentStateChanged -= OnMediaElementCurrentStateChanged;
}

base.Dispose(disposing);
}
···
}
}

The two event handlers are detached in the Dispose event for the renderer.

Showing the transport controls


All the video players included in the platforms support a default set of transport controls that include buttons for
playing and pausing, and a bar to indicate the current position within the video, and to move to a new position.
The VideoPlayer class defines a property named AreTransportControlsEnabled and sets the default value to true :
namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// AreTransportControlsEnabled property
public static readonly BindableProperty AreTransportControlsEnabledProperty =
BindableProperty.Create(nameof(AreTransportControlsEnabled), typeof(bool), typeof(VideoPlayer),
true);

public bool AreTransportControlsEnabled


{
set { SetValue(AreTransportControlsEnabledProperty, value); }
get { return (bool)GetValue(AreTransportControlsEnabledProperty); }
}
···
}
}

Although this property has both set and get accessors, the renderer has to handle cases only when the property
is set. The get accessor simply returns the current value of the property.
Properties such as AreTransportControlsEnabled are handled in platform renderers in two ways:
The first time is when Xamarin.Forms creates a VideoPlayer element. This is indicated in the
OnElementChanged override of the renderer when the NewElement property is not null . At this time, the
renderer can set is own platform video player from the property's initial value as defined in the VideoPlayer
.
If the property in VideoPlayer later changes, then the OnElementPropertyChanged method in the renderer is
called. This allows the renderer to update the platform video player based on the new property setting.
The following sections discuss how the AreTransportControlsEnabled property is handled on each platform.
iOS playback controls
The property of the iOS AVPlayerViewController that governs the display of transport controls is
ShowsPlaybackControls . Here's how that property is set in the iOS VideoViewRenderer :
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
AVPlayerViewController _playerViewController; // solely for ViewController property

public override UIViewController ViewController => _playerViewController;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)


{
···
if (args.NewElement != null)
{
···
SetAreTransportControlsEnabled();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(sender, args);

if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}

void SetAreTransportControlsEnabled()
{
((AVPlayerViewController)ViewController).ShowsPlaybackControls =
Element.AreTransportControlsEnabled;
}
···
}
}

The Element property of the renderer refers to the VideoPlayer class.


The Android media controller
In Android, displaying the transport controls requires creating a MediaController object and associating it with the
VideoView object. The mechanics are demonstrated in the SetAreTransportControlsEnabled method:
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
MediaController mediaController; // Used to display transport controls
bool isPrepared;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)


{
···
if (args.NewElement != null)
{
···
SetAreTransportControlsEnabled();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(sender, args);

if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}

void SetAreTransportControlsEnabled()
{
if (Element.AreTransportControlsEnabled)
{
mediaController = new MediaController(Context);
mediaController.SetMediaPlayer(videoView);
videoView.SetMediaController(mediaController);
}
else
{
videoView.SetMediaController(null);

if (mediaController != null)
{
mediaController.SetMediaPlayer(null);
mediaController = null;
}
}
}
···
}
}

The UWP Transport Controls property


The UWP MediaElement defines a property named AreTransportControlsEnabled , so that property is set from the
VideoPlayer property of the same name:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetAreTransportControlsEnabled();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(sender, args);

if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}

void SetAreTransportControlsEnabled()
{
Control.AreTransportControlsEnabled = Element.AreTransportControlsEnabled;
}
···
}
}

One more property is necessary to begin playing a video: This is the crucial Source property that references a
video file. Implementing the Source property is described in the next article, Playing a Web Video.

Related Links
Video Player Demos (sample)
Playing a Web video
8 minutes to read • Edit Online

Download the sample


The VideoPlayerclass defines a Source property used to specify the source of the video file, as well as an
AutoPlay property. AutoPlay has a default setting of true , which means that the video should begin playing
automatically after Source has been set:

using System;
using Xamarin.Forms;

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// Source property
public static readonly BindableProperty SourceProperty =
BindableProperty.Create(nameof(Source), typeof(VideoSource), typeof(VideoPlayer), null);

[TypeConverter(typeof(VideoSourceConverter))]
public VideoSource Source
{
set { SetValue(SourceProperty, value); }
get { return (VideoSource)GetValue(SourceProperty); }
}

// AutoPlay property
public static readonly BindableProperty AutoPlayProperty =
BindableProperty.Create(nameof(AutoPlay), typeof(bool), typeof(VideoPlayer), true);

public bool AutoPlay


{
set { SetValue(AutoPlayProperty, value); }
get { return (bool)GetValue(AutoPlayProperty); }
}
···
}
}

The Source property is of type VideoSource , which is patterned after the Xamarin.Forms ImageSource abstract
class, and its three derivatives, UriImageSource , FileImageSource , and StreamImageSource . No stream option is
available for the VideoPlayer however, because iOS and Android do not support playing a video from a stream.

Video sources
The abstract VideoSource class consists solely of three static methods that instantiate the three classes that derive
from VideoSource :
namespace FormsVideoLibrary
{
[TypeConverter(typeof(VideoSourceConverter))]
public abstract class VideoSource : Element
{
public static VideoSource FromUri(string uri)
{
return new UriVideoSource() { Uri = uri };
}

public static VideoSource FromFile(string file)


{
return new FileVideoSource() { File = file };
}

public static VideoSource FromResource(string path)


{
return new ResourceVideoSource() { Path = path };
}
}
}

The UriVideoSource class is used to specify a downloadable video file with a URI. It defines a single property of
type string :

namespace FormsVideoLibrary
{
public class UriVideoSource : VideoSource
{
public static readonly BindableProperty UriProperty =
BindableProperty.Create(nameof(Uri), typeof(string), typeof(UriVideoSource));

public string Uri


{
set { SetValue(UriProperty, value); }
get { return (string)GetValue(UriProperty); }
}
}
}

Handling objects of type UriVideoSource is described below.


The ResourceVideoSource class is used to access video files that are stored as embedded resources in the platform
application, also specified with a string property:

namespace FormsVideoLibrary
{
public class ResourceVideoSource : VideoSource
{
public static readonly BindableProperty PathProperty =
BindableProperty.Create(nameof(Path), typeof(string), typeof(ResourceVideoSource));

public string Path


{
set { SetValue(PathProperty, value); }
get { return (string)GetValue(PathProperty); }
}
}
}

Handling objects of type ResourceVideoSource is described in the article Loading Application Resource Videos. The
VideoPlayer class has no facility to load a video file stored as a resource in the .NET Standard library.
The FileVideoSource class is used to access video files from the device's video library. The single property is also
of type string :

namespace FormsVideoLibrary
{
public class FileVideoSource : VideoSource
{
public static readonly BindableProperty FileProperty =
BindableProperty.Create(nameof(File), typeof(string), typeof(FileVideoSource));

public string File


{
set { SetValue(FileProperty, value); }
get { return (string)GetValue(FileProperty); }
}
}
}

Handling objects of type FileVideoSource is described in the article Accessing the Device's Video Library.
The VideoSource class includes a TypeConverter attribute that references VideoSourceConverter :

namespace FormsVideoLibrary
{
[TypeConverter(typeof(VideoSourceConverter))]
public abstract class VideoSource : Element
{
···
}
}

This type converter is invoked when the Source property is set to a string in XAML. Here's the
VideoSourceConverter class:

namespace FormsVideoLibrary
{
public class VideoSourceConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
if (!String.IsNullOrWhiteSpace(value))
{
Uri uri;
return Uri.TryCreate(value, UriKind.Absolute, out uri) && uri.Scheme != "file" ?
VideoSource.FromUri(value) : VideoSource.FromResource(value);
}

throw new InvalidOperationException("Cannot convert null or whitespace to ImageSource");


}
}
}

The ConvertFromInvariantString method attempts to convert the string to a Uri object. If that succeeds, and the
scheme is not file: , then the method returns a UriVideoSource . Otherwise, it returns a ResourceVideoSource .

Setting the video source


All the other logic involving video sources is implemented in the individual platform renderers. The following
sections show how the platform renderers play videos when the Source property is set to a UriVideoSource
object.
The iOS video source
Two sections of the VideoPlayerRenderer are involved in setting the video source of the video player. When
Xamarin.Forms first creates an object of type VideoPlayer , the OnElementChanged method is called with the
NewElement property of the arguments object set to that VideoPlayer . The OnElementChanged method calls
SetSource :

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetSource();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
···
else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
{
SetSource();
}
···
}
···
}
}

Later on, when the Source property is changed, the OnElementPropertyChanged method is called with a
PropertyName property of "Source", and SetSource is called again.

To play a video file in iOS, an object of type AVAsset is first created to encapsulate the video file, and that is used
to create an AVPlayerItem , which is then handed off to the AVPlayer object. Here's how the SetSource method
handles the Source property when it's of type UriVideoSource :
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
AVPlayer player;
AVPlayerItem playerItem;
···
void SetSource()
{
AVAsset asset = null;

if (Element.Source is UriVideoSource)
{
string uri = (Element.Source as UriVideoSource).Uri;

if (!String.IsNullOrWhiteSpace(uri))
{
asset = AVAsset.FromUrl(new NSUrl(uri));
}
}
···
if (asset != null)
{
playerItem = new AVPlayerItem(asset);
}
else
{
playerItem = null;
}

player.ReplaceCurrentItemWithPlayerItem(playerItem);

if (playerItem != null && Element.AutoPlay)


{
player.Play();
}
}
···
}
}

The AutoPlayproperty has no analogue in the iOS video classes, so the property is examined at the end of the
SetSource method to call the Play method on the AVPlayer object.
In some cases, videos continued playing after the page with the VideoPlayer navigated back to the home page. To
stop the video, the ReplaceCurrentItemWithPlayerItem is also set in the Dispose override:

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);

if (player != null)
{
player.ReplaceCurrentItemWithPlayerItem(null);
}
}
···
}
}
The Android video source
The Android VideoPlayerRenderer needs to set the video source of the player when the VideoPlayer is first
created and later when the Source property changes:

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetSource();
···
}
}
···
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
···
else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
{
SetSource();
}
···
}
···
}
}

The SetSource method handles objects of type UriVideoSource by calling SetVideoUri on the VideoView with an
Android Uri object created from the string URI. The Uri class is fully qualified here to distinguish it from the
.NET Uri class:
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void SetSource()
{
isPrepared = false;
bool hasSetSource = false;

if (Element.Source is UriVideoSource)
{
string uri = (Element.Source as UriVideoSource).Uri;

if (!String.IsNullOrWhiteSpace(uri))
{
videoView.SetVideoURI(Android.Net.Uri.Parse(uri));
hasSetSource = true;
}
}
···

if (hasSetSource && Element.AutoPlay)


{
videoView.Start();
}
}
···
}
}

The Android VideoView doesn't have a corresponding AutoPlay property, so the Start method is called if a new
video has been set.
There is a difference between the behavior of the iOS and Android renderers if the Source property of
VideoPlayer is set to null , or if the Uri property of UriVideoSource is set to null or a blank string. If the iOS
video player is currently playing a video, and Source is set to null (or the string is null or blank),
ReplaceCurrentItemWithPlayerItem is called with null value. The current video is replaced and stops playing.

Android does not support a similar facility. If the Source property is set to null , the SetSource method simply
ignores it, and the current video continues to play.
The UWP video source
The UWP MediaElement defines an AutoPlay property, which is handled in the renderer like any other property:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetSource();
SetAutoPlay();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
···
else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
{
SetSource();
}
else if (args.PropertyName == VideoPlayer.AutoPlayProperty.PropertyName)
{
SetAutoPlay();
}
···
}
···
}
}

The SetSource property handles a UriVideoSource object by setting the Source property of MediaElement to a
.NET Uri value, or to null if the Source property of VideoPlayer is set to null :
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
async void SetSource()
{
bool hasSetSource = false;

if (Element.Source is UriVideoSource)
{
string uri = (Element.Source as UriVideoSource).Uri;

if (!String.IsNullOrWhiteSpace(uri))
{
Control.Source = new Uri(uri);
hasSetSource = true;
}
}
···
if (!hasSetSource)
{
Control.Source = null;
}
}

void SetAutoPlay()
{
Control.AutoPlay = Element.AutoPlay;
}
···
}
}

Setting a URL source


With the implementation of these properties in the three renderers, it's possible to play a video from a URL
source. The Play Web Video page in the VideoPlayDemos program is defined by the following XAML file:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.PlayWebVideoPage"
Title="Play Web Video">

<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4" />

</ContentPage>

The VideoSourceConverter class converts the string to a UriVideoSource . When you navigate to the Play Web
Video page, the video begins loading and starts playing when a sufficient quantity of data has been downloaded
and buffered. The video is about 10 minutes in length:
On each of the platforms, the transport controls fade out if they're not used but can be restored to view by tapping
the video.
You can prevent the video from automatically starting by setting the AutoPlay property to false :

<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
AutoPlay="false" />

You'll need to press the Play button to start the video.


Similarly, you can suppress the display of the transport controls by setting the AreTransportControlsEnabled
property to false :

<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
AreTransportControlsEnabled="False" />

If you set both properties to false , then the video won't begin playing and there will be no way to start it! You
would need to call Play from the code-behind file, or to create your own transport controls as described in the
article Implementing Custom Video Transport Controls.
The App.xaml file includes resources for two additional videos:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.App">
<Application.Resources>
<ResourceDictionary>

<video:UriVideoSource x:Key="ElephantsDream"
Uri="https://archive.org/download/ElephantsDream/ed_hd_512kb.mp4" />

<video:UriVideoSource x:Key="BigBuckBunny"
Uri="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
/>

<video:UriVideoSource x:Key="Sintel"
Uri="https://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4" />

</ResourceDictionary>
</Application.Resources>
</Application>

To reference one of these other movies, you can replace the explicit URL in the PlayWebVideo.xaml file with a
StaticResource markup extension, in which case VideoSourceConverter is not required to create the
UriVideoSource object:

<video:VideoPlayer Source="{StaticResource ElephantsDream}" />

Alternatively, you can set the Source property from a video file in a ListView , as described in the next article,
Binding Video Sources to the Player.

Related Links
Video Player Demos (sample)
Binding video sources to the player
2 minutes to read • Edit Online

Download the sample


When the Source property of the VideoPlayer view is set to a new video file, the existing video stops playing and
the new video begins. This is demonstrated by the Select Web Video page of the VideoPlayerDemos sample.
The page includes a ListView with the titles of the three videos referenced from the App.xaml file:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.SelectWebVideoPage"
Title="Select Web Video">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<video:VideoPlayer x:Name="videoPlayer"
Grid.Row="0" />

<ListView Grid.Row="1"
ItemSelected="OnListViewItemSelected">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Elephant's Dream</x:String>
<x:String>Big Buck Bunny</x:String>
<x:String>Sintel</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</Grid>
</ContentPage>

When a video is selected, the ItemSelected event handler in the code-behind file is executed. The handler removes
any blanks and apostrophes from the title and uses that as a key to obtain one of the resources defined in the
App.xaml file. That UriVideoSource object is then set to the Source property of the VideoPlayer .
namespace VideoPlayerDemos
{
public partial class SelectWebVideoPage : ContentPage
{
public SelectWebVideoPage()
{
InitializeComponent();
}

void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs args)


{
if (args.SelectedItem != null)
{
string key = ((string)args.SelectedItem).Replace(" ", "").Replace("'", "");
videoPlayer.Source = (UriVideoSource)Application.Current.Resources[key];
}
}
}
}

When the page first loads, no item is selected in the ListView , so you must select one for the video to begin
playing:

The Source property of VideoPlayer is backed by a bindable property, which means that it can be the target of a
data binding. This is demonstrated by the Bind to VideoPlayer page. The markup in the
BindToVideoPlayer.xaml file is supported by the following class that encapsulates a title of a video and a
corresponding VideoSource object:

namespace VideoPlayerDemos
{
public class VideoInfo
{
public string DisplayName { set; get; }

public VideoSource VideoSource { set; get; }

public override string ToString()


{
return DisplayName;
}
}
}
The ListView in the BindToVideoPlayer.xaml file contains an array of these VideoInfo objects, each one
initialized with a video title and the UriVideoSource object from the resource dictionary in App.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:VideoPlayerDemos"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.BindToVideoPlayerPage"
Title="Bind to VideoPlayer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<video:VideoPlayer x:Name="videoPlayer"
Grid.Row="0"
Source="{Binding Source={x:Reference listView},
Path=SelectedItem.VideoSource}" />

<ListView x:Name="listView"
Grid.Row="1">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:VideoInfo}">
<local:VideoInfo DisplayName="Elephant's Dream"
VideoSource="{StaticResource ElephantsDream}" />

<local:VideoInfo DisplayName="Big Buck Bunny"


VideoSource="{StaticResource BigBuckBunny}" />

<local:VideoInfo DisplayName="Sintel"
VideoSource="{StaticResource Sintel}" />
</x:Array>
</ListView.ItemsSource>
</ListView>
</Grid>
</ContentPage>

The Sourceproperty of the VideoPlayer is bound to the ListView . The Path of the binding is specified as
SelectedItem.VideoSource , which is a compound path consisting of two properties: SelectedItem is a property of
ListView . The selected item is of type VideoInfo , which has a VideoSource property.

As with the first Select Web Video page, no item is initially selected from the ListView , so you need to select
one of the videos before it begins playing.

Related Links
Video Player Demos (sample)
Loading application resource videos
3 minutes to read • Edit Online

Download the sample


The custom renderers for the VideoPlayer view are capable of playing video files that have been embedded in the
individual platform projects as application resources. However, the current version of VideoPlayer cannot access
resources embedded in a .NET Standard library.
To load these resources, create an instance of ResourceVideoSource by setting the Path property to the filename
(or the folder and filename) of the resource. Alternatively, you can call the static VideoSource.FromResource method
to reference the resource. Then, set the ResourceVideoSource object to the Source property of VideoPlayer .

Storing the video files


Storing a video file in the platform project is different for each platform.
iOS video resources
In an iOS project, you can store a video in the Resources folder, or a subfolder of the Resources folder. The video
file must have a Build Action of BundleResource . Set the Path property of ResourceVideoSource to the filename,
for example, MyFile.mp4 for a file in the Resources folder, or MyFolder/MyFile.mp4, where MyFolder is a
subfolder of Resources.
In the VideoPlayerDemos solution, the VideoPlayerDemos.iOS project contains a subfolder of Resources
named Videos containing a file named iOSApiVideo.mp4. This is a short video that shows you how to use the
Xamarin web site to find documentation for the iOS AVPlayerViewController class.
Android video resources
In an Android project, videos must be stored in a subfolder of Resources named raw. The raw folder cannot
contain subfolders. Give the video file a Build Action of AndroidResource . Set the Path property of
ResourceVideoSource to the filename, for example, MyFile.mp4.

The VideoPlayerDemos.Android project contains a subfolder of Resources named raw, which contains a file
named AndroidApiVideo.mp4.
UWP video resources
In a Universal Windows Platform project, you can store videos in any folder in the project. Give the file a
Build Action of Content . Set the Path property of ResourceVideoSource to the folder and filename, for example,
MyFolder/MyVideo.mp4.
The VideoPlayerDemos.UWP project contains a folder named Videos with the file UWPApiVideo.mp4.

Loading the video files


Each of the platform renderer classes contains code in its SetSource method for loading video files stored as
resources.
iOS resource loading
The iOS version of VideoPlayerRenderer uses the GetUrlForResource method of NSBundle for loading the
resource. The complete path must be divided into a filename, extension, and directory. The code uses the Path
class in the .NET System.IO namespace for dividing the file path into these components:
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void SetSource()
{
AVAsset asset = null;
···
else if (Element.Source is ResourceVideoSource)
{
string path = (Element.Source as ResourceVideoSource).Path;

if (!String.IsNullOrWhiteSpace(path))
{
string directory = Path.GetDirectoryName(path);
string filename = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path).Substring(1);
NSUrl url = NSBundle.MainBundle.GetUrlForResource(filename, extension, directory);
asset = AVAsset.FromUrl(url);
}
}
···
}
···
}
}

Android resource loading


The Android VideoPlayerRenderer uses the filename and package name to construct a Uri object. The package
name is the name of the application, in this case VideoPlayerDemos.Android, which can be obtained from the
static Context.PackageName property. The resultant Uri object is then passed to the SetVideoURI method of
VideoView :

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void SetSource()
{
isPrepared = false;
bool hasSetSource = false;
···
else if (Element.Source is ResourceVideoSource)
{
string package = Context.PackageName;
string path = (Element.Source as ResourceVideoSource).Path;

if (!String.IsNullOrWhiteSpace(path))
{
string filename = Path.GetFileNameWithoutExtension(path).ToLowerInvariant();
string uri = "android.resource://" + package + "/raw/" + filename;
videoView.SetVideoURI(Android.Net.Uri.Parse(uri));
hasSetSource = true;
}
}
···
}
···
}
}
UWP resource loading
The UWP VideoPlayerRenderer constructs a Uri object for the path and sets it to the Source property of
MediaElement :

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
async void SetSource()
{
bool hasSetSource = false;
···
else if (Element.Source is ResourceVideoSource)
{
string path = "ms-appx:///" + (Element.Source as ResourceVideoSource).Path;

if (!String.IsNullOrWhiteSpace(path))
{
Control.Source = new Uri(path);
hasSetSource = true;
}
}
}
···
}
}

Playing the resource file


The Play Video Resource page in the VideoPlayerDemos solution uses the OnPlatform class to specify the
video file for each platform:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.PlayVideoResourcePage"
Title="Play Video Resource">
<video:VideoPlayer>
<video:VideoPlayer.Source>
<video:ResourceVideoSource>
<video:ResourceVideoSource.Path>
<OnPlatform x:TypeArguments="x:String">
<On Platform="iOS" Value="Videos/iOSApiVideo.mp4" />
<On Platform="Android" Value="AndroidApiVideo.mp4" />
<On Platform="UWP" Value="Videos/UWPApiVideo.mp4" />
</OnPlatform>
</video:ResourceVideoSource.Path>
</video:ResourceVideoSource>
</video:VideoPlayer.Source>
</video:VideoPlayer>
</ContentPage>

If the iOS resource is stored in the Resources folder, and if the UWP resource is stored in the root folder of the
project, you can use the same filename for each platform. If that is the case, then you can set that name directly to
the Source property of VideoPlayer .
Here's that page running:
You've now seen how to load videos from a Web URI and how to play embedded resources. In addition, you can
load videos from the device's video library.

Related Links
Video Player Demos (sample)
Accessing the device's video library
6 minutes to read • Edit Online

Download the sample


Most modern mobile devices and desktop computers have the ability to record videos using the device's camera.
The videos that a user creates are then stored as files on the device. These files can be retrieved from the image
library and played by the VideoPlayer class just like any other video.

The photo picker dependency service


Each of the platforms includes a facility that allows the user to select a photo or video from the device's image
library. The first step in playing a video from the device's image library is building a dependency service that
invokes the image picker on each platform. The dependency service described below is very similar to one defined
in the Picking a Photo from the Picture Library article, except that the video picker returns a filename rather
than a Stream object.
The .NET Standard library project defines an interface named IVideoPicker for the dependency service:

namespace FormsVideoLibrary
{
public interface IVideoPicker
{
Task<string> GetVideoFileAsync();
}
}

Each of the platforms contains a class named VideoPicker that implements this interface.
The iOS video picker
The iOS VideoPicker uses the iOS UIImagePickerController to access the image library, specifying that it should
be restricted to videos (referred to as "movies") in the iOS MediaType property. Notice that VideoPicker explicitly
implements the IVideoPicker interface. Notice also the Dependency attribute that identifies this class as a
dependency service. These are the two requirements that allow Xamarin.Forms to find the dependency service in
the platform project:
using System;
using System.Threading.Tasks;
using UIKit;
using Xamarin.Forms;

[assembly: Dependency(typeof(FormsVideoLibrary.iOS.VideoPicker))]

namespace FormsVideoLibrary.iOS
{
public class VideoPicker : IVideoPicker
{
TaskCompletionSource<string> taskCompletionSource;
UIImagePickerController imagePicker;

public Task<string> GetVideoFileAsync()


{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum,
MediaTypes = new string[] { "public.movie" }
};

// Set event handlers


imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
imagePicker.Canceled += OnImagePickerCancelled;

// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);

// Return Task object


taskCompletionSource = new TaskCompletionSource<string>();
return taskCompletionSource.Task;
}

void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)


{
if (args.MediaType == "public.movie")
{
taskCompletionSource.SetResult(args.MediaUrl.AbsoluteString);
}
else
{
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}

void OnImagePickerCancelled(object sender, EventArgs args)


{
taskCompletionSource.SetResult(null);
imagePicker.DismissModalViewController(true);
}
}
}

The Android video picker


The Android implementation of IVideoPicker requires a callback method that is part of the application's activity.
For that reason, the MainActivity class defines two properties, a field, and a callback method:
namespace VideoPlayerDemos.Droid
{
···
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
Current = this;
···
}

// Field, properties, and method for Video Picker


public static MainActivity Current { private set; get; }

public static readonly int PickImageId = 1000;

public TaskCompletionSource<string> PickImageTaskCompletionSource { set; get; }

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)


{
base.OnActivityResult(requestCode, resultCode, data);

if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (data != null))
{
// Set the filename as the completion of the Task
PickImageTaskCompletionSource.SetResult(data.DataString);
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}
}

The OnCreate method in MainActivity stores its own instance in the static Current property. This allows the
implementation of IVideoPicker to obtain the MainActivity instance for starting the Select Video chooser:
using System;
using System.Threading.Tasks;
using Android.Content;
using Xamarin.Forms;

// Need application's MainActivity


using VideoPlayerDemos.Droid;

[assembly: Dependency(typeof(FormsVideoLibrary.Droid.VideoPicker))]

namespace FormsVideoLibrary.Droid
{
public class VideoPicker : IVideoPicker
{
public Task<string> GetVideoFileAsync()
{
// Define the Intent for getting images
Intent intent = new Intent();
intent.SetType("video/*");
intent.SetAction(Intent.ActionGetContent);

// Get the MainActivity instance


MainActivity activity = MainActivity.Current;

// Start the picture-picker activity (resumes in MainActivity.cs)


activity.StartActivityForResult(
Intent.CreateChooser(intent, "Select Video"),
MainActivity.PickImageId);

// Save the TaskCompletionSource object as a MainActivity property


activity.PickImageTaskCompletionSource = new TaskCompletionSource<string>();

// Return Task object


return activity.PickImageTaskCompletionSource.Task;
}
}
}

The additions to the MainActivity object are the only code in the VideoPlayerDemos solution where normal
application code needs to be altered to support the FormsVideoLibrary classes.
The UWP video picker
The UWP implementation of the IVideoPicker interface uses the UWP FileOpenPicker . It begins the file search
with the pictures library, and restricts the file types to MP4 and WMV (Windows Media Video):
using System;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Pickers;
using Xamarin.Forms;

[assembly: Dependency(typeof(FormsVideoLibrary.UWP.VideoPicker))]

namespace FormsVideoLibrary.UWP
{
public class VideoPicker : IVideoPicker
{
public async Task<string> GetVideoFileAsync()
{
// Create and initialize the FileOpenPicker
FileOpenPicker openPicker = new FileOpenPicker
{
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.PicturesLibrary
};

openPicker.FileTypeFilter.Add(".wmv");
openPicker.FileTypeFilter.Add(".mp4");

// Get a file and return the path


StorageFile storageFile = await openPicker.PickSingleFileAsync();
return storageFile?.Path;
}
}
}

Invoking the dependency service


The Play Library Video page of the VideoPlayerDemos program demonstrates how to use the video picker
dependency service. The XAML file contains a VideoPlayer instance and a Button labeled Show Video Library:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.PlayLibraryVideoPage"
Title="Play Library Video">
<StackLayout>
<video:VideoPlayer x:Name="videoPlayer"
VerticalOptions="FillAndExpand" />

<Button Text="Show Video Library"


Margin="10"
HorizontalOptions="Center"
Clicked="OnShowVideoLibraryClicked" />
</StackLayout>
</ContentPage>

The code-behind file contains the Clicked handler for the Button . Invoking the dependency service requires a
call to DependencyService.Get to obtain the implementation of an IVideoPicker interface in the platform project.
The GetVideoFileAsync method is then called on that instance:
namespace VideoPlayerDemos
{
public partial class PlayLibraryVideoPage : ContentPage
{
public PlayLibraryVideoPage()
{
InitializeComponent();
}

async void OnShowVideoLibraryClicked(object sender, EventArgs args)


{
Button btn = (Button)sender;
btn.IsEnabled = false;

string filename = await DependencyService.Get<IVideoPicker>().GetVideoFileAsync();

if (!String.IsNullOrWhiteSpace(filename))
{
videoPlayer.Source = new FileVideoSource
{
File = filename
};
}

btn.IsEnabled = true;
}
}
}

The Clicked handler then uses that filename to create a FileVideoSource object and to set it to the Source
property of the VideoPlayer .
Each of the classes contains code in its
VideoPlayerRenderer SetSource method for objects of type
FileVideoSource . These are shown below:

Handling iOS files


The iOS version of VideoPlayerRenderer processes FileVideoSource objects by using the static Asset.FromUrl
method with the filename. This create an AVAsset object representing the file in the device's image library:

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void SetSource()
{
AVAsset asset = null;
···
else if (Element.Source is FileVideoSource)
{
string uri = (Element.Source as FileVideoSource).File;

if (!String.IsNullOrWhiteSpace(uri))
{
asset = AVAsset.FromUrl(new NSUrl(uri));
}
}
···
}
···
}
}
Handling Android files
When processing objects of type FileVideoSource , the Android implementation of VideoPlayerRenderer uses the
SetVideoPath method of VideoView to specify the file in the device's image library:

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void SetSource()
{
isPrepared = false;
bool hasSetSource = false;
···
else if (Element.Source is FileVideoSource)
{
string filename = (Element.Source as FileVideoSource).File;

if (!String.IsNullOrWhiteSpace(filename))
{
videoView.SetVideoPath(filename);
hasSetSource = true;
}
}
···
}
···
}
}

Handling UWP files


When handling objects of type FileVideoSource , the UWP implementation of the SetSource method needs to
create a StorageFile object, open that file for reading, and pass the stream object to the SetSource method of the
MediaElement :
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
async void SetSource()
{
bool hasSetSource = false;
···
else if (Element.Source is FileVideoSource)
{
// Code requires Pictures Library in Package.appxmanifest Capabilities to be enabled
string filename = (Element.Source as FileVideoSource).File;

if (!String.IsNullOrWhiteSpace(filename))
{
StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filename);
IRandomAccessStreamWithContentType stream = await storageFile.OpenReadAsync();
Control.SetSource(stream, storageFile.ContentType);
hasSetSource = true;
}
}
···
}
···
}
}

For each platform, the video begins playing almost immediately after the video source is set because the file is on
the device and doesn't need to be downloaded.

Related Links
Video Player Demos (sample)
Picking a Photo from the Picture Library
Custom video transport controls
10 minutes to read • Edit Online

Download the sample


The transport controls of a video player include the buttons that perform the functions Play, Pause, and Stop.
These buttons are generally identified with familiar icons rather than text, and the Play and Pause functions are
generally combined into one button.
By default, the displays transport controls supported by each platform. When you set the
VideoPlayer
AreTransportControlsEnabled property to false , these controls are suppressed. You can then control the
VideoPlayer programmatically or supply your own transport controls.

The Play, Pause, and Stop methods


The VideoPlayer class defines three methods named Play , Pause , and Stop that are implemented by firing
events:

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
public event EventHandler PlayRequested;

public void Play()


{
PlayRequested?.Invoke(this, EventArgs.Empty);
}

public event EventHandler PauseRequested;

public void Pause()


{
PauseRequested?.Invoke(this, EventArgs.Empty);
}

public event EventHandler StopRequested;

public void Stop()


{
StopRequested?.Invoke(this, EventArgs.Empty);
}
}
}

Event handlers for these events are set by the VideoPlayerRenderer class in each platform, as shown below:
iOS transport implementations
The iOS version of VideoPlayerRenderer uses the OnElementChanged method to set handlers for these three events
when the NewElement property is not null and detaches the event handlers when OldElement is not null :
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
AVPlayer player;
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
args.NewElement.PlayRequested += OnPlayRequested;
args.NewElement.PauseRequested += OnPauseRequested;
args.NewElement.StopRequested += OnStopRequested;
}

if (args.OldElement != null)
{
···
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
···
// Event handlers to implement methods
void OnPlayRequested(object sender, EventArgs args)
{
player.Play();
}

void OnPauseRequested(object sender, EventArgs args)


{
player.Pause();
}

void OnStopRequested(object sender, EventArgs args)


{
player.Pause();
player.Seek(new CMTime(0, 1));
}
}
}

The event handlers are implemented by calling methods on the AVPlayer object. There is no Stop method for
AVPlayer , so it's simulated by pausing the video and moving the position to the beginning.

Android transport implementations


The Android implementation is similar to the iOS implementation. The handlers for the three functions are set
when NewElement is not null and detached when OldElement is not null :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
args.NewElement.PlayRequested += OnPlayRequested;
args.NewElement.PauseRequested += OnPauseRequested;
args.NewElement.StopRequested += OnStopRequested;
}

if (args.OldElement != null)
{
···
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
···
void OnPlayRequested(object sender, EventArgs args)
{
videoView.Start();
}

void OnPauseRequested(object sender, EventArgs args)


{
videoView.Pause();
}

void OnStopRequested(object sender, EventArgs args)


{
videoView.StopPlayback();
}
}
}

The three functions call methods defined by VideoView .


UWP transport implementations
The UWP implementation of the three transport functions is very similar to both the iOS and Android
implementations:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
args.NewElement.PlayRequested += OnPlayRequested;
args.NewElement.PauseRequested += OnPauseRequested;
args.NewElement.StopRequested += OnStopRequested;
}

if (args.OldElement != null)
{
···
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
···
// Event handlers to implement methods
void OnPlayRequested(object sender, EventArgs args)
{
Control.Play();
}

void OnPauseRequested(object sender, EventArgs args)


{
Control.Pause();
}

void OnStopRequested(object sender, EventArgs args)


{
Control.Stop();
}
}
}

The video player status


Implementing the Play, Pause, and Stop functions is not sufficient for supporting transport controls. Often the
Play and Pause commands are implemented with the same button that changes its appearance to indicate
whether the video is currently playing or paused. Moreover, the button shouldn't even be enabled if the video has
not yet loaded.
These requirements imply that the video player needs to make available a current status indicating if it's playing or
paused, or if it's not yet ready to play a video. (Each platform also supports properties that indicate if the video can
be paused, or can be moved to a new position, but these properties are applicable for streaming video rather than
video files, so they are not supported in the VideoPlayer described here.)
The VideoPlayerDemos project includes a VideoStatus enumeration with three members:
namespace FormsVideoLibrary
{
public enum VideoStatus
{
NotReady,
Playing,
Paused
}
}

The VideoPlayer class defines a real-only bindable property named Status of type VideoStatus . This property is
defined as read-only because it should only be set from the platform renderer:

using System;
using Xamarin.Forms;

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// Status read-only property
private static readonly BindablePropertyKey StatusPropertyKey =
BindableProperty.CreateReadOnly(nameof(Status), typeof(VideoStatus), typeof(VideoPlayer),
VideoStatus.NotReady);

public static readonly BindableProperty StatusProperty = StatusPropertyKey.BindableProperty;

public VideoStatus Status


{
get { return (VideoStatus)GetValue(StatusProperty); }
}

VideoStatus IVideoPlayerController.Status
{
set { SetValue(StatusPropertyKey, value); }
get { return Status; }
}
···
}
}

Usually, a read-only bindable property would have a private set accessor on the Status property to allow it to
be set from within the class. For a View derivative supported by renderers, however, the property must be set
from outside the class, but only by the platform renderer.
For this reason, another property is defined with the name IVideoPlayerController.Status . This is an explicit
interface implementation, and is made possible by the IVideoPlayerController interface that the VideoPlayer
class implements:

namespace FormsVideoLibrary
{
public interface IVideoPlayerController
{
VideoStatus Status { set; get; }

TimeSpan Duration { set; get; }


}
}

This is similar to how the WebView control uses the IWebViewController interface to implement the CanGoBack and
CanGoForward properties. (See the source code of WebView and its renderers for details.)
This makes it possible for a class external to VideoPlayer to set the Status property by referencing the
IVideoPlayerController interface. ( You'll see the code shortly.) The property can be set from other classes as well,
but it's unlikely to be set inadvertently. Most importantly, the Status property cannot be set through a data
binding.
To assist the renderers in keeping this Status property updated, the VideoPlayer class defines an UpdateStatus
event that is triggered every tenth of a second:

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
public event EventHandler UpdateStatus;

public VideoPlayer()
{
Device.StartTimer(TimeSpan.FromMilliseconds(100), () =>
{
UpdateStatus?.Invoke(this, EventArgs.Empty);
return true;
});
}
···
}
}

The iOS status setting


The iOS VideoPlayerRenderer sets a handler for the UpdateStatus event (and detaches that handler when the
underlying VideoPlayer element is absent), and uses the handler to set the Status property:
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
args.NewElement.UpdateStatus += OnUpdateStatus;
···
}

if (args.OldElement != null)
{
args.OldElement.UpdateStatus -= OnUpdateStatus;
···
}
}
···
void OnUpdateStatus(object sender, EventArgs args)
{
VideoStatus videoStatus = VideoStatus.NotReady;

switch (player.Status)
{
case AVPlayerStatus.ReadyToPlay:
switch (player.TimeControlStatus)
{
case AVPlayerTimeControlStatus.Playing:
videoStatus = VideoStatus.Playing;
break;

case AVPlayerTimeControlStatus.Paused:
videoStatus = VideoStatus.Paused;
break;
}
break;
}
}

((IVideoPlayerController)Element).Status = videoStatus;
···
}
···
}
}

Two properties of AVPlayermust be accessed: The Status property of type AVPlayerStatus and the
TimeControlStatus property of type AVPlayerTimeControlStatus . Notice that the Element property (which is the
VideoPlayer ) must be cast to IVideoPlayerController to set the Status property.

The Android status setting


The IsPlaying property of the Android VideoView is a Boolean that only indicates if the video is playing or
paused. To determine if the VideoView can neither play nor pause the video yet, the Prepared event of VideoView
must be handled. These two handlers are set in the OnElementChanged method, and detached during the Dispose
override:
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
···
bool isPrepared;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)


{
···
if (args.NewElement != null)
{
if (Control == null)
{
···
videoView.Prepared += OnVideoViewPrepared;
···
}
···
args.NewElement.UpdateStatus += OnUpdateStatus;
···
}

if (args.OldElement != null)
{
args.OldElement.UpdateStatus -= OnUpdateStatus;
···
}

protected override void Dispose(bool disposing)


{
if (Control != null && videoView != null)
{
videoView.Prepared -= OnVideoViewPrepared;
}
if (Element != null)
{
Element.UpdateStatus -= OnUpdateStatus;
}

base.Dispose(disposing);
}
···
}
}

The UpdateStatus handler uses the isPrepared field (set in the Prepared handler) and the IsPlaying property to
set the Status property:
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
···
bool isPrepared;
···
void OnVideoViewPrepared(object sender, EventArgs args)
{
isPrepared = true;
···
}
···
void OnUpdateStatus(object sender, EventArgs args)
{
VideoStatus status = VideoStatus.NotReady;

if (isPrepared)
{
status = videoView.IsPlaying ? VideoStatus.Playing : VideoStatus.Paused;
}
···
}
···
}
}

The UWP status setting


The UWP VideoPlayerRenderer makes use of the UpdateStatus event, but it does not need it for setting the
Status property. The MediaElement defines a CurrentStateChanged event that allows the renderer to be notified
when the CurrentState property has changed. The property is detached in the Dispose override:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
base.OnElementChanged(args);

if (args.NewElement != null)
{
if (Control == null)
{
···
mediaElement.CurrentStateChanged += OnMediaElementCurrentStateChanged;
};
···
}
···
}

protected override void Dispose(bool disposing)


{
if (Control != null)
{
···
Control.CurrentStateChanged -= OnMediaElementCurrentStateChanged;
}

base.Dispose(disposing);
}
···
}
}

The CurrentState property is of type MediaElementState , and maps easily into VideoStatus :

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
void OnMediaElementCurrentStateChanged(object sender, RoutedEventArgs args)
{
VideoStatus videoStatus = VideoStatus.NotReady;

switch (Control.CurrentState)
{
case MediaElementState.Playing:
videoStatus = VideoStatus.Playing;
break;

case MediaElementState.Paused:
case MediaElementState.Stopped:
videoStatus = VideoStatus.Paused;
break;
}

((IVideoPlayerController)Element).Status = videoStatus;
}
···
}
}
Play, Pause, and Stop Buttons
Using Unicode characters for symbolic Play, Pause, and Stop images is problematic. The Miscellaneous Technical
section of the Unicode standard defines three symbol characters seemingly appropriate for this purpose. These
are:
0x23F5 (black medium right-pointing triangle) or for Play
0x23F8 (double vertical bar) or for Pause
0x23F9 (black square) or for Stop
Regardless how these symbols appear in your browser (and different browsers handle them in different ways),
they are not displayed consistently on the platforms supported by Xamarin.Forms. On iOS and UWP devices, the
Pause and Stop characters have a graphical appearance, with a blue 3D background and a white foreground. This
isn't the case on Android, where the symbol is simply blue. However, the 0x23F5 codepoint for Play does not have
that same appearance on the UWP, and it's not even supported on iOS and Android.
For that reason, the 0x23F5 codepoint can't be used for Play. A good substitute is:
0x25B6 (black right-pointing triangle) or ▶ for Play
This is supported by each platform except that it's a plain black triangle that does not resemble the 3D appearance
of Pause and Stop. One possibility is to follow the 0x25B6 codepoint with a variant code:
0x25B6 followed by 0xFE0F (variant 16) or ▶ for Play
This is what's used in the markup shown below. On iOS, it gives the Play symbol the same 3D appearance as the
Pause and Stop buttons, but the variant doesn't work on Android and the UWP.
The Custom Transport page sets the AreTransportControlsEnabled property to false and includes an
ActivityIndicator displayed when the video is loading, and two buttons. DataTrigger objects are used to enable
and disable the ActivityIndicator and the buttons, and to switch the first button between Play and Pause:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.CustomTransportPage"
Title="Custom Transport">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<video:VideoPlayer x:Name="videoPlayer"
Grid.Row="0"
AutoPlay="False"
AreTransportControlsEnabled="False"
Source="{StaticResource BigBuckBunny}" />

<ActivityIndicator Grid.Row="0"
Color="Gray"
IsVisible="False">
<ActivityIndicator.Triggers>
<DataTrigger TargetType="ActivityIndicator"
Binding="{Binding Source={x:Reference videoPlayer},
Path=Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsVisible" Value="True" />
<Setter Property="IsRunning" Value="True" />
</DataTrigger>
</ActivityIndicator.Triggers>
</ActivityIndicator>
<StackLayout Grid.Row="1"
Orientation="Horizontal"
Margin="0, 10"
BindingContext="{x:Reference videoPlayer}">

<Button Text="&#x25B6;&#xFE0F; Play"


HorizontalOptions="CenterAndExpand"
Clicked="OnPlayPauseButtonClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.Playing}">
<Setter Property="Text" Value="&#x23F8; Pause" />
</DataTrigger>

<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>

<Button Text="&#x23F9; Stop"


HorizontalOptions="CenterAndExpand"
Clicked="OnStopButtonClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
</StackLayout>
</Grid>
</ContentPage>

Data triggers are described in detail in the article Data Triggers.


The code-behind file has the handlers for the button Clicked events:
namespace VideoPlayerDemos
{
public partial class CustomTransportPage : ContentPage
{
public CustomTransportPage()
{
InitializeComponent();
}

void OnPlayPauseButtonClicked(object sender, EventArgs args)


{
if (videoPlayer.Status == VideoStatus.Playing)
{
videoPlayer.Pause();
}
else if (videoPlayer.Status == VideoStatus.Paused)
{
videoPlayer.Play();
}
}

void OnStopButtonClicked(object sender, EventArgs args)


{
videoPlayer.Stop();
}
}
}

Because AutoPlay is set to false in the CustomTransport.xaml file, you'll need to press the Play button when it
becomes enabled to begin the video. The buttons are defined so that the Unicode characters discussed above are
accompanied by their text equivalents. The buttons have a consistent appearance on each platform when the video
is playing:

But on Android and UWP, the Play button looks very different when the video is paused:
In a production application, you'll probably want to use your own bitmap images for the buttons to achieve visual
uniformity.

Related Links
Video Player Demos (sample)
Custom video positioning
10 minutes to read • Edit Online

Download the sample


The transport controls implemented by each platform include a position bar. This bar resembles a slider or scroll
bar and shows the current location of the video within its total duration. In addition, the user can manipulate the
position bar to move forwards or backwards to a new position in the video.
This article shows how you can implement your own custom position bar.

The Duration property


One item of information that VideoPlayer needs to support a custom position bar is the duration of the video. The
VideoPlayer defines a read-only Duration property of type TimeSpan :

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// Duration read-only property
private static readonly BindablePropertyKey DurationPropertyKey =
BindableProperty.CreateReadOnly(nameof(Duration), typeof(TimeSpan), typeof(VideoPlayer), new
TimeSpan(),
propertyChanged: (bindable, oldValue, newValue) => ((VideoPlayer)bindable).SetTimeToEnd());

public static readonly BindableProperty DurationProperty = DurationPropertyKey.BindableProperty;

public TimeSpan Duration


{
get { return (TimeSpan)GetValue(DurationProperty); }
}

TimeSpan IVideoPlayerController.Duration
{
set { SetValue(DurationPropertyKey, value); }
get { return Duration; }
}
···
}
}

Like the Status property described in the previous article, this Duration property is read-only. It's defined with a
private BindablePropertyKey and can only be set by referencing the IVideoPlayerController interface, which
includes this Duration property:

namespace FormsVideoLibrary
{
public interface IVideoPlayerController
{
VideoStatus Status { set; get; }

TimeSpan Duration { set; get; }


}
}
Also notice the property-changed handler that calls a method named SetTimeToEnd that is described later in this
article.
The duration of a video is not available immediately after the Source property of VideoPlayer is set. The video file
must be partially downloaded before the underlying video player can determine its duration.
Here's how each of the platform renderers obtains the video's duration:
Video duration in iOS
In iOS, the duration of a video is obtained from the Duration property of AVPlayerItem , but not immediately after
the AVPlayerItem is created. It's possible to set an iOS observer for the Duration property, but the
VideoPlayerRenderer obtains the duration in the UpdateStatus method, which is called 10 times a second:

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void OnUpdateStatus(object sender, EventArgs args)
{
···
if (playerItem != null)
{
((IVideoPlayerController)Element).Duration = ConvertTime(playerItem.Duration);
···
}
}

TimeSpan ConvertTime(CMTime cmTime)


{
return TimeSpan.FromSeconds(Double.IsNaN(cmTime.Seconds) ? 0 : cmTime.Seconds);

}
···
}
}

The ConvertTime method converts a CMTime object to a TimeSpan value.


Video duration in Android
The Duration property of the Android VideoView reports a valid duration in milliseconds when the Prepared
event of VideoView is fired. The Android VideoPlayerRenderer class uses that handler to obtain the Duration
property:

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void OnVideoViewPrepared(object sender, EventArgs args)
{
···
((IVideoPlayerController)Element).Duration = TimeSpan.FromMilliseconds(videoView.Duration);
}
···
}
}

Video duration in UWP


The NaturalDuration property of MediaElement is a TimeSpan value and becomes valid when MediaElement fires
the MediaOpened event:

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
void OnMediaElementMediaOpened(object sender, RoutedEventArgs args)
{
((IVideoPlayerController)Element).Duration = Control.NaturalDuration.TimeSpan;
}
···
}
}

The Position property


VideoPlayer also needs a Position property that increases from zero to Duration as the video is playing.
VideoPlayer implements this property like the Position property in the UWP MediaElement , which is a normal
bindable property with public set and get accessors:

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// Position property
public static readonly BindableProperty PositionProperty =
BindableProperty.Create(nameof(Position), typeof(TimeSpan), typeof(VideoPlayer), new TimeSpan(),
propertyChanged: (bindable, oldValue, newValue) => ((VideoPlayer)bindable).SetTimeToEnd());

public TimeSpan Position


{
set { SetValue(PositionProperty, value); }
get { return (TimeSpan)GetValue(PositionProperty); }
}
···
}
}

The get accessor returns the current position of the video as it is playing, but the set accessor is intended to
respond to the user's manipulation of the position bar by moving the video position forwards or backwards.
In iOS and Android, the property that obtains the current position has only a get accessor, and a Seek method is
available to perform this second task. If you think about it, a separate Seek method seems to be a more sensible
approach than a single Position property. A single Position property has an inherent problem: As the video
plays, the Position property must be continually updated to reflect the new position. But you don't want most
changes to the Position property to cause the video player to move to a new position in the video. If that
happens, the video player would respond by seeking to the last value of the Position property, and the video
wouldn't advance.
Despite the difficulties of implementing a Position property with set and get accessors, this approach was
chosen because it is consistent with the UWP MediaElement , and it has a big advantage with data binding: The
Position property of the VideoPlayer can be bound to the slider that is used both to display the position and to
seek to a new position. However, several precautions are necessary when implementing this Position property to
avoid feedback loops.
Setting and getting iOS position
In iOS, the CurrentTime property of the AVPlayerItem object indicates the current position of the playing video.
The iOS VideoPlayerRenderer sets the Position property in the UpdateStatus handler at the same time that it sets
the Duration property:

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void OnUpdateStatus(object sender, EventArgs args)
{
···
if (playerItem != null)
{
···
((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty,
ConvertTime(playerItem.CurrentTime));
}
}
···
}
}

The renderer detects when the Position property set from VideoPlayer has changed in the
OnElementPropertyChanged override, and uses that new value to call a Seek method on the AVPlayer object:

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
···
else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
{
TimeSpan controlPosition = ConvertTime(player.CurrentTime);

if (Math.Abs((controlPosition - Element.Position).TotalSeconds) > 1)


{
player.Seek(CMTime.FromSeconds(Element.Position.TotalSeconds, 1));
}
}
}
···
}
}

Keep in mind that every time the Position property in VideoPlayer is set from the OnUpdateStatus handler, the
Position property fires a PropertyChanged event, which is detected in the OnElementPropertyChanged override. For
most of these changes, the OnElementPropertyChanged method should do nothing. Otherwise, with every change in
the video's position, it would be moved to the same position it just reached!
To avoid this feedback loop, the OnElementPropertyChanged method only calls Seek when the difference between
the Position property and the current position of the AVPlayer is greater than one second.
Setting and getting Android position
Just as in the iOS renderer, the Android VideoPlayerRenderer sets a new value for the Position property in the
OnUpdateStatus handler. The CurrentPosition property of VideoView contains the new position in units of
milliseconds:
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void OnUpdateStatus(object sender, EventArgs args)
{
···
TimeSpan timeSpan = TimeSpan.FromMilliseconds(videoView.CurrentPosition);
((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty, timeSpan);
}
···
}
}

Also, just as in the iOS renderer, the Android renderer calls the SeekTo method of VideoView when the Position
property has changed, but only when the change is more than one second different from the CurrentPosition
value of VideoView :

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
···
else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
{
if (Math.Abs(videoView.CurrentPosition - Element.Position.TotalMilliseconds) > 1000)
{
videoView.SeekTo((int)Element.Position.TotalMilliseconds);
}
}
}
···
}
}

Setting and getting UWP position


The UWP VideoPlayerRenderer handles the Position in the same way as the iOS and Android renderers, but
because the Position property of the UWP MediaElement is also a TimeSpan value, no conversion is necessary:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
···
else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
{
if (Math.Abs((Control.Position - Element.Position).TotalSeconds) > 1)
{
Control.Position = Element.Position;
}
}
}
···
void OnUpdateStatus(object sender, EventArgs args)
{
((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty,
Control.Position);
}
···
}
}

Calculating a TimeToEnd property


Sometimes video players show the time remaining in the video. This value begins at the video's duration when the
video begins and decreases down to zero when the video ends.
VideoPlayer includes a read-only TimeToEnd property that is handled entirely within the class based on changes to
the Duration and Position properties:

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
private static readonly BindablePropertyKey TimeToEndPropertyKey =
BindableProperty.CreateReadOnly(nameof(TimeToEnd), typeof(TimeSpan), typeof(VideoPlayer), new
TimeSpan());

public static readonly BindableProperty TimeToEndProperty = TimeToEndPropertyKey.BindableProperty;

public TimeSpan TimeToEnd


{
private set { SetValue(TimeToEndPropertyKey, value); }
get { return (TimeSpan)GetValue(TimeToEndProperty); }
}

void SetTimeToEnd()
{
TimeToEnd = Duration - Position;
}
···
}
}

The SetTimeToEnd method is called from the property-changed handlers of both Duration and Position .
A custom slider for video
It's possible to write a custom control for a position bar, or to use the Xamarin.Forms Slider or a class that
derives from Slider , such as the following PositionSlider class. The class defines two new properties named
Duration and Position of type TimeSpan that are intended to be data-bound to the two properties of the same
name in VideoPlayer . Notice that the default binding mode of the Position property is two-way:

namespace FormsVideoLibrary
{
public class PositionSlider : Slider
{
public static readonly BindableProperty DurationProperty =
BindableProperty.Create(nameof(Duration), typeof(TimeSpan), typeof(PositionSlider), new
TimeSpan(1),
propertyChanged: (bindable, oldValue, newValue) =>
{
double seconds = ((TimeSpan)newValue).TotalSeconds;
((PositionSlider)bindable).Maximum = seconds <= 0 ? 1 : seconds;
});

public TimeSpan Duration


{
set { SetValue(DurationProperty, value); }
get { return (TimeSpan)GetValue(DurationProperty); }
}

public static readonly BindableProperty PositionProperty =


BindableProperty.Create(nameof(Position), typeof(TimeSpan), typeof(PositionSlider), new
TimeSpan(0),
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
double seconds = ((TimeSpan)newValue).TotalSeconds;
((PositionSlider)bindable).Value = seconds;
});

public TimeSpan Position


{
set { SetValue(PositionProperty, value); }
get { return (TimeSpan)GetValue(PositionProperty); }
}

public PositionSlider()
{
PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "Value")
{
TimeSpan newPosition = TimeSpan.FromSeconds(Value);

if (Math.Abs(newPosition.TotalSeconds - Position.TotalSeconds) / Duration.TotalSeconds >


0.01)
{
Position = newPosition;
}
}
};
}
}
}

The property-changed handler for the Duration property sets the Maximum property of the underlying Slider to
the TotalSeconds property of the TimeSpan value. Similarly, the property-changed handler for Position sets the
Value property of the Slider . In this way, the underlying Slider tracks the position of the PositionSlider .
The PositionSlider is updated from the underlying Slider in only one instance: When the user manipulates the
Slider to indicate that the video should be advanced or reversed to a new position. This is detected in the
PropertyChanged handler in the constructor of the PositionSlider . The handler checks for a change in the Value
property, and if it's different from the Position property, then the Position property is set from the Value
property.
In theory, the inner if statement could be written like this:

if (newPosition.Seconds != Position.Seconds)
{
Position = newPosition;
}

However, the Android implementation of Slider has only 1,000 discrete steps regardless of the Minimum and
Maximum settings. It the length of a video is greater than 1,000 seconds, then two different Position values would
correspond to the same Value setting of the Slider , and this if statement would trigger a false positive for a
user manipulation of the Slider . It's safer to instead check that the new position and existing position are greater
than one-hundredth of the overall duration.

Using the PositionSlider


Documentation for the UWP MediaElement warns about binding to the Position property because the property
frequently updates. The documentation recommends that a timer be used to query the Position property.
That's a good recommendation, but the three VideoPlayerRenderer classes are already indirectly using a timer to
update the Position property. The Position property is changed in a handler for the UpdateStatus event, which
is fired only 10 times a second.
Therefore, the Position property of the VideoPlayer can be bound to the Position property of the
PositionSlider without performance issues, as demonstrated in the Custom Position Bar page:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.CustomPositionBarPage"
Title="Custom Position Bar">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<video:VideoPlayer x:Name="videoPlayer"
Grid.Row="0"
AreTransportControlsEnabled="False"
Source="{StaticResource ElephantsDream}" />

···

<StackLayout Grid.Row="1"
Orientation="Horizontal"
Margin="10, 0"
BindingContext="{x:Reference videoPlayer}">

<Label Text="{Binding Path=Position,


StringFormat='{0:hh\\:mm\\:ss}'}"
VerticalOptions="Center"/>

···

<Label Text="{Binding Path=TimeToEnd,


StringFormat='{0:hh\\:mm\\:ss}'}"
VerticalOptions="Center" />
</StackLayout>

<video:PositionSlider Grid.Row="2"
Margin="10, 0, 10, 10"
BindingContext="{x:Reference videoPlayer}"
Duration="{Binding Duration}"
Position="{Binding Position}">
<video:PositionSlider.Triggers>
<DataTrigger TargetType="video:PositionSlider"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</video:PositionSlider.Triggers>
</video:PositionSlider>
</Grid>
</ContentPage>

The first ellipsis (···) hides the ActivityIndicator ; it's the same as in the previous Custom Transport page. Notice
the two Label elements displaying the Position and TimeToEnd properties. The ellipsis between those two
Label elements hides the two Button elements shown in the Custom Transport page for Play, Pause, and Stop.
The code-behind logic is also the same as the Custom Transport page.
This concludes the discussion of the VideoPlayer .

Related Links
Video Player Demos (sample)
Xamarin.Forms Data Binding
2 minutes to read • Edit Online

Download the sample


Data binding is the technique of linking properties of two objects so that changes in one property are
automatically reflected in the other property. Data binding is an integral part of the Model-View -ViewModel
(MVVM ) application architecture.

The Data Linking Problem


A Xamarin.Forms application consists of one or more pages, each of which generally contains multiple user-
interface objects called views. One of the primary tasks of the program is to keep these views synchronized, and
to keep track of the various values or selections that they represent. Often the views represent values from an
underlying data source, and the user manipulates these views to change that data. When the view changes, the
underlying data must reflect that change, and similarly, when the underlying data changes, that change must be
reflected in the view.
To handle this job successfully, the program must be notified of changes in these views or the underlying data.
The common solution is to define events that signal when a change occurs. An event handler can then be
installed that is notified of these changes. It responds by transferring data from one object to another. However,
when there are many views, there must also be many event handlers, and a lot of code gets involved.

The Data Binding Solution


Data binding automates this job, and renders the event handlers unnecessary. (The events are still necessary,
however, because the data-binding infrastructure uses them.) Data bindings can be implemented either in code
or in XAML, but they are much more common in XAML where they help to reduce the size of the code-behind
file. By replacing procedural code in event handlers with declarative code or markup, the application is
simplified and clarified.
One of the two objects involved in a data binding is almost always an element that derives from View and
forms part of the visual interface of a page. The other object is either:
Another View derivative, usually on the same page.
An object in a code file.
In demonstration programs such as those in the DataBindingDemos sample, data bindings between two
View derivatives are often shown for purposes of clarity and simplicity. However, the same principles can be
applied to data bindings between a View and other objects. When an application is built using the Model-View -
ViewModel (MVVM ) architecture, the class with underlying data is often called a viewmodel.
Data bindings are explored in the following series of articles:

Basic Bindings
Learn the difference between the data binding target and source, and see simple data bindings in code and
XAML.

Binding Mode
Discover how the binding mode can control the flow of data between the two objects.

String Formatting
Use a data binding to format and display objects as strings.

Binding Path
Dive deeper into the Path property of the data binding to access sub-properties and collection members.

Binding Value Converters


Use binding value converters to alter values within the data binding.

Relative Bindings
Use relative bindings to set the binding source relative to the position of the binding target.

Binding Fallbacks
Make data bindings more robust by defining fallback values to use if the binding process fails.

The Command Interface


Implement the Command property with data bindings.

Compiled Bindings
Use compiled bindings to improve data binding performance.

Related links
Data Binding Demos (sample)
Data binding chapter from Xamarin.Forms book
XAML Markup Extensions
Xamarin.Forms Basic Bindings
9 minutes to read • Edit Online

Download the sample


A Xamarin.Forms data binding links a pair of properties between two objects, at least one of which is usually a
user-interface object. These two objects are called the target and the source:
The target is the object (and property) on which the data binding is set.
The source is the object (and property) referenced by the data binding.
This distinction can sometimes be a little confusing: In the simplest case, data flows from the source to the target,
which means that the value of the target property is set from the value of the source property. However, in some
cases, data can alternatively flow from the target to the source, or in both directions. To avoid confusion, keep in
mind that the target is always the object on which the data binding is set even if it's providing data rather than
receiving data.

Bindings with a Binding Context


Although data bindings are usually specified entirely in XAML, it's instructive to see data bindings in code. The
Basic Code Binding page contains a XAML file with a Label and a Slider :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicCodeBindingPage"
Title="Basic Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="48"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

The Slider is set for a range of 0 to 360. The intent of this program is to rotate the Label by manipulating the
Slider .
Without data bindings, you would set the ValueChanged event of the Slider to an event handler that accesses the
Value property of the Slider and sets that value to the Rotation property of the Label . The data binding
automates that job; the event handler and the code within it are no longer necessary.
You can set a binding on an instance of any class that derives from BindableObject , which includes Element ,
VisualElement , View , and View derivatives. The binding is always set on the target object. The binding references
the source object. To set the data binding, use the following two members of the target class:
The BindingContext property specifies the source object.
The SetBinding method specifies the target property and source property.
In this example, the Label is the binding target, and the Slider is the binding source. Changes in the Slider
source affect the rotation of the Label target. Data flows from the source to the target.
The SetBindingmethod defined by BindableObject has an argument of type BindingBase from which the
Binding class derives, but there are other SetBinding methods defined by the BindableObjectExtensions class.
The code-behind file in the Basic Code Binding sample uses a simpler SetBinding extension method from this
class.

public partial class BasicCodeBindingPage : ContentPage


{
public BasicCodeBindingPage()
{
InitializeComponent();

label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
}
}

The Label object is the binding target so that's the object on which this property is set and on which the method
is called. The BindingContext property indicates the binding source, which is the Slider .
The SetBinding method is called on the binding target but specifies both the target property and the source
property. The target property is specified as a BindableProperty object: Label.RotationProperty . The source
property is specified as a string and indicates the Value property of Slider .
The SetBinding method reveals one of the most important rules of data bindings:
The target property must be backed by a bindable property.
This rule implies that the target object must be an instance of a class that derives from BindableObject . See the
Bindable Properties article for an overview of bindable objects and bindable properties.
There is no such rule for the source property, which is specified as a string. Internally, reflection is used to access
the actual property. In this particular case, however, the Value property is also backed by a bindable property.
The code can be simplified somewhat: The RotationProperty bindable property is defined by VisualElement , and
inherited by Label and ContentPage as well, so the class name isn't required in the SetBinding call:

label.SetBinding(RotationProperty, "Value");

However, including the class name is a good reminder of the target object.
As you manipulate the Slider , the Label rotates accordingly:
The Basic Xaml Binding page is identical to Basic Code Binding except that it defines the entire data binding in
XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicXamlBindingPage"
Title="Basic XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}" />

<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

Just as in code, the data binding is set on the target object, which is the Label . Two XAML markup extensions are
involved. These are instantly recognizable by the curly brace delimiters:
The x:Reference markup extension is required to reference the source object, which is the Slider named
slider .
The Binding markup extension links the Rotation property of the Label to the Value property of the
Slider .

See the article XAML Markup Extensions for more information about XAML markup extensions. The x:Reference
markup extension is supported by the ReferenceExtension class; Binding is supported by the BindingExtension
class. As the XML namespace prefixes indicate, x:Reference is part of the XAML 2009 specification, while
Binding is part of Xamarin.Forms. Notice that no quotation marks appear within the curly braces.

It's easy to forget the x:Reference markup extension when setting the BindingContext . It's common to mistakenly
set the property directly to the name of the binding source like this:

BindingContext="slider"
But that's not right. That markup sets the BindingContext property to a string object whose characters spell
"slider"!
Notice that the source property is specified with the Path property of BindingExtension , which corresponds with
the Path property of the Binding class.
The markup shown on the Basic XAML Binding page can be simplified: XAML markup extensions such as
x:Reference and Binding can have content property attributes defined, which for XAML markup extensions
means that the property name doesn't need to appear. The Name property is the content property of x:Reference ,
and the Path property is the content property of Binding , which means that they can be eliminated from the
expressions:

<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference slider}"
Rotation="{Binding Value}" />

Bindings without a Binding Context


The BindingContext property is an important component of data bindings, but it is not always necessary. The
source object can instead be specified in the SetBinding call or the Binding markup extension.
This is demonstrated in the Alternative Code Binding sample. The XAML file is similar to the Basic Code
Binding sample except that the Slider is defined to control the Scale property of the Label . For that reason,
the Slider is set for a range of –2 to 2:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeCodeBindingPage"
Title="Alternative Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

The code-behind file sets the binding with the SetBinding method defined by BindableObject . The argument is a
constructor for the Binding class:

public partial class AlternativeCodeBindingPage : ContentPage


{
public AlternativeCodeBindingPage()
{
InitializeComponent();

label.SetBinding(Label.ScaleProperty, new Binding("Value", source: slider));


}
}
The Binding constructor has 6 parameters, so the source parameter is specified with a named argument. The
argument is the slider object.
Running this program might be a little surprising:

The iOS screen on the left shows how the screen looks when the page first appears. Where is the Label ?
The problem is that the Slider has an initial value of 0. This causes the Scale property of the Label to be also
set to 0, overriding its default value of 1. This results in the Label being initially invisible. As the Android
screenshot demonstrates, you can manipulate the Slider to make the Label appear again, but its initial
disappearance is disconcerting.
You'll discover in the next article how to avoid this problem by initializing the Slider from the default value of the
Scale property.

NOTE
The VisualElement class also defines ScaleX and ScaleY properties, which can scale the VisualElement differently in
the horizontal and vertical directions.

The Alternative XAML Binding page shows the equivalent binding entirely in XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeXamlBindingPage"
Title="Alternative XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value}" />

<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Now the Binding markup extension has two properties set, Source and Path , separated by a comma. They can
appear on the same line if you prefer:

Scale="{Binding Source={x:Reference slider}, Path=Value}" />

The Source property is set to an embedded x:Reference markup extension that otherwise has the same syntax as
setting the BindingContext . Notice that no quotation marks appear within the curly braces, and that the two
properties must be separated by a comma.
The content property of the Binding markup extension is Path , but the Path= part of the markup extension can
only be eliminated if it is the first property in the expression. To eliminate the Path= part, you need to swap the
two properties:

Scale="{Binding Value, Source={x:Reference slider}}" />

Although XAML markup extensions are usually delimited by curly braces, they can also be expressed as object
elements:

<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<Label.Scale>
<Binding Source="{x:Reference slider}"
Path="Value" />
</Label.Scale>
</Label>

Now the Source and Path properties are regular XAML attributes: The values appear within quotation marks
and the attributes are not separated by a comma. The x:Reference markup extension can also become an object
element:

<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<Label.Scale>
<Binding Path="Value">
<Binding.Source>
<x:Reference Name="slider" />
</Binding.Source>
</Binding>
</Label.Scale>
</Label>

This syntax isn't common, but sometimes it's necessary when complex objects are involved.
The examples shown so far set the BindingContext property and the Source property of Binding to an
x:Reference markup extension to reference another view on the page. These two properties are of type Object ,
and they can be set to any object that includes properties that are suitable for binding sources.
In the articles ahead, you'll discover that you can set the BindingContext or Source property to an x:Static
markup extension to reference the value of a static property or field, or a StaticResource markup extension to
reference an object stored in a resource dictionary, or directly to an object, which is generally (but not always) an
instance of a ViewModel.
The BindingContext property can also be set to a Binding object so that the Source and Path properties of
Binding define the binding context.

Binding Context Inheritance


In this article, you've seen that you can specify the source object using the BindingContext property or the Source
property of the Binding object. If both are set, the Source property of the Binding takes precedence over the
BindingContext .

The BindingContext property has an extremely important characteristic:


The setting of the BindingContext property is inherited through the visual tree.
As you'll see, this can be very handy for simplifying binding expressions, and in some cases — particularly in
Model-View -ViewModel (MVVM ) scenarios — it is essential.
The Binding Context Inheritance sample is a simple demonstration of the inheritance of the binding context:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BindingContextInheritancePage"
Title="BindingContext Inheritance">
<StackLayout Padding="10">

<StackLayout VerticalOptions="FillAndExpand"
BindingContext="{x:Reference slider}">

<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="EndAndExpand"
Rotation="{Binding Value}" />

<BoxView Color="#800000FF"
WidthRequest="180"
HeightRequest="40"
HorizontalOptions="Center"
VerticalOptions="StartAndExpand"
Rotation="{Binding Value}" />
</StackLayout>

<Slider x:Name="slider"
Maximum="360" />

</StackLayout>
</ContentPage>

The BindingContext property of the StackLayout is set to the slider object. This binding context is inherited by
both the Label and the BoxView , both of which have their Rotation properties set to the Value property of the
Slider :
In the next article, you'll see how the binding mode can change the flow of data between target and source objects.

Related Links
Data Binding Demos (sample)
Data binding chapter from Xamarin.Forms book

Related Video
Find more Xamarin videos on Channel 9 and YouTube.
Xamarin.Forms Binding Mode
15 minutes to read • Edit Online

Download the sample


In the previous article, the Alternative Code Binding and Alternative XAML Binding pages featured a Label
with its Scale property bound to the Value property of a Slider . Because the Slider initial value is 0, this
caused the Scale property of the Label to be set to 0 rather than 1, and the Label disappeared.
In the DataBindingDemos sample, the Reverse Binding page is similar to the programs in the previous article,
except that the data binding is defined on the Slider rather than on the Label :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.ReverseBindingPage"
Title="Reverse Binding">
<StackLayout Padding="10, 0">

<Label x:Name="label"
Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
VerticalOptions="CenterAndExpand"
Value="{Binding Source={x:Reference label},
Path=Opacity}" />
</StackLayout>
</ContentPage>

At first, this might seem backwards: Now the Label is the data-binding source, and the Slider is the target. The
binding references the Opacity property of the Label , which has a default value of 1.
As you might expect, the Slider is initialized to the value 1 from the initial Opacity value of Label . This is
shown in the iOS screenshot on the left:
But you might be surprised that the Slider continues to work, as the Android screenshot demonstrates. This
seems to suggest that the data binding works better when the Slider is the binding target rather than the Label
because the initialization works like we might expect.
The difference between the Reverse Binding sample and the earlier samples involves the binding mode.

The Default Binding Mode


The binding mode is specified with a member of the BindingMode enumeration:
Default
TwoWay – data goes both ways between source and target
OneWay – data goes from source to target
OneWayToSource – data goes from target to source
OneTime – data goes from source to target, but only when the BindingContext changes (new with
Xamarin.Forms 3.0)
Every bindable property has a default binding mode that is set when the bindable property is created, and which
is available from the DefaultBindingMode property of the BindableProperty object. This default binding mode
indicates the mode in effect when that property is a data-binding target.
The default binding mode for most properties such as Rotation , Scale , and Opacity is OneWay . When these
properties are data-binding targets, then the target property is set from the source.
However, the default binding mode for the Value property of Slider is TwoWay . This means that when the
Value property is a data-binding target, then the target is set from the source (as usual) but the source is also set
from the target. This is what allows the Slider to be set from the initial Opacity value.
This two-way binding might seem to create an infinite loop, but that doesn't happen. Bindable properties do not
signal a property change unless the property actually changes. This prevents an infinite loop.
Two -Way Bindings
Most bindable properties have a default binding mode of OneWay but the following properties have a default
binding mode of TwoWay :
Date property of DatePicker
Text property of Editor , Entry , SearchBar , and EntryCell
IsRefreshing property of ListView
SelectedItem property of MultiPage
SelectedIndex and SelectedItem properties of Picker
Value property of Slider and Stepper
IsToggled property of Switch
On property of SwitchCell
Time property of TimePicker

These particular properties are defined as TwoWay for a very good reason:
When data bindings are used with the Model-View -ViewModel (MVVM ) application architecture, the ViewModel
class is the data-binding source, and the View, which consists of views such as Slider , are data-binding targets.
MVVM bindings resemble the Reverse Binding sample more than the bindings in the previous samples. It is
very likely that you want each view on the page to be initialized with the value of the corresponding property in
the ViewModel, but changes in the view should also affect the ViewModel property.
The properties with default binding modes of TwoWay are those properties most likely to be used in MVVM
scenarios.
One -Way-to -Source Bindings
Read-only bindable properties have a default binding mode of OneWayToSource . There is only one read/write
bindable property that has a default binding mode of OneWayToSource :
SelectedItem property of ListView

The rationale is that a binding on the SelectedItem property should result in setting the binding source. An
example later in this article overrides that behavior.
One -Time Bindings
Several properties have a default binding mode of OneTime , including the IsTextPredictionEnabled property of
Entry .

Target properties with a binding mode of OneTime are updated only when the binding context changes. For
bindings on these target properties, this simplifies the binding infrastructure because it is not necessary to
monitor changes in the source properties.

ViewModels and Property-Change Notifications


The Simple Color Selector page demonstrates the use of a simple ViewModel. Data bindings allow the user to
select a color using three Slider elements for the hue, saturation, and luminosity.
The ViewModel is the data-binding source. The ViewModel does not define bindable properties, but it does
implement a notification mechanism that allows the binding infrastructure to be notified when the value of a
property changes. This notification mechanism is the INotifyPropertyChanged interface, which defines a single
event named PropertyChanged . A class that implements this interface generally fires the event when one of its
public properties changes value. The event does not need to be fired if the property never changes. (The
INotifyPropertyChanged interface is also implemented by BindableObject and a PropertyChanged event is fired
whenever a bindable property changes value.)
The HslColorViewModel class defines five properties: The Hue , Saturation , Luminosity , and Color properties
are interrelated. When any one of the three color components changes value, the Color property is recalculated,
and PropertyChanged events are fired for all four properties:

public class HslColorViewModel : INotifyPropertyChanged


{
Color color;
string name;

public event PropertyChangedEventHandler PropertyChanged;

public double Hue


{
set
{
if (color.Hue != value)
{
Color = Color.FromHsla(value, color.Saturation, color.Luminosity);
}
}
get
{
return color.Hue;
}
}

public double Saturation


{
set
{
if (color.Saturation != value)
{
Color = Color.FromHsla(color.Hue, value, color.Luminosity);
}
}
get
{
return color.Saturation;
}
}

public double Luminosity


{
set
{
if (color.Luminosity != value)
{
Color = Color.FromHsla(color.Hue, color.Saturation, value);
}
}
get
{
return color.Luminosity;
}
}

public Color Color


{
set
{
if (color != value)
{
color = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hue"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Saturation"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Luminosity"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));

Name = NamedColor.GetNearestColorName(color);
}
}
get
{
return color;
}
}

public string Name


{
private set
{
if (name != value)
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
get
{
return name;
}
}
}

When the Color property changes, the static GetNearestColorName method in the NamedColor class (also included
in the DataBindingDemos solution) obtains the closest named color and sets the Name property. This Name
property has a private set accessor, so it cannot be set from outside the class.
When a ViewModel is set as a binding source, the binding infrastructure attaches a handler to the
PropertyChanged event. In this way, the binding can be notified of changes to the properties, and can then set the
target properties from the changed values.
However, when a target property (or the Binding definition on a target property) has a BindingMode of OneTime ,
it is not necessary for the binding infrastructure to attach a handler on the PropertyChanged event. The target
property is updated only when the BindingContext changes and not when the source property itself changes.
The Simple Color Selector XAML file instantiates the HslColorViewModel in the page's resource dictionary and
initializes the Color property. The BindingContext property of the Grid is set to a StaticResource binding
extension to reference that resource:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SimpleColorSelectorPage">

<ContentPage.Resources>
<ResourceDictionary>
<local:HslColorViewModel x:Key="viewModel"
Color="MediumTurquoise" />

<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<Grid BindingContext="{StaticResource viewModel}">


<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<BoxView Color="{Binding Color}"


Grid.Row="0" />

<StackLayout Grid.Row="1"
Margin="10, 0">

<Label Text="{Binding Name}"


HorizontalTextAlignment="Center" />

<Slider Value="{Binding Hue}" />

<Slider Value="{Binding Saturation}" />

<Slider Value="{Binding Luminosity}" />


</StackLayout>
</Grid>
</ContentPage>

The BoxView , Label , and three Slider views inherit the binding context from the Grid . These views are all
binding targets that reference source properties in the ViewModel. For the Color property of the BoxView , and
the Text property of the Label , the data bindings are OneWay : The properties in the view are set from the
properties in the ViewModel.
The Value property of the Slider , however, is TwoWay . This allows each Slider to be set from the ViewModel,
and also for the ViewModel to be set from each Slider .
When the program is first run, the BoxView , Label , and three Slider elements are all set from the ViewModel
based on the initial Color property set when the ViewModel was instantiated. This is shown in the iOS
screenshot at the left:

As you manipulate the sliders, the BoxView and Label are updated accordingly, as illustrated by the Android
screenshot.
Instantiating the ViewModel in the resource dictionary is one common approach. It's also possible to instantiate
the ViewModel within property element tags for the BindingContext property. In the Simple Color Selector
XAML file, try removing the HslColorViewModel from the resource dictionary and set it to the BindingContext
property of the Grid like this:

<Grid>
<Grid.BindingContext>
<local:HslColorViewModel Color="MediumTurquoise" />
</Grid.BindingContext>

···

</Grid>

The binding context can be set in a variety of ways. Sometimes, the code-behind file instantiates the ViewModel
and sets it to the BindingContext property of the page. These are all valid approaches.

Overriding the Binding Mode


If the default binding mode on the target property is not suitable for a particular data binding, it's possible to
override it by setting the Mode property of Binding (or the Mode property of the Binding markup extension) to
one of the members of the BindingMode enumeration.
However, setting the Mode property to TwoWay doesn't always work as you might expect. For example, try
modifying the Alternative XAML Binding XAML file to include TwoWay in the binding definition:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value,
Mode=TwoWay}" />

It might be expected that the Slider would be initialized to the initial value of the Scale property, which is 1, but
that doesn't happen. When a TwoWay binding is initialized, the target is set from the source first, which means that
the Scale property is set to the Slider default value of 0. When the TwoWay binding is set on the Slider , then
the Slider is initially set from the source.
You can set the binding mode to OneWayToSource in the Alternative XAML Binding sample:

<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value,
Mode=OneWayToSource}" />

Now the Slider is initialized to 1 (the default value of Scale ) but manipulating the Slider doesn't affect the
Scale property, so this is not very useful.

NOTE
The VisualElement class also defines ScaleX and ScaleY properties, which can scale the VisualElement differently in
the horizontal and vertical directions.

A very useful application of overriding the default binding mode with TwoWay involves the SelectedItem property
of ListView . The default binding mode is OneWayToSource . When a data binding is set on the SelectedItem
property to reference a source property in a ViewModel, then that source property is set from the ListView
selection. However, in some circumstances, you might also want the ListView to be initialized from the
ViewModel.
The Sample Settings page demonstrates this technique. This page represents a simple implementation of
application settings, which are very often defined in a ViewModel, such as this SampleSettingsViewModel file:

public class SampleSettingsViewModel : INotifyPropertyChanged


{
string name;
DateTime birthDate;
bool codesInCSharp;
double numberOfCopies;
NamedColor backgroundNamedColor;

public event PropertyChangedEventHandler PropertyChanged;

public SampleSettingsViewModel(IDictionary<string, object> dictionary)


{
Name = GetDictionaryEntry<string>(dictionary, "Name");
BirthDate = GetDictionaryEntry(dictionary, "BirthDate", new DateTime(1980, 1, 1));
CodesInCSharp = GetDictionaryEntry<bool>(dictionary, "CodesInCSharp");
NumberOfCopies = GetDictionaryEntry(dictionary, "NumberOfCopies", 1.0);
BackgroundNamedColor = NamedColor.Find(GetDictionaryEntry(dictionary, "BackgroundNamedColor",
"White"));
}
}

public string Name


{
set { SetProperty(ref name, value); }
get { return name; }
}

public DateTime BirthDate


{
set { SetProperty(ref birthDate, value); }
get { return birthDate; }
}

public bool CodesInCSharp


{
set { SetProperty(ref codesInCSharp, value); }
get { return codesInCSharp; }
}

public double NumberOfCopies


{
set { SetProperty(ref numberOfCopies, value); }
get { return numberOfCopies; }
}

public NamedColor BackgroundNamedColor


{
set
{
if (SetProperty(ref backgroundNamedColor, value))
{
OnPropertyChanged("BackgroundColor");
}
}
get { return backgroundNamedColor; }
}

public Color BackgroundColor


{
get { return BackgroundNamedColor?.Color ?? Color.White; }
}

public void SaveState(IDictionary<string, object> dictionary)


{
dictionary["Name"] = Name;
dictionary["BirthDate"] = BirthDate;
dictionary["CodesInCSharp"] = CodesInCSharp;
dictionary["NumberOfCopies"] = NumberOfCopies;
dictionary["BackgroundNamedColor"] = BackgroundNamedColor.Name;
}

T GetDictionaryEntry<T>(IDictionary<string, object> dictionary, string key, T defaultValue = default(T))


{
return dictionary.ContainsKey(key) ? (T)dictionary[key] : defaultValue;
}

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));
}
}

Each application setting is a property that is saved to the Xamarin.Forms properties dictionary in a method named
SaveState and loaded from that dictionary in the constructor. Towards the bottom of the class are two methods
that help streamline ViewModels and make them less prone to errors. The OnPropertyChanged method at the
bottom has an optional parameter that is set to the calling property. This avoids spelling errors when specifying
the name of the property as a string.
The SetProperty method in the class does even more: It compares the value that is being set to the property with
the value stored as a field, and only calls OnPropertyChanged when the two values are not equal.
The SampleSettingsViewModel class defines two properties for the background color: The BackgroundNamedColor
property is of type NamedColor , which is a class also included in the DataBindingDemos solution. The
BackgroundColor property is of type Color , and is obtained from the Color property of the NamedColor object.

The NamedColor class uses .NET reflection to enumerate all the static public fields in the Xamarin.Forms Color
structure, and to store them with their names in a collection accessible from the static All property:

public class NamedColor : IEquatable<NamedColor>, IComparable<NamedColor>


{
// Instance members
private NamedColor()
{
}

public string Name { private set; get; }

public string FriendlyName { private set; get; }

public Color Color { private set; get; }

public string RgbDisplay { private set; get; }

public bool Equals(NamedColor other)


{
return Name.Equals(other.Name);
}

public int CompareTo(NamedColor other)


{
return Name.CompareTo(other.Name);
}

// Static members
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();

// Loop through the public static fields of the Color structure.


foreach (FieldInfo fieldInfo in typeof(Color).GetRuntimeFields())
{
if (fieldInfo.IsPublic &&
fieldInfo.IsStatic &&
fieldInfo.FieldType == typeof(Color))
{
// Convert the name to a friendly name.
string name = fieldInfo.Name;
stringBuilder.Clear();
int index = 0;

foreach (char ch in name)


{
if (index != 0 && Char.IsUpper(ch))
{
stringBuilder.Append(' ');
}
stringBuilder.Append(ch);
index++;
}

// Instantiate a NamedColor object.


Color color = (Color)fieldInfo.GetValue(null);

NamedColor namedColor = new NamedColor


{
Name = name,
FriendlyName = stringBuilder.ToString(),
Color = color,
RgbDisplay = String.Format("{0:X2}-{1:X2}-{2:X2}",
(int)(255 * color.R),
(int)(255 * color.G),
(int)(255 * color.B))
};

// Add it to the collection.


all.Add(namedColor);
}
}
all.TrimExcess();
all.Sort();
All = all;
}

public static IList<NamedColor> All { private set; get; }

public static NamedColor Find(string name)


{
return ((List<NamedColor>)All).Find(nc => nc.Name == name);
}

public static string GetNearestColorName(Color color)


{
double shortestDistance = 1000;
NamedColor closestColor = null;

foreach (NamedColor namedColor in NamedColor.All)


{
double distance = Math.Sqrt(Math.Pow(color.R - namedColor.Color.R, 2) +
Math.Pow(color.G - namedColor.Color.G, 2) +
Math.Pow(color.B - namedColor.Color.B, 2));

if (distance < shortestDistance)


{
shortestDistance = distance;
closestColor = namedColor;
}
}
return closestColor.Name;
}
}

The class in the DataBindingDemos project defines a property named Settings of type
App
SampleSettingsViewModel . This property is initialized when the App class is instantiated, and the SaveState
method is called when the OnSleep method is called:
public partial class App : Application
{
public App()
{
InitializeComponent();

Settings = new SampleSettingsViewModel(Current.Properties);

MainPage = new NavigationPage(new MainPage());


}

public SampleSettingsViewModel Settings { private set; get; }

protected override void OnStart()


{
// Handle when your app starts
}

protected override void OnSleep()


{
// Handle when your app sleeps
Settings.SaveState(Current.Properties);
}

protected override void OnResume()


{
// Handle when your app resumes
}
}

For more information on the application lifecycle methods, see the article App Lifecycle.
Almost everything else is handled in the SampleSettingsPage.xaml file. The BindingContext of the page is set
using a Binding markup extension: The binding source is the static Application.Current property, which is the
instance of the App class in the project, and the Path is set to the Settings property, which is the
SampleSettingsViewModel object:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SampleSettingsPage"
Title="Sample Settings"
BindingContext="{Binding Source={x:Static Application.Current},
Path=Settings}">

<StackLayout BackgroundColor="{Binding BackgroundColor}"


Padding="10"
Spacing="10">

<StackLayout Orientation="Horizontal">
<Label Text="Name: "
VerticalOptions="Center" />

<Entry Text="{Binding Name}"


Placeholder="your name"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center" />
</StackLayout>

<StackLayout Orientation="Horizontal">
<Label Text="Birth Date: "
VerticalOptions="Center" />

<DatePicker Date="{Binding BirthDate}"


HorizontalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center" />
</StackLayout>

<StackLayout Orientation="Horizontal">
<Label Text="Do you code in C#? "
VerticalOptions="Center" />

<Switch IsToggled="{Binding CodesInCSharp}"


VerticalOptions="Center" />
</StackLayout>

<StackLayout Orientation="Horizontal">
<Label Text="Number of Copies: "
VerticalOptions="Center" />

<Stepper Value="{Binding NumberOfCopies}"


VerticalOptions="Center" />

<Label Text="{Binding NumberOfCopies}"


VerticalOptions="Center" />
</StackLayout>

<Label Text="Background Color:" />

<ListView x:Name="colorListView"
ItemsSource="{x:Static local:NamedColor.All}"
SelectedItem="{Binding BackgroundNamedColor, Mode=TwoWay}"
VerticalOptions="FillAndExpand"
RowHeight="40">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
HeightRequest="32"
WidthRequest="32"
VerticalOptions="Center" />

<Label Text="{Binding FriendlyName}"


FontSize="24"
VerticalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>

All the children of the page inherit the binding context. Most of the other bindings on this page are to properties
in SampleSettingsViewModel . The BackgroundColor property is used to set the BackgroundColor property of the
StackLayout , and the Entry , DatePicker , Switch , and Stepper properties are all bound to other properties in
the ViewModel.
The ItemsSource property of the ListView is set to the static NamedColor.All property. This fills the ListView
with all the NamedColor instances. For each item in the ListView , the binding context for the item is set to a
NamedColor object. The BoxView and Label in the ViewCell are bound to properties in NamedColor .

The SelectedItem property of the ListView is of type NamedColor , and is bound to the BackgroundNamedColor
property of SampleSettingsViewModel :

SelectedItem="{Binding BackgroundNamedColor, Mode=TwoWay}"


The default binding mode for SelectedItem is OneWayToSource , which sets the ViewModel property from the
selected item. The TwoWay mode allows the SelectedItem to be initialized from the ViewModel.
However, when the SelectedItem is set in this way, the ListView does not automatically scroll to show the
selected item. A little code in the code-behind file is necessary:

public partial class SampleSettingsPage : ContentPage


{
public SampleSettingsPage()
{
InitializeComponent();

if (colorListView.SelectedItem != null)
{
colorListView.ScrollTo(colorListView.SelectedItem,
ScrollToPosition.MakeVisible,
false);
}
}
}

The iOS screenshot at the left shows the program when it's first run. The constructor in SampleSettingsViewModel
initializes the background color to white, and that's what's selected in the ListView :

The other screenshot shows altered settings. When experimenting with this page, remember to put the program
to sleep or to terminate it on the device or emulator that it's running. Terminating the program from the Visual
Studio debugger will not cause the OnSleep override in the App class to be called.
In the next article you'll see how to specify String Formatting of data bindings that are set on the Text property
of Label .

Related Links
Data Binding Demos (sample)
Data binding chapter from Xamarin.Forms book
Xamarin.Forms String Formatting
4 minutes to read • Edit Online

Download the sample


Sometimes it's convenient to use data bindings to display the string representation of an object or value. For
example, you might want to use a Label to display the current value of a Slider . In this data binding, the Slider
is the source, and the target is the Text property of the Label .
When displaying strings in code, the most powerful tool is the static String.Format method. The formatting string
includes formatting codes specific to various types of objects, and you can include other text along with the values
being formatted. See the Formatting Types in .NET article for more information on string formatting.

The StringFormat Property


This facility is carried over into data bindings: You set the StringFormat property of Binding (or the StringFormat
property of the Binding markup extension) to a standard .NET formatting string with one placeholder:

<Slider x:Name="slider" />


<Label Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The slider value is {0:F2}'}" />

Notice that the formatting string is delimited by single-quote (apostrophe) characters to help the XAML parser
avoid treating the curly braces as another XAML markup extension. Otherwise, that string without the single-
quote character is the same string you'd use to display a floating-point value in a call to String.Format . A
formatting specification of F2 causes the value to be displayed with two decimal places.
The StringFormat property only makes sense when the target property is of type string , and the binding mode
is OneWay or TwoWay . For two-way bindings, the StringFormat is only applicable for values passing from the
source to the target.
As you'll see in the next article on the Binding Path, data bindings can become quite complex and convoluted.
When debugging these data bindings, you can add a Label into the XAML file with a StringFormat to display
some intermediate results. Even if you use it only to display an object's type, that can be helpful.
The String Formatting page illustrates several uses of the StringFormat property:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="DataBindingDemos.StringFormattingPage"
Title="String Formatting">

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>

<Style TargetType="BoxView">
<Setter Property="Color" Value="Blue" />
<Setter Property="HeightRequest" Value="2" />
<Setter Property="Margin" Value="0, 5" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Margin="10">
<Slider x:Name="slider" />
<Label Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The slider value is {0:F2}'}" />

<BoxView />

<TimePicker x:Name="timePicker" />


<Label Text="{Binding Source={x:Reference timePicker},
Path=Time,
StringFormat='The TimeSpan is {0:c}'}" />

<BoxView />

<Entry x:Name="entry" />


<Label Text="{Binding Source={x:Reference entry},
Path=Text,
StringFormat='The Entry text is &quot;{0}&quot;'}" />

<BoxView />

<StackLayout BindingContext="{x:Static sys:DateTime.Now}">


<Label Text="{Binding}" />
<Label Text="{Binding Path=Ticks,
StringFormat='{0:N0} ticks since 1/1/1'}" />
<Label Text="{Binding StringFormat='The {{0:MMMM}} specifier produces {0:MMMM}'}" />
<Label Text="{Binding StringFormat='The long date is {0:D}'}" />
</StackLayout>

<BoxView />

<StackLayout BindingContext="{x:Static sys:Math.PI}">


<Label Text="{Binding}" />
<Label Text="{Binding StringFormat='PI to 4 decimal points = {0:F4}'}" />
<Label Text="{Binding StringFormat='PI in scientific notation = {0:E7}'}" />
</StackLayout>
</StackLayout>
</ContentPage>

The bindings on the Slider and TimePicker show the use of format specifications particular to double and
TimeSpan data types. The StringFormat that displays the text from the Entry view demonstrates how to specify
double quotation marks in the formatting string with the use of the &quot; HTML entity.
The next section in the XAML file is a StackLayout with a BindingContext set to an x:Static markup extension
that references the static DateTime.Now property. The first binding has no properties:

<Label Text="{Binding}" />

This simply displays the DateTime value of the BindingContext with default formatting. The second binding
displays the Ticks property of DateTime , while the other two bindings display the DateTime itself with specific
formatting. Notice this StringFormat :

<Label Text="{Binding StringFormat='The {{0:MMMM}} specifier produces {0:MMMM}'}" />

If you need to display left or right curly braces in your formatting string, simply use a pair of them.
The last section sets the BindingContext to the value of Math.PI and displays it with default formatting and two
different types of numeric formatting.
Here's the program running:

ViewModels and String Formatting


When you're using Label and StringFormat to display the value of a view that is also the target of a ViewModel,
you can either define the binding from the view to the Label or from the ViewModel to the Label . In general, the
second approach is best because it verifies that the bindings between the View and ViewModel are working.
This approach is shown in the Better Color Selector sample, which uses the same ViewModel as the Simple
Color Selector program shown in the Binding Mode article:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.BetterColorSelectorPage"
Title="Better Color Selector">

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>

<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>

<BoxView Color="{Binding Color}"


VerticalOptions="FillAndExpand" />

<StackLayout Margin="10, 0">


<Label Text="{Binding Name}" />

<Slider Value="{Binding Hue}" />


<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />

<Slider Value="{Binding Saturation}" />


<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />

<Slider Value="{Binding Luminosity}" />


<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>

There are now three pairs of Slider and Label elements that are bound to the same source property in the
HslColorViewModel object. The only difference is that Label has a StringFormat property to display each Slider
value.
You might be wondering how you could display RGB (red, green, blue) values in traditional two-digit hexadecimal
format. Those integer values aren't directly available from the Color structure. One solution would be to calculate
integer values of the color components within the ViewModel and expose them as properties. You could then
format them using the X2 formatting specification.
Another approach is more general: You can write a binding value converter as discussed in the later article,
Binding Value Converters.
The next article, however, explores the Binding Path in more detail, and show how you can use it to reference
sub-properties and items in collections.

Related Links
Data Binding Demos (sample)
Data binding chapter from Xamarin.Forms book
Xamarin.Forms Binding Path
3 minutes to read • Edit Online

Download the sample


In all the previous data-binding examples, the Path property of the Binding class (or the Path property of the
Binding markup extension) has been set to a single property. It's actually possible to set Path to a sub -property
(a property of a property), or to a member of a collection.
For example, suppose your page contains a TimePicker :

<TimePicker x:Name="timePicker">

The Time property of TimePicker is of type TimeSpan , but perhaps you want to create a data binding that
references the TotalSeconds property of that TimeSpan value. Here's the data binding:

{Binding Source={x:Reference timePicker},


Path=Time.TotalSeconds}

The Time property is of type TimeSpan , which has a TotalSeconds property. The Time and TotalSeconds
properties are simply connected with a period. The items in the Path string always refer to properties and not to
the types of these properties.
That example and several others are shown in the Path Variations page:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:globe="clr-namespace:System.Globalization;assembly=mscorlib"
x:Class="DataBindingDemos.PathVariationsPage"
Title="Path Variations"
x:Name="page">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="Large" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Margin="10, 0">


<TimePicker x:Name="timePicker" />

<Label Text="{Binding Source={x:Reference timePicker},


Path=Time.TotalSeconds,
StringFormat='{0} total seconds'}" />

<Label Text="{Binding Source={x:Reference page},


Path=Content.Children.Count,
StringFormat='There are {0} children in this StackLayout'}" />

<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},


Path=DateTimeFormat.DayNames[3],
StringFormat='The middle day of the week is {0}'}" />

<Label>
<Label.Text>
<Binding Path="DateTimeFormat.DayNames[3]"
StringFormat="The middle day of the week in France is {0}">
<Binding.Source>
<globe:CultureInfo>
<x:Arguments>
<x:String>fr-FR</x:String>
</x:Arguments>
</globe:CultureInfo>
</Binding.Source>
</Binding>
</Label.Text>
</Label>

<Label Text="{Binding Source={x:Reference page},


Path=Content.Children[1].Text.Length,
StringFormat='The second Label has {0} characters'}" />
</StackLayout>
</ContentPage>

In the second Label , the binding source is the page itself. The Content property is of type StackLayout , which
has a Children property of type IList<View> , which has a Count property indicating the number of children.

Paths with Indexers


The binding in the third Label in the Path Variations pages references the CultureInfo class in the
System.Globalization namespace:

<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},


Path=DateTimeFormat.DayNames[3],
StringFormat='The middle day of the week is {0}'}" />
The source is set to the static CultureInfo.CurrentCulture property, which is an object of type CultureInfo . That
class defines a property named DateTimeFormat of type DateTimeFormatInfo that contains a DayNames collection.
The index selects the fourth item.
The fourth Label does something similar but for the culture associated with France. The Source property of the
binding is set to CultureInfo object with a constructor:

<Label>
<Label.Text>
<Binding Path="DateTimeFormat.DayNames[3]"
StringFormat="The middle day of the week in France is {0}">
<Binding.Source>
<globe:CultureInfo>
<x:Arguments>
<x:String>fr-FR</x:String>
</x:Arguments>
</globe:CultureInfo>
</Binding.Source>
</Binding>
</Label.Text>
</Label>

See Passing Constructor Arguments for more details on specifying constructor arguments in XAML.
Finally, the last example is similar to the second, except that it references one of the children of the StackLayout :

<Label Text="{Binding Source={x:Reference page},


Path=Content.Children[1].Text.Length,
StringFormat='The first Label has {0} characters'}" />

That child is a Label , which has a Text property of type String , which has a Length property. The first Label
reports the TimeSpan set in the TimePicker , so when that text changes, the final Label changes as well.
Here's the program running:

Debugging Complex Paths


Complex path definitions can be difficult to construct: You need to know the type of each sub-property or the type
of items in the collection to correctly add the next sub-property, but the types themselves do not appear in the
path. One good technique is to build up the path incrementally and look at the intermediate results. For that last
example, you could start with no Path definition at all:

<Label Text="{Binding Source={x:Reference page},


StringFormat='{0}'}" />

That displays the type of the binding source, or DataBindingDemos.PathVariationsPage . You know
PathVariationsPage derives from ContentPage , so it has a Content property:

<Label Text="{Binding Source={x:Reference page},


Path=Content,
StringFormat='{0}'}" />

The type of the Content property is now revealed to be Xamarin.Forms.StackLayout . Add the Children property
to the Path and the type is Xamarin.Forms.ElementCollection'1[Xamarin.Forms.View] , which is a class internal to
Xamarin.Forms, but obviously a collection type. Add an index to that and the type is Xamarin.Forms.Label .
Continue in this way.
As Xamarin.Forms processes the binding path, it installs a PropertyChanged handler on any object in the path that
implements the INotifyPropertyChanged interface. For example, the final binding reacts to a change in the first
Label because the Text property changes.

If a property in the binding path does not implement INotifyPropertyChanged , any changes to that property will be
ignored. Some changes could entirely invalidate the binding path, so you should use this technique only when the
string of properties and sub-properties never become invalid.

Related Links
Data Binding Demos (sample)
Data binding chapter from Xamarin.Forms book
Xamarin.Forms Binding Value Converters
10 minutes to read • Edit Online

Download the sample


Data bindings usually transfer data from a source property to a target property, and in some cases from the target
property to the source property. This transfer is straightforward when the source and target properties are of the
same type, or when one type can be converted to the other type through an implicit conversion. When that is not
the case, a type conversion must take place.
In the String Formatting article, you saw how you can use the StringFormat property of a data binding to
convert any type into a string. For other types of conversions, you need to write some specialized code in a class
that implements the IValueConverter interface. (The Universal Windows Platform contains a similar class named
IValueConverter in the Windows.UI.Xaml.Data namespace, but this IValueConverter is in the Xamarin.Forms
namespace.) Classes that implement IValueConverter are called value converters, but they are also often referred
to as binding converters or binding value converters.

The IValueConverter Interface


Suppose you want to define a data binding where the source property is of type int but the target property is a
bool . You want this data binding to produce a false value when the integer source is equal to 0, and true
otherwise.
You can do this with a class that implements the IValueConverter interface:

public class IntToBoolConverter : IValueConverter


{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value != 0;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? 1 : 0;
}
}

You set an instance of this class to the Converter property of the Binding class or to the Converter property of
the Binding markup extension. This class becomes part of the data binding.
The Convertmethod is called when data moves from the source to the target in OneWay or TwoWay bindings. The
value parameter is the object or value from the data-binding source. The method must return a value of the type
of the data-binding target. The method shown here casts the value parameter to an int and then compares it
with 0 for a bool return value.
The ConvertBack method is called when data moves from the target to the source in TwoWay or OneWayToSource
bindings. ConvertBack performs the opposite conversion: It assumes the value parameter is a bool from the
target, and converts it to an int return value for the source.
If the data binding also includes a StringFormat setting, the value converter is invoked before the result is
formatted as a string.
The Enable Buttons page in the Data Binding Demos sample demonstrates how to use this value converter in
a data binding. The IntToBoolConverter is instantiated in the page's resource dictionary. It is then referenced with a
StaticResource markup extension to set the Converter property in two data bindings. It is very common to share
data converters among multiple data bindings on the page:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.EnableButtonsPage"
Title="Enable Buttons">
<ContentPage.Resources>
<ResourceDictionary>
<local:IntToBoolConverter x:Key="intToBool" />
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Padding="10, 0">


<Entry x:Name="entry1"
Text=""
Placeholder="enter search term"
VerticalOptions="CenterAndExpand" />

<Button Text="Search"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
IsEnabled="{Binding Source={x:Reference entry1},
Path=Text.Length,
Converter={StaticResource intToBool}}" />

<Entry x:Name="entry2"
Text=""
Placeholder="enter destination"
VerticalOptions="CenterAndExpand" />

<Button Text="Submit"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
IsEnabled="{Binding Source={x:Reference entry2},
Path=Text.Length,
Converter={StaticResource intToBool}}" />
</StackLayout>
</ContentPage>

If a value converter is used in multiple pages of your application, you can instantiate it in the resource dictionary in
the App.xaml file.
The Enable Buttons page demonstrates a common need when a Button performs an operation based on text
that the user types into an Entry view. If nothing has been typed into the Entry , the Button should be disabled.
Each Button contains a data binding on its IsEnabled property. The data-binding source is the Length property
of the Text property of the corresponding Entry . If that Length property is not 0, the value converter returns
true and the Button is enabled:
Notice that the Text property in each Entry is initialized to an empty string. The Text property is null by
default, and the data binding will not work in that case.
Some value converters are written specifically for particular applications, while others are generalized. If you know
that a value converter will only be used in OneWay bindings, then the ConvertBack method can simply return
null .

The Convert method shown above implicitly assumes that the value argument is of type int and the return
value must be of type bool . Similarly, the ConvertBack method assumes that the value argument is of type
bool and the return value is int . If that is not the case, a runtime exception will occur.

You can write value converters to be more generalized and to accept several different types of data. The Convert
and ConvertBack methods can use the as or is operators with the value parameter, or can call GetType on
that parameter to determine its type, and then do something appropriate. The expected type of each method's
return value is given by the targetType parameter. Sometimes, value converters are used with data bindings of
different target types; the value converter can use the targetType argument to perform a conversion for the
correct type.
If the conversion being performed is different for different cultures, use the culture parameter for this purpose.
The parameter argument to Convert and ConvertBack is discussed later in this article.

Binding Converter Properties


Value converter classes can have properties and generic parameters. This particular value converter converts a
bool from the source to an object of type T for the target:
public class BoolToObjectConverter<T> : IValueConverter
{
public T TrueObject { set; get; }

public T FalseObject { set; get; }

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? TrueObject : FalseObject;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((T)value).Equals(TrueObject);
}
}

The Switch Indicators page demonstrates how it can be used to display the value of a Switch view. Although it's
common to instantiate value converters as resources in a resource dictionary, this page demonstrates an
alternative: Each value converter is instantiated between Binding.Converter property-element tags. The
x:TypeArguments indicates the generic argument, and TrueObject and FalseObject are both set to objects of that
type:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SwitchIndicatorsPage"
Title="Switch Indicators">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="18" />
<Setter Property="VerticalOptions" Value="Center" />
</Style>

<Style TargetType="Switch">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Padding="10, 0">


<StackLayout Orientation="Horizontal"
VerticalOptions="CenterAndExpand">
<Label Text="Subscribe?" />
<Switch x:Name="switch1" />
<Label>
<Label.Text>
<Binding Source="{x:Reference switch1}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="x:String"
TrueObject="Of course!"
FalseObject="No way!" />
</Binding.Converter>
</Binding>
</Label.Text>
</Label>
</StackLayout>

<StackLayout Orientation="Horizontal"
VerticalOptions="CenterAndExpand">
<Label Text="Allow popups?" />
<Switch x:Name="switch2" />
<Label>
<Label>
<Label.Text>
<Binding Source="{x:Reference switch2}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="x:String"
TrueObject="Yes"
FalseObject="No" />
</Binding.Converter>
</Binding>
</Label.Text>
<Label.TextColor>
<Binding Source="{x:Reference switch2}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="Color"
TrueObject="Green"
FalseObject="Red" />
</Binding.Converter>
</Binding>
</Label.TextColor>
</Label>
</StackLayout>

<StackLayout Orientation="Horizontal"
VerticalOptions="CenterAndExpand">
<Label Text="Learn more?" />
<Switch x:Name="switch3" />
<Label FontSize="18"
VerticalOptions="Center">
<Label.Style>
<Binding Source="{x:Reference switch3}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="Style">
<local:BoolToObjectConverter.TrueObject>
<Style TargetType="Label">
<Setter Property="Text" Value="Indubitably!" />
<Setter Property="FontAttributes" Value="Italic, Bold" />
<Setter Property="TextColor" Value="Green" />
</Style>
</local:BoolToObjectConverter.TrueObject>

<local:BoolToObjectConverter.FalseObject>
<Style TargetType="Label">
<Setter Property="Text" Value="Maybe later" />
<Setter Property="FontAttributes" Value="None" />
<Setter Property="TextColor" Value="Red" />
</Style>
</local:BoolToObjectConverter.FalseObject>
</local:BoolToObjectConverter>
</Binding.Converter>
</Binding>
</Label.Style>
</Label>
</StackLayout>
</StackLayout>
</ContentPage>

In the last of the three Switch and Label pairs, the generic argument is set to Style , and entire Style objects
are provided for the values of TrueObject and FalseObject . These override the implicit style for Label set in the
resource dictionary, so the properties in that style are explicitly assigned to the Label . Toggling the Switch causes
the corresponding Label to reflect the change:
It's also possible to use Triggers to implement similar changes in the user-interface based on other views.

Binding Converter Parameters


The Binding class defines a ConverterParameter property, and the Binding markup extension also defines a
ConverterParameter property. If this property is set, then the value is passed to the Convert and ConvertBack
methods as the parameter argument. Even if the instance of the value converter is shared among several data
bindings, the ConverterParameter can be different to perform somewhat different conversions.
The use of ConverterParameter is demonstrated with a color-selection program. In this case, the
RgbColorViewModel has three properties of type double named Red , Green , and Blue that it uses to construct a
Color value:

public class RgbColorViewModel : INotifyPropertyChanged


{
Color color;
string name;

public event PropertyChangedEventHandler PropertyChanged;

public double Red


{
set
{
if (color.R != value)
{
Color = new Color(value, color.G, color.B);
}
}
get
{
return color.R;
}
}

public double Green


{
set
{
if (color.G != value)
{
Color = new Color(color.R, value, color.B);
}
}
}
get
{
return color.G;
}
}

public double Blue


{
set
{
if (color.B != value)
{
Color = new Color(color.R, color.G, value);
}
}
get
{
return color.B;
}
}

public Color Color


{
set
{
if (color != value)
{
color = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Red"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Green"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Blue"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));

Name = NamedColor.GetNearestColorName(color);
}
}
get
{
return color;
}
}

public string Name


{
private set
{
if (name != value)
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
get
{
return name;
}
}
}

The Red , Green , and Blue properties range between 0 and 1. However, you might prefer that the components
be displayed as two-digit hexadecimal values.
To display these as hexadecimal values in XAML, they must be multiplied by 255, converted to an integer, and then
formatted with a specification of "X2" in the StringFormat property. The first two tasks (multiplying by 255 and
converting to an integer) can be handled by the value converter. To make the value converter as generalized as
possible, the multiplication factor can be specified with the ConverterParameter property, which means that it
enters the Convert and ConvertBack methods as the parameter argument:

public class DoubleToIntConverter : IValueConverter


{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)Math.Round((double)value * GetParameter(parameter));
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value / GetParameter(parameter);
}

double GetParameter(object parameter)


{
if (parameter is double)
return (double)parameter;

else if (parameter is int)


return (int)parameter;

else if (parameter is string)


return double.Parse((string)parameter);

return 1;
}
}

The Convert converts from a double to int while multiplying by the parameter value; the ConvertBack divides
the integer value argument by parameter and returns a double result. (In the program shown below, the value
converter is used only in connection with string formatting, so ConvertBack is not used.)
The type of the parameter argument is likely to be different depending on whether the data binding is defined in
code or XAML. If the ConverterParameter property of Binding is set in code, it's likely to be set to a numeric value:

binding.ConverterParameter = 255;

The ConverterParameter property is of type Object , so the C# compiler interprets the literal 255 as an integer, and
sets the property to that value.
In XAML, however, the ConverterParameter is likely to be set like this:

<Label Text="{Binding Red,


Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />

The 255 looks like a number, but because ConverterParameter is of type Object , the XAML parser treats the 255
as a string.
For that reason, the value converter shown above includes a separate GetParameter method that handles cases for
parameter being of type double , int , or string .

The RGB Color Selector page instantiates DoubleToIntConverter in its resource dictionary following the definition
of two implicit styles:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.RgbColorSelectorPage"
Title="RGB Color Selector">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>

<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>

<local:DoubleToIntConverter x:Key="doubleToInt" />


</ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
<StackLayout.BindingContext>
<local:RgbColorViewModel Color="Gray" />
</StackLayout.BindingContext>

<BoxView Color="{Binding Color}"


VerticalOptions="FillAndExpand" />

<StackLayout Margin="10, 0">


<Label Text="{Binding Name}" />

<Slider Value="{Binding Red}" />


<Label Text="{Binding Red,
Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />

<Slider Value="{Binding Green}" />


<Label Text="{Binding Green,
Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Green = {0:X2}'}" />

<Slider Value="{Binding Blue}" />


<Label>
<Label.Text>
<Binding Path="Blue"
StringFormat="Blue = {0:X2}"
Converter="{StaticResource doubleToInt}">
<Binding.ConverterParameter>
<x:Double>255</x:Double>
</Binding.ConverterParameter>
</Binding>
</Label.Text>
</Label>
</StackLayout>
</StackLayout>
</ContentPage>

The values of the Red and Green properties are displayed with a Binding markup extension. The Blue property,
however, instantiates the Binding class to demonstrate how an explicit double value can be set to
ConverterParameter property.

Here's the result:


Related Links
Data Binding Demos (sample)
Data binding chapter from Xamarin.Forms book
Xamarin.Forms Relative Bindings
5 minutes to read • Edit Online

Download the sample


Relative bindings provide the ability to set the binding source relative to the position of the binding target. They
are created with the RelativeSource markup extension, and set as the Source property of a binding expression.
The RelativeSource markup extension is supported by the RelativeSourceExtension class, which defines the
following properties:
, of type RelativeBindingSourceMode , describes the location of the binding source relative to the position
Mode
of the binding target.
AncestorLevel , of type int , an optional ancestor level to look for, when the Mode property is FindAncestor .
An AncestorLevel of n skips n-1 instances of the AncestorType .
AncestorType , of type Type , the type of ancestor to look for, when the Mode property is FindAncestor .

NOTE
The XAML parser allows the RelativeSourceExtension class to be abbreviated as RelativeSource .

The Mode property should be set to one of the RelativeBindingSourceMode enumeration members:
TemplatedParentindicates the element to which the template, in which the bound element exists, is applied.
For more information, see Bind to a templated parent.
Self indicates the element on which the binding is being set, allowing you to bind one property of that
element to another property on the same element. For more information, see Bind to self.
FindAncestor indicates the ancestor in the visual tree of the bound element. This mode should be used to bind
to an ancestor control represented by the AncestorType property. For more information, see Bind to an
ancestor.
FindAncestorBindingContext indicates the BindingContext of the ancestor in the visual tree of the bound
element. This mode should be used to bind to the BindingContext of an ancestor represented by the
AncestorType property. For more information, see Bind to an ancestor.

The Mode property is the content property of the RelativeSourceExtension class. Therefore, for XAML markup
expressions expressed with curly braces, you can eliminate the Mode= part of the expression.
For more information about Xamarin.Forms markup extensions, see XAML Markup Extensions.

Bind to self
The Self relative binding mode is used bind a property of an element to another property on the same element:

<BoxView Color="Red"
WidthRequest="200"
HeightRequest="{Binding Source={RelativeSource Self}, Path=WidthRequest}"
HorizontalOptions="Center" />

In this example, the BoxView sets its WidthRequest property to a fixed size, and the HeightRequest property binds
to the WidthRequest property. Therefore, both properties are equal and so a square is drawn:
IMPORTANT
When binding a property of an element to another property on the same element, the properties must be the same type.
Alternatively, you can specify a converter on the binding to convert the value.

A common use of this binding mode is set an object's BindingContext to a property on itself. The following code
shows an example of this:

<ContentPage ...
BindingContext="{Binding Source={RelativeSource Self}, Path=DefaultViewModel}">
<StackLayout>
<ListView ItemsSource="{Binding Employees}">
...
</ListView>
</StackLayout>
</ContentPage>

In this example, the BindingContext of the page is set to the DefaultViewModel property of itself. This property is
defined in the code-behind file for the page, and provides a viewmodel instance. The ListView binds to the
Employees property of the viewmodel.

Bind to an ancestor
The FindAncestor and FindAncestorBindingContext relative binding modes are used to bind to parent elements, of
a certain type, in the visual tree. The FindAncestor mode is used to bind to a parent element, which derives from
the Element type. The FindAncestorBindingContext mode is used to bind to the BindingContext of a parent
element.

WARNING
The AncestorType property must be set to a Type when using the FindAncestor and FindAncestorBindingContext
relative binding modes, otherwise a XamlParseException is thrown.

If the Mode property isn't explicitly set, setting the AncestorType property to a type that derives from Element
will implicitly set the Mode property to FindAncestor . Similarly, setting the AncestorType property to a type that
does not derive from Element will implicitly set the Mode property to FindAncestorBindingContext .

NOTE
Relative bindings that use the FindAncestorBindingContext mode will be reapplied when the BindingContext of any
ancestors change.

The following XAML shows an example where the Mode property will be implicitly set to
FindAncestorBindingContext :
<ContentPage ...
BindingContext="{Binding Source={RelativeSource Self}, Path=DefaultViewModel}">
<StackLayout>
<ListView ItemsSource="{Binding Employees}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Fullname}"
VerticalOptions="Center" />
<Button Text="Delete"
Command="{Binding Source={RelativeSource AncestorType={x:Type
local:PeopleViewModel}}, Path=DeleteEmployeeCommand}"
CommandParameter="{Binding}"
HorizontalOptions="EndAndExpand" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>

In this example, the BindingContext of the page is set to the DefaultViewModel property of itself. This property is
defined in the code-behind file for the page, and provides a viewmodel instance. The ListView binds to the
Employees property of the viewmodel. The DataTemplate , which defines the appearance of each item in the
ListView , contains a Button . The button's Command property is bound to the DeleteEmployeeCommand in its
parent's viewmodel. Tapping a Button deletes an employee:

In addition, the optional AncestorLevel property can help disambiguate ancestor lookup in scenarios where there
is possibly more than one ancestor of that type in the visual tree:

<Label Text="{Binding Source={RelativeSource AncestorType={x:Type Entry}, AncestorLevel=2}, Path=Text}" />

In this example, the Label.Text property binds to the Text property of the second Entry that's encountered on
the upward path, starting at the target element of the binding.

NOTE
The AncestorLevel property should be set to 1 to find the ancestor nearest to the binding target element.

Bind to a templated parent


The TemplatedParent relative binding mode is used to bind from within a control template to the runtime object
instance to which the template is applied (known as the templated parent). This mode is only applicable if the
relative binding is within a control template, and is similar to setting a TemplateBinding .
The following XAML shows an example of the TemplatedParent relative binding mode:
<ContentPage ...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
<Frame BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
BackgroundColor="{Binding CardColor}"
BorderColor="{Binding BorderColor}"
...>
<Grid>
...
<Label Text="{Binding CardTitle}"
... />
<BoxView BackgroundColor="{Binding BorderColor}"
... />
<Label Text="{Binding CardDescription}"
... />
</Grid>
</Frame>
</ControlTemplate>
</ContentPage.Resources>
<StackLayout>
<controls:CardView BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla
elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Jane Doe"
CardDescription="Phasellus eu convallis mi. In tempus augue eu dignissim fermentum.
Morbi ut lacus vitae eros lacinia."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Xamarin Monkey"
CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat
scelerisque erat, quis aliquet arcu."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
</StackLayout>
</ContentPage>

In this example, the Frame , which is the root element of the ControlTemplate , has its BindingContext set to the
runtime object instance to which the template is applied. Therefore, the Frame and its children resolve their
binding expressions against the properties of each CardView object:

For more information about control templates, see Xamarin.Forms Control Templates.
Related links
Data Binding Demos (sample)
XAML Markup Extensions
Xamarin.Forms Control Templates
Xamarin.Forms Binding Fallbacks
3 minutes to read • Edit Online

Download the sample


Sometimes data bindings fail, because the binding source can't be resolved, or because the binding succeeds but
returns a null value. While these scenarios can be handled with value converters, or other additional code, data
bindings can be made more robust by defining fallback values to use if the binding process fails. This can be
accomplished by defining the FallbackValue and TargetNullValue properties in a binding expression. Because
these properties reside in the BindingBase class, they can be used with bindings, compiled bindings, and with the
Binding markup extension.

NOTE
Use of the FallbackValue and TargetNullValue properties in a binding expression is optional.

Defining a fallback value


The FallbackValue property allows a fallback value to be defined that will be used when the binding source can't
be resolved. A common scenario for setting this property is when binding to source properties that might not exist
on all objects in a bound collection of heterogeneous types.
The MonkeyDetail page illustrates setting the FallbackValue property:

<Label Text="{Binding Population, FallbackValue='Population size unknown'}"


... />

The binding on the Label defines a FallbackValue value that will be set on the target if the binding source can't
be resolved. Therefore, the value defined by the FallbackValue property will be displayed if the Population
property doesn't exist on the bound object. Notice that here the FallbackValue property value is delimited by
single-quote (apostrophe) characters.
Rather than defining FallbackValue property values inline, it's recommended to define them as resources in a
ResourceDictionary . The advantage of this approach is that such values are defined once in a single location, and
are more easily localizable. The resources can then be retrieved using the StaticResource markup extension:

<Label Text="{Binding Population, FallbackValue={StaticResource populationUnknown}}"


... />

NOTE
It's not possible to set the FallbackValue property with a binding expression.

Here's the program running:


When the FallbackValue property isn't set in a binding expression and the binding path or part of the path isn't
resolved, BindableProperty.DefaultValue is set on the target. However, when the FallbackValue property is set and
the binding path or part of the path isn't resolved, the value of the FallbackValue value property is set on the
target. Therefore, on the MonkeyDetail page the Label displays "Population size unknown" because the bound
object lacks a Population property.

IMPORTANT
A defined value converter is not executed in a binding expression when the FallbackValue property is set.

Defining a null replacement value


The TargetNullValue property allows a replacement value to be defined that will be used when the binding source
is resolved, but the value is null . A common scenario for setting this property is when binding to source
properties that might be null in a bound collection.
The Monkeys page illustrates setting the TargetNullValue property:

<ListView ItemsSource="{Binding Monkeys}"


...>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
...
<Image Source="{Binding ImageUrl,
TargetNullValue='https://upload.wikimedia.org/wikipedia/commons/2/20/Point_d_interrogation.jpg'}"
... />
...
<Label Text="{Binding Location, TargetNullValue='Location unknown'}"
... />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

The bindings on the Image and Label both define TargetNullValue values that will be applied if the binding path
returns null . Therefore, the values defined by the TargetNullValue properties will be displayed for any objects in
the collection where the ImageUrl and Location properties are not defined. Notice that here the TargetNullValue
property values are delimited by single-quote (apostrophe) characters.
Rather than defining TargetNullValue property values inline, it's recommended to define them as resources in a
ResourceDictionary . The advantage of this approach is that such values are defined once in a single location, and
are more easily localizable. The resources can then be retrieved using the StaticResource markup extension:
<Image Source="{Binding ImageUrl, TargetNullValue={StaticResource fallbackImageUrl}}"
... />
<Label Text="{Binding Location, TargetNullValue={StaticResource locationUnknown}}"
... />

NOTE
It's not possible to set the TargetNullValue property with a binding expression.

Here's the program running:

When the TargetNullValue property isn't set in a binding expression, a source value of null will be converted if a
value converter is defined, formatted if a StringFormat is defined, and the result is then set on the target. However,
when the TargetNullValue property is set, a source value of null will be converted if a value converter is defined,
and if it's still null after the conversion, the value of the TargetNullValue property is set on the target.

IMPORTANT
String formatting is not applied in a binding expression when the TargetNullValue property is set.

Related Links
Data Binding Demos (sample)
The Xamarin.Forms Command Interface
17 minutes to read • Edit Online

Download the sample


In the Model-View -ViewModel (MVVM ) architecture, data bindings are defined between properties in the
ViewModel, which is generally a class that derives from INotifyPropertyChanged , and properties in the View,
which is generally the XAML file. Sometimes an application has needs that go beyond these property bindings by
requiring the user to initiate commands that affect something in the ViewModel. These commands are generally
signaled by button clicks or finger taps, and traditionally they are processed in the code-behind file in a handler for
the Clicked event of the Button or the Tapped event of a TapGestureRecognizer .
The commanding interface provides an alternative approach to implementing commands that is much better
suited to the MVVM architecture. The ViewModel itself can contain commands, which are methods that are
executed in reaction to a specific activity in the View such as a Button click. Data bindings are defined between
these commands and the Button .
To allow a data binding between a Button and a ViewModel, the Button defines two properties:
Command of type System.Windows.Input.ICommand
CommandParameter of type Object

To use the command interface, you define a data binding that targets the Command property of the Button where
the source is a property in the ViewModel of type ICommand . The ViewModel contains code associated with that
ICommand property that is executed when the button is clicked. You can set CommandParameter to arbitrary data to
distinguish between multiple buttons if they are all bound to the same ICommand property in the ViewModel.
The Command and CommandParameter properties are also defined by the following classes:
MenuItem and hence, ToolbarItem , which derives from MenuItem
TextCell and hence, ImageCell , which derives from TextCell
TapGestureRecognizer

SearchBar defines a SearchCommand property of type ICommand and a SearchCommandParameter property. The
RefreshCommand property of ListView is also of type ICommand .
All these commands can be handled within a ViewModel in a manner that doesn't depend on the particular user-
interface object in the View.

The ICommand Interface


The System.Windows.Input.ICommand interface is not part of Xamarin.Forms. It is defined instead in the
System.Windows.Input namespace, and consists of two methods and one event:

public interface ICommand


{
public void Execute (Object parameter);

public bool CanExecute (Object parameter);

public event EventHandler CanExecuteChanged;


}
To use the command interface, your ViewModel contains properties of type ICommand :

public ICommand MyCommand { private set; get; }

The ViewModel must also reference a class that implements the ICommand interface. This class will be described
shortly. In the View, the Command property of a Button is bound to that property:

<Button Text="Execute command"


Command="{Binding MyCommand}" />

When the user presses the Button , the Button calls the Execute method in the ICommand object bound to its
Command property. That's the simplest part of the commanding interface.

The CanExecute method is more complex. When the binding is first defined on the Command property of the
Button , and when the data binding changes in some way, the Button calls the CanExecute method in the
ICommand object. If CanExecute returns false , then the Button disables itself. This indicates that the particular
command is currently unavailable or invalid.
The Button also attaches a handler on the CanExecuteChanged event of ICommand . The event is fired from within
the ViewModel. When that event is fired, the Button calls CanExecute again. The Button enables itself if
CanExecute returns true and disables itself if CanExecute returns false .

IMPORTANT
Do not use the IsEnabled property of Button if you're using the command interface.

The Command Class


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.
You can write such a class yourself, or you can use a class that someone else has written. Because ICommand is part
of Microsoft Windows, it has been used for years with Windows MVVM applications. Using a Windows class that
implements ICommand allows you to share your ViewModels between Windows applications and Xamarin.Forms
applications.
If sharing ViewModels between Windows and Xamarin.Forms is not a concern, then you can use the Command or
Command<T> class included in Xamarin.Forms to implement the ICommand interface. These classes allow you to
specify the bodies of the Execute and CanExecute methods in class constructors. Use Command<T> when you use
the CommandParameter property to distinguish between multiple views bound to the same ICommand property, and
the simpler Command class when that isn't a requirement.

Basic Commanding
The Person Entry page in the Data Binding Demos program demonstrates some simple commands
implemented in a ViewModel.
The PersonViewModel defines three properties named Name , Age , and Skills that define a person. This class
does not contain any ICommand properties:
public class PersonViewModel : INotifyPropertyChanged
{
string name;
double age;
string skills;

public event PropertyChangedEventHandler PropertyChanged;

public string Name


{
set { SetProperty(ref name, value); }
get { return name; }
}

public double Age


{
set { SetProperty(ref age, value); }
get { return age; }
}

public string Skills


{
set { SetProperty(ref skills, value); }
get { return skills; }
}

public override string ToString()


{
return Name + ", age " + Age;
}

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));
}
}

The PersonCollectionViewModel shown below creates new objects of type PersonViewModel and allows the user to
fill in the data. For that purpose, the class defines properties IsEditing of type bool and PersonEdit of type
PersonViewModel . In addition, the class defines three properties of type ICommand and a property named Persons
of type IList<PersonViewModel> :
public class PersonCollectionViewModel : INotifyPropertyChanged
{
PersonViewModel personEdit;
bool isEditing;

public event PropertyChangedEventHandler PropertyChanged;

···

public bool IsEditing


{
private set { SetProperty(ref isEditing, value); }
get { return isEditing; }
}

public PersonViewModel PersonEdit


{
set { SetProperty(ref personEdit, value); }
get { return personEdit; }
}

public ICommand NewCommand { private set; get; }

public ICommand SubmitCommand { private set; get; }

public ICommand CancelCommand { private set; get; }

public IList<PersonViewModel> Persons { get; } = new ObservableCollection<PersonViewModel>();

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));
}
}

This abbreviated listing does not include the class's constructor, which is where the three properties of type
ICommand are defined, which will be shown shortly. Notice that changes to the three properties of type ICommand
and the Persons property do not result in PropertyChanged events being fired. These properties are all set when
the class is first created and do not change thereafter.
Before examining the constructor of the PersonCollectionViewModel class, let's look at the XAML file for the
Person Entry program. This contains a Grid with its BindingContext property set to the
PersonCollectionViewModel . The Grid contains a Button with the text New with its Command property bound to
the NewCommand property in the ViewModel, an entry form with properties bound to the IsEditing property, as
well as properties of PersonViewModel , and two more buttons bound to the SubmitCommand and CancelCommand
properties of the ViewModel. The final ListView displays the collection of persons already entered:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.PersonEntryPage"
Title="Person Entry">
<Grid Margin="10">
<Grid.BindingContext>
<local:PersonCollectionViewModel />
</Grid.BindingContext>

<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<!-- New Button -->


<Button Text="New"
Grid.Row="0"
Command="{Binding NewCommand}"
HorizontalOptions="Start" />

<!-- Entry Form -->


<Grid Grid.Row="1"
IsEnabled="{Binding IsEditing}">

<Grid BindingContext="{Binding PersonEdit}">


<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Label Text="Name: " Grid.Row="0" Grid.Column="0" />


<Entry Text="{Binding Name}"
Grid.Row="0" Grid.Column="1" />

<Label Text="Age: " Grid.Row="1" Grid.Column="0" />


<StackLayout Orientation="Horizontal"
Grid.Row="1" Grid.Column="1">
<Stepper Value="{Binding Age}"
Maximum="100" />
<Label Text="{Binding Age, StringFormat='{0} years old'}"
VerticalOptions="Center" />
</StackLayout>

<Label Text="Skills: " Grid.Row="2" Grid.Column="0" />


<Entry Text="{Binding Skills}"
Grid.Row="2" Grid.Column="1" />

</Grid>
</Grid>

<!-- Submit and Cancel Buttons -->


<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Button Text="Submit"
Grid.Column="0"
Command="{Binding SubmitCommand}"
VerticalOptions="CenterAndExpand" />

<Button Text="Cancel"
Grid.Column="1"
Command="{Binding CancelCommand}"
VerticalOptions="CenterAndExpand" />
VerticalOptions="CenterAndExpand" />
</Grid>

<!-- List of Persons -->


<ListView Grid.Row="3"
ItemsSource="{Binding Persons}" />
</Grid>
</ContentPage>

Here's how it works: The user first presses the New button. This enables the entry form but disables the New
button. The user then enters a name, age, and skills. At any time during the editing, the user can press the Cancel
button to start over. Only when a name and a valid age have been entered is the Submit button enabled. Pressing
this Submit button transfers the person to the collection displayed by the ListView . After either the Cancel or
Submit button is pressed, the entry form is cleared and the New button is enabled again.
The iOS screen at the left shows the layout before a valid age is entered. The Android screen shows the Submit
button enabled after an age has been set:

The program does not have any facility for editing existing entries, and does not save the entries when you
navigate away from the page.
All the logic for the New, Submit, and Cancel buttons is handled in PersonCollectionViewModel through
definitions of the NewCommand , SubmitCommand , and CancelCommand properties. The constructor of the
PersonCollectionViewModel sets these three properties to objects of type Command .

A constructor of the Command class allows you to pass arguments of type Action and Func<bool> corresponding
to the Execute and CanExecute methods. It's easiest to define these actions and functions as lambda functions
right in the Command constructor. Here is the definition of the Command object for the NewCommand property:
public class PersonCollectionViewModel : INotifyPropertyChanged
{

···

public PersonCollectionViewModel()
{
NewCommand = new Command(
execute: () =>
{
PersonEdit = new PersonViewModel();
PersonEdit.PropertyChanged += OnPersonEditPropertyChanged;
IsEditing = true;
RefreshCanExecutes();
},
canExecute: () =>
{
return !IsEditing;
});

···

void OnPersonEditPropertyChanged(object sender, PropertyChangedEventArgs args)


{
(SubmitCommand as Command).ChangeCanExecute();
}

void RefreshCanExecutes()
{
(NewCommand as Command).ChangeCanExecute();
(SubmitCommand as Command).ChangeCanExecute();
(CancelCommand as Command).ChangeCanExecute();
}

···

When the user clicks the New button, the execute function passed to the Command constructor is executed. This
creates a new PersonViewModel object, sets a handler on that object's PropertyChanged event, sets IsEditing to
true , and calls the RefreshCanExecutes method defined after the constructor.

Besides implementing the ICommand interface, the Command class also defines a method named ChangeCanExecute .
Your ViewModel should call ChangeCanExecute for an ICommand property whenever anything happens that might
change the return value of the CanExecute method. A call to ChangeCanExecute causes the Command class to fire
the CanExecuteChanged method. The Button has attached a handler for that event and responds by calling
CanExecute again, and then enabling itself based on the return value of that method.

When the method of NewCommand calls RefreshCanExecutes , the NewCommand property gets a call to
execute
ChangeCanExecute , and the Button calls the canExecute method, which now returns false because the
IsEditing property is now true .

The handler for the new PersonViewModel object calls the


PropertyChanged ChangeCanExecute method of
SubmitCommand . Here's how that command property is implemented:
public class PersonCollectionViewModel : INotifyPropertyChanged
{

···

public PersonCollectionViewModel()
{

···

SubmitCommand = new Command(


execute: () =>
{
Persons.Add(PersonEdit);
PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
PersonEdit = null;
IsEditing = false;
RefreshCanExecutes();
},
canExecute: () =>
{
return PersonEdit != null &&
PersonEdit.Name != null &&
PersonEdit.Name.Length > 1 &&
PersonEdit.Age > 0;
});

···
}

···

The canExecutefunction for SubmitCommand is called every time there's a property changed in the
PersonViewModel object being edited. It returns true only when the Name property is at least one character long,
and Age is greater than 0. At that time, the Submit button becomes enabled.
The execute function for Submit removes the property-changed handler from the PersonViewModel , adds the
object to the Persons collection, and returns everything to initial conditions.
The execute function for the Cancel button does everything that the Submit button does except add the object
to the collection:
public class PersonCollectionViewModel : INotifyPropertyChanged
{

···

public PersonCollectionViewModel()
{

···

CancelCommand = new Command(


execute: () =>
{
PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
PersonEdit = null;
IsEditing = false;
RefreshCanExecutes();
},
canExecute: () =>
{
return IsEditing;
});
}

···

The canExecute method returns true at any time a PersonViewModel is being edited.
These techniques could be adapted to more complex scenarios: A property in PersonCollectionViewModel could be
bound to the SelectedItem property of the ListView for editing existing items, and a Delete button could be
added to delete those items.
It isn't necessary to define the execute and canExecute methods as lambda functions. You can write them as
regular private methods in the ViewModel and reference them in the Command constructors. However, this
approach does tend to result in a lot of methods that are referenced only once in the ViewModel.

Using Command Parameters


It is sometimes convenient for one or more buttons (or other user-interface objects) to share the same ICommand
property in the ViewModel. In this case, you use the CommandParameter property to distinguish between the
buttons.
You can continue to use the Command class for these shared ICommand properties. The class defines an alternative
constructor that accepts execute and canExecute methods with parameters of type Object . This is how the
CommandParameter is passed to these methods.

However, when using CommandParameter , it's easiest to use the generic Command<T> class to specify the type of the
object set to CommandParameter . The execute and canExecute methods that you specify have parameters of that
type.
The Decimal Keyboard page illustrates this technique by showing how to implement a keypad for entering
decimal numbers. The BindingContext for the Grid is a DecimalKeypadViewModel . The Entry property of this
ViewModel is bound to the Text property of a Label . All the Button objects are bound to various commands in
the ViewModel: ClearCommand , BackspaceCommand , and DigitCommand :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.DecimalKeypadPage"
Title="Decimal Keyboard">

<Grid WidthRequest="240"
HeightRequest="480"
ColumnSpacing="2"
RowSpacing="2"
HorizontalOptions="Center"
VerticalOptions="Center">

<Grid.BindingContext>
<local:DecimalKeypadViewModel />
</Grid.BindingContext>

<Grid.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="FontSize" Value="32" />
<Setter Property="BorderWidth" Value="1" />
<Setter Property="BorderColor" Value="Black" />
</Style>
</ResourceDictionary>
</Grid.Resources>

<Label Text="{Binding Entry}"


Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
FontSize="32"
LineBreakMode="HeadTruncation"
VerticalTextAlignment="Center"
HorizontalTextAlignment="End" />

<Button Text="CLEAR"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Command="{Binding ClearCommand}" />

<Button Text="&#x21E6;"
Grid.Row="1" Grid.Column="2"
Command="{Binding BackspaceCommand}" />

<Button Text="7"
Grid.Row="2" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="7" />

<Button Text="8"
Grid.Row="2" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="8" />

<Button Text="9"
Grid.Row="2" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="9" />

<Button Text="4"
Grid.Row="3" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="4" />

<Button Text="5"
Grid.Row="3" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="5" />

<Button Text="6"
Grid.Row="3" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="6" />
<Button Text="1"
Grid.Row="4" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="1" />

<Button Text="2"
Grid.Row="4" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="2" />

<Button Text="3"
Grid.Row="4" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="3" />

<Button Text="0"
Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2"
Command="{Binding DigitCommand}"
CommandParameter="0" />

<Button Text="&#x00B7;"
Grid.Row="5" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="." />
</Grid>
</ContentPage>

The 11 buttons for the 10 digits and the decimal point share a binding to DigitCommand . The CommandParameter
distinguishes between these buttons. The value set to CommandParameter is generally the same as the text displayed
by the button except for the decimal point, which for purposes of clarity is displayed with a middle dot character.
Here's the program in action:

Notice that the button for the decimal point in all three screenshots is disabled because the entered number
already contains a decimal point.
The DecimalKeypadViewModel defines an Entry property of type string (which is the only property that triggers a
PropertyChanged event) and three properties of type ICommand :
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
string entry = "0";

public event PropertyChangedEventHandler PropertyChanged;

···

public string Entry


{
private set
{
if (entry != value)
{
entry = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Entry"));
}
}
get
{
return entry;
}
}

public ICommand ClearCommand { private set; get; }

public ICommand BackspaceCommand { private set; get; }

public ICommand DigitCommand { private set; get; }


}

The button corresponding to the ClearCommand is always enabled and simply sets the entry back to "0":

public class DecimalKeypadViewModel : INotifyPropertyChanged


{

···

public DecimalKeypadViewModel()
{
ClearCommand = new Command(
execute: () =>
{
Entry = "0";
RefreshCanExecutes();
});

···

void RefreshCanExecutes()
{
((Command)BackspaceCommand).ChangeCanExecute();
((Command)DigitCommand).ChangeCanExecute();
}

···

Because the button is always enabled, it is not necessary to specify a canExecute argument in the Command
constructor.
The logic for entering numbers and backspacing is a little tricky because if no digits have been entered, then the
Entry property is the string "0". If the user types more zeroes, then the Entry still contains just one zero. If the
user types any other digit, that digit replaces the zero. But if the user types a decimal point before any other digit,
then Entry is the string "0.".
The Backspace button is enabled only when the length of the entry is greater than 1, or if Entry is not equal to
the string "0":

public class DecimalKeypadViewModel : INotifyPropertyChanged


{

···

public DecimalKeypadViewModel()
{

···

BackspaceCommand = new Command(


execute: () =>
{
Entry = Entry.Substring(0, Entry.Length - 1);
if (Entry == "")
{
Entry = "0";
}
RefreshCanExecutes();
},
canExecute: () =>
{
return Entry.Length > 1 || Entry != "0";
});

···

···

The logic for the execute function for the Backspace button ensures that the Entry is at least a string of "0".
The DigitCommand property is bound to 11 buttons, each of which identifies itself with the CommandParameter
property. The DigitCommand could be set to an instance of the regular Command class, but it's easier to use the
Command<T> generic class. When using the commanding interface with XAML, the CommandParameter properties
are usually strings, and that's the type of the generic argument. The execute and canExecute functions then have
arguments of type string :
public class DecimalKeypadViewModel : INotifyPropertyChanged
{

···

public DecimalKeypadViewModel()
{

···

DigitCommand = new Command<string>(


execute: (string arg) =>
{
Entry += arg;
if (Entry.StartsWith("0") && !Entry.StartsWith("0."))
{
Entry = Entry.Substring(1);
}
RefreshCanExecutes();
},
canExecute: (string arg) =>
{
return !(arg == "." && Entry.Contains("."));
});
}

···

The execute method appends the string argument to the Entry property. However, if the result begins with a
zero (but not a zero and a decimal point) then that initial zero must be removed using the Substring function.
The canExecute method returns false only if the argument is the decimal point (indicating that the decimal
point is being pressed) and Entry already contains a decimal point.
All the executemethods call RefreshCanExecutes , which then calls ChangeCanExecute for both DigitCommand and
ClearCommand . This ensures that the decimal point and backspace buttons are enabled or disabled based on the
current sequence of entered digits.

Adding Commands to Existing Views


If you'd like to use the commanding interface with views that don't support it, it's possible to use a Xamarin.Forms
behavior that converts an event into a command. This is described in the article Reusable
EventToCommandBehavior.

Asynchronous Commanding for Navigation Menus


Commanding is convenient for implementing navigation menus, such as that in the Data Binding Demos
program itself. Here's part of 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:DataBindingDemos"
x:Class="DataBindingDemos.MainPage"
Title="Data Binding Demos"
Padding="10">
<TableView Intent="Menu">
<TableRoot>
<TableSection Title="Basic Bindings">

<TextCell Text="Basic Code Binding"


Detail="Define a data-binding in code"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BasicCodeBindingPage}" />

<TextCell Text="Basic XAML Binding"


Detail="Define a data-binding in XAML"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BasicXamlBindingPage}" />

<TextCell Text="Alternative Code Binding"


Detail="Define a data-binding in code without a BindingContext"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:AlternativeCodeBindingPage}" />

···

</TableSection>
</TableRoot>
</TableView>
</ContentPage>

When using commanding with XAML, CommandParameter properties are usually set to strings. In this case,
however, a XAML markup extension is used so that the CommandParameter is of type System.Type .
Each Command property is bound to a property named NavigateCommand . That property is defined in the code-
behind file, MainPage.xaml.cs:

public partial class MainPage : ContentPage


{
public MainPage()
{
InitializeComponent();

NavigateCommand = new Command<Type>(


async (Type pageType) =>
{
Page page = (Page)Activator.CreateInstance(pageType);
await Navigation.PushAsync(page);
});

BindingContext = this;
}

public ICommand NavigateCommand { private set; get; }


}

The constructor sets the NavigateCommand property to an execute method that instantiates the System.Type
parameter and then navigates to it. Because the PushAsync call requires an await operator, the execute method
must be flagged as asynchronous. This is accomplished with the async keyword before the parameter list.
The constructor also sets the BindingContext of the page to itself so that the bindings reference the
NavigateCommand in this class.
The order of the code in this constructor makes a difference: The InitializeComponent call causes the XAML to be
parsed, but at that time the binding to a property named NavigateCommand cannot be resolved because
BindingContext is set to null . If the BindingContext is set in the constructor before NavigateCommand is set, then
the binding can be resolved when BindingContext is set, but at that time, NavigateCommand is still null . Setting
NavigateCommand after BindingContext will have no effect on the binding because a change to NavigateCommand
doesn't fire a PropertyChanged event, and the binding doesn't know that NavigateCommand is now valid.
Setting both NavigateCommand and BindingContext (in any order) prior to the call to InitializeComponent will
work because both components of the binding are set when the XAML parser encounters the binding definition.
Data bindings can sometimes be tricky, but as you've seen in this series of articles, they are powerful and versatile,
and help greatly to organize your code by separating underlying logic from the user interface.

Related Links
Data Binding Demos (sample)
Data binding chapter from Xamarin.Forms book
Xamarin.Forms Compiled Bindings
7 minutes to read • Edit Online

Download the sample


Compiled bindings are resolved more quickly than classic bindings, therefore improving data binding
performance in Xamarin.Forms applications.
Data bindings have two main problems:
1. There's no compile-time validation of binding expressions. Instead, bindings are resolved at runtime.
Therefore, any invalid bindings aren't detected until runtime when the application doesn't behave as expected
or error messages appear.
2. They aren't cost efficient. Bindings are resolved at runtime using general-purpose object inspection (reflection),
and the overhead of doing this varies from platform to platform.
Compiled bindings improve data binding performance in Xamarin.Forms applications by resolving binding
expressions at compile-time rather than runtime. In addition, this compile-time validation of binding expressions
enables a better developer troubleshooting experience because invalid bindings are reported as build errors.
The process for using compiled bindings is to:
1. Enable XAML compilation. For more information about XAML compilation, see XAML Compilation.
2. Set an x:DataType attribute on a VisualElement to the type of the object that the VisualElement and its
children will bind to.

NOTE
It's recommended to set the x:DataType attribute at the same level in the view hierarchy as the BindingContext is set.
However, this attribute can be re-defined at any location in a view hierarchy.

To use compiled bindings, the x:DataType attribute must be set to a string literal, or a type using the x:Type
markup extension. At XAML compile time, any invalid binding expressions will be reported as build errors.
However, the XAML compiler will only report a build error for the first invalid binding expression that it
encounters. Any valid binding expressions that are defined on the VisualElement or its children will be compiled,
regardless of whether the BindingContext is set in XAML or code. Compiling a binding expression generates
compiled code that will get a value from a property on the source, and set it on the property on the target that's
specified in the markup. In addition, depending on the binding expression, the generated code may observe
changes in the value of the source property and refresh the target property, and may push changes from the
target back to the source.

IMPORTANT
Compiled bindings are currently disabled for any binding expressions that define the Source property. This is because the
Source property is always set using the x:Reference markup extension, which can't be resolved at compile time.

Use compiled bindings


The Compiled Color Selector page demonstrates using compiled bindings between Xamarin.Forms views and
viewmodel properties:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorSelectorPage"
Title="Compiled Color Selector">
...
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
... />
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>

The root StackLayout instantiates the HslColorViewModel and initializes the Color property within property
element tags for the BindingContext property. This root StackLayout also defines the x:DataType attribute as the
viewmodel type, indicating that any binding expressions in the root StackLayout view hierarchy will be compiled.
This can be verified by changing any of the binding expressions to bind to a non-existent viewmodel property,
which will result in a build error. While this example sets the x:DataType attribute to a string literal, it can also be
set to a type with the x:Type markup extension. For more information about the x:Type markup extension, see
x:Type Markup Extension.

IMPORTANT
The x:DataType attribute can be re-defined at any point in a view hierarchy.

The BoxView , Label elements, and Slider views inherit the binding context from the StackLayout . These views
are all binding targets that reference source properties in the viewmodel. For the BoxView.Color property, and the
Label.Text property, the data bindings are OneWay – the properties in the view are set from the properties in the
viewmodel. However, the Slider.Value property uses a TwoWay binding. This allows each Slider to be set from
the viewmodel, and also for the viewmodel to be set from each Slider .
When the application is first run, the BoxView , Label elements, and Slider elements are all set from the
viewmodel based on the initial Color property set when the viewmodel was instantiated. This is shown in the
following screenshots:
As the sliders are manipulated, the BoxView and Label elements are updated accordingly.
For more information about this color selector, see ViewModels and Property-Change Notifications.

Use compiled bindings in a DataTemplate


Bindings in a DataTemplate are interpreted in the context of the object being templated. Therefore, when using
compiled bindings in a DataTemplate , the DataTemplate needs to declare the type of its data object using the
x:DataType attribute.

The Compiled Color List page demonstrates using compiled bindings in a DataTemplate :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorListPage"
Title="Compiled Color List">
<Grid>
...
<ListView x:Name="colorListView"
ItemsSource="{x:Static local:NamedColor.All}"
... >
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:NamedColor">
<ViewCell>
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
... />
<Label Text="{Binding FriendlyName}"
... />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- The BoxView doesn't use compiled bindings -->
<BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
... />
</Grid>
</ContentPage>

The ListView.ItemsSource property is set to the static NamedColor.All property. The NamedColor class uses .NET
reflection to enumerate all the static public fields in the Color structure, and to store them with their names in a
collection that is accessible from the static All property. Therefore, the ListView is filled with all of the
NamedColor instances. For each item in the ListView , the binding context for the item is set to a NamedColor
object. The BoxView and Label elements in the ViewCell are bound to NamedColor properties.
Note that the DataTemplate defines the x:DataType attribute to be the NamedColor type, indicating that any
binding expressions in the DataTemplate view hierarchy will be compiled. This can be verified by changing any of
the binding expressions to bind to a non-existent NamedColor property, which will result in a build error. While this
example sets the x:DataType attribute to a string literal, it can also be set to a type with the x:Type markup
extension. For more information about the x:Type markup extension, see x:Type Markup Extension.
When the application is first run, the ListView is populated with NamedColor instances. When an item in the
ListView is selected, the BoxView.Color property is set to the color of the selected item in the ListView :

Selecting other items in the ListView updates the color of the BoxView .

Combine compiled bindings with classic bindings


Binding expressions are only compiled for the view hierarchy that the x:DataType attribute is defined on.
Conversely, any views in a hierarchy on which the x:DataType attribute is not defined will use classic bindings. It's
therefore possible to combine compiled bindings and classic bindings on a page. For example, in the previous
section the views within the DataTemplate use compiled bindings, while the BoxView that's set to the color
selected in the ListView does not.
Careful structuring of x:DataType attributes can therefore lead to a page using compiled and classic bindings.
Alternatively, the x:DataType attribute can be re-defined at any point in a view hierarchy to null using the
x:Null markup extension. Doing this indicates that any binding expressions within the view hierarchy will use
classic bindings. The Mixed Bindings page demonstrates this approach:
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />
<StackLayout x:DataType="{x:Null}"
Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>

The root StackLayout sets the x:DataType attribute to be the HslColorViewModel type, indicating that any binding
expression in the root StackLayout view hierarchy will be compiled. However, the inner StackLayout redefines
the x:DataType attribute to null with the x:Null markup expression. Therefore, the binding expressions within
the inner StackLayout use classic bindings. Only the BoxView , within the root StackLayout view hierarchy, uses
compiled bindings.
For more information about the x:Null markup expression, see x:Null Markup Extension.

Performance
Compiled bindings improve data binding performance, with the performance benefit varying. Unit testing reveals
that:
A compiled binding that uses property-change notification (i.e. a OneWay , OneWayToSource , or TwoWay binding)
is resolved approximately 8 times quicker than a classic binding.
A compiled binding that doesn't use property-change notification (i.e. a OneTime binding) is resolved
approximately 20 times quicker than a classic binding.
Setting the BindingContext on a compiled binding that uses property change notification (i.e. a OneWay ,
OneWayToSource , or TwoWay binding) is approximately 5 times quicker than setting the BindingContext on a
classic binding.
Setting the BindingContext on a compiled binding that doesn't use property change notification (i.e. a OneTime
binding) is approximately 7 times quicker than setting the BindingContext on a classic binding.

These performance differences can be magnified on mobile devices, dependent upon the platform being used, the
version of the operating system being used, and the device on which the application is running.

Related links
Data Binding Demos (sample)
Xamarin.Forms DependencyService
2 minutes to read • Edit Online

Introduction
The DependencyService class is a service locator that enables Xamarin.Forms applications to invoke native platform
functionality from shared code.

Registration and Resolution


Platform implementations must be registered with the DependencyService , and then resolved from shared code to
invoke them.

Picking a Photo from the Library


This article explains how to use the Xamarin.Forms DependencyService class to pick a photo from the phone's
picture library.
Xamarin.Forms DependencyService Introduction
2 minutes to read • Edit Online

Download the sample


The DependencyService class is a service locator that enables Xamarin.Forms applications to invoke native
platform functionality from shared code.
The process for using the DependencyService to invoke native platform functionality is to:
1. Create an interface for the native platform functionality, in shared code. For more information, see Create an
interface.
2. Implement the interface in the required platform projects. For more information, see Implement the interface
on each platform.
3. Register the platform implementations with the DependencyService . This enables Xamarin.Forms to locate the
platform implementations at runtime. For more information, see Register the platform implementations.
4. Resolve the platform implementations from shared code, and invoke them. For more information, see Resolve
the platform implementations.
The following diagram shows how native platform functionality is invoked in a Xamarin.Forms application:

Create an interface
The first step in being able to invoke native platform functionality from shared code, is to create an interface that
defines the API for interacting with the native platform functionality. This interface should be placed in your shared
code project.
The following example shows an interface for an API that can be used to retrieve the orientation of a device:

public interface IDeviceOrientationService


{
DeviceOrientation GetOrientation();
}

Implement the interface on each platform


After creating the interface that defines the API for interacting with the native platform functionality, the interface
must be implemented in each platform project.
iOS
The following code example shows the implementation of the IDeviceOrientationService interface on iOS:

namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
UIInterfaceOrientation orientation = UIApplication.SharedApplication.StatusBarOrientation;

bool isPortrait = orientation == UIInterfaceOrientation.Portrait ||


orientation == UIInterfaceOrientation.PortraitUpsideDown;
return isPortrait ? DeviceOrientation.Portrait : DeviceOrientation.Landscape;
}
}
}

Android
The following code example shows the implementation of the IDeviceOrientationService interface on Android:

namespace DependencyServiceDemos.Droid
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
IWindowManager windowManager =
Android.App.Application.Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();

SurfaceOrientation orientation = windowManager.DefaultDisplay.Rotation;


bool isLandscape = orientation == SurfaceOrientation.Rotation90 ||
orientation == SurfaceOrientation.Rotation270;
return isLandscape ? DeviceOrientation.Landscape : DeviceOrientation.Portrait;
}
}
}

Universal Windows Platform


The following code example shows the implementation of the IDeviceOrientationService interface on the
Universal Windows Platform (UWP ):

namespace DependencyServiceDemos.UWP
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
ApplicationViewOrientation orientation = ApplicationView.GetForCurrentView().Orientation;
return orientation == ApplicationViewOrientation.Landscape ? DeviceOrientation.Landscape :
DeviceOrientation.Portrait;
}
}
}

Register the platform implementations


After implementing the interface in each platform project, the platform implementations must be registered with
the DependencyService , so that Xamarin.Forms can locate them at runtime. This is typically performed with the
DependencyAttribute , which indicates that the specified type provides an implementation of the interface.
The following example shows using the DependencyAttribute to register the iOS implementation of the
IDeviceOrientationService interface:

using Xamarin.Forms;

[assembly: Dependency(typeof(DependencyServiceDemos.iOS.DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
...
}
}
}

In this example, the DependencyAttribute registers the DeviceOrientationService with the DependencyService .
Similarly, the implementations of the IDeviceOrientationService interface on other platforms should be registered
with the DependencyAttribute .
For more information about registering platform implementations with the DependencyService , see
Xamarin.Forms DependencyService Registration and Resolution.

Resolve the platform implementations


Following registration of platform implementations with the DependencyService , the implementations must be
resolved before being invoked. This is typically performed in shared code using the DependencyService.Get<T>
method.
The following code shows an example of calling the Get<T> method to resolve the IDeviceOrientationService
interface, and then invoking its GetOrientation method:

IDeviceOrientationService service = DependencyService.Get<IDeviceOrientationService>();


DeviceOrientation orientation = service.GetOrientation();

Alternatively, this code can be condensed into a single line:

DeviceOrientation orientation = DependencyService.Get<IDeviceOrientationService>().GetOrientation();

For more information about resolving platform implementations with the DependencyService , see Xamarin.Forms
DependencyService Registration and Resolution.

Related links
DependencyService Demos (sample)
Xamarin.Forms DependencyService Registration and Resolution
Xamarin.Forms DependencyService Registration and
Resolution
5 minutes to read • Edit Online

Download the sample


When using the Xamarin.Forms DependencyService to invoke native platform functionality, platform
implementations must be registered with the DependencyService , and then resolved from shared code to invoke
them.

Register platform implementations


Platform implementations must be registered with the DependencyService so that Xamarin.Forms can locate them
at runtime.
Registration can be performed with the DependencyAttribute , or with the Register methods.

IMPORTANT
Release builds of UWP projects that use .NET native compilation should register platform implementations with the
Register methods.

Registration by attribute
The DependencyAttribute can be used to register a platform implementation with the DependencyService . The
attribute indicates that the specified type provides a concrete implementation of the interface.
The following example shows using the DependencyAttribute to register the iOS implementation of the
IDeviceOrientationService interface:

using Xamarin.Forms;

[assembly: Dependency(typeof(DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
...
}
}
}

In this example, the DependencyAttribute registers the DeviceOrientationService with the DependencyService . This
results in the concrete type being registered against the interface it implements.
Similarly, the implementations of the IDeviceOrientationService interface on other platforms should be
registered with the DependencyAttribute .
NOTE
Registration with the DependencyAttribute is performed at the namespace level.

Registration by method
The DependencyService.Register methods can be used to register a platform implementation with the
DependencyService .

The following example shows using the Register method to register the iOS implementation of the
IDeviceOrientationService interface:

[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
DependencyService.Register<IDeviceOrientationService, DeviceOrientationService>();
return base.FinishedLaunching(app, options);
}
}

In this example, the method registers the concrete type, DeviceOrientationService , against the
Register
IDeviceOrientationService interface. Alternatively, an overload of the Register method can be used to register a
platform implementation with the DependencyService :

DependencyService.Register<DeviceOrientationService>();

In this example, the Register method registers the DeviceOrientationService with the DependencyService . This
results in the concrete type being registered against the interface it implements.
Similarly, the implementations of the IDeviceOrientationService interface on other platforms can be registered
with the Register methods.

IMPORTANT
Registration with the Register methods must be performed in platform projects, before the functionality provided by the
platform implementation is invoked from shared code.

Resolve the platform implementations


Platform implementations must be resolved before being invoked. This is typically performed in shared code
using the DependencyService.Get<T> method. However, it can also be accomplished with the
DependencyService.Resolve<T> method.

By default, the DependencyService will only resolve platform implementations that have parameterless
constructors. However, a dependency resolution method can be injected into Xamarin.Forms that uses a
dependency injection container or factory methods to resolve platform implementations. This approach can be
used to resolve platform implementations that have constructors with parameters. For more information, see
Dependency resolution in Xamarin.Forms.
IMPORTANT
Invoking a platform implementation that hasn't been registered with the DependencyService will result in a
NullReferenceException being thrown.

Resolve using the Get<T> method


The Get<T> method retrieves the platform implementation of interface T at runtime, and creates an instance of it
as a singleton. This instance will live for the lifetime of the application, and any subsequent calls to resolve the
same platform implementation will retrieve the same instance.
The following code shows an example of calling the Get<T> method to resolve the IDeviceOrientationService
interface, and then invoking its GetOrientation method:

IDeviceOrientationService service = DependencyService.Get<IDeviceOrientationService>();


DeviceOrientation orientation = service.GetOrientation();

Alternatively, this code can be condensed into a single line:

DeviceOrientation orientation = DependencyService.Get<IDeviceOrientationService>().GetOrientation();

NOTE
The Get<T> method creates an instance of the platform implementation of interface T as a singleton, by default.
However, this behavior can be changed. For more information, see Manage the lifetime of resolved objects.

Resolve using the Resolve<T> method


The Resolve<T> method retrieves the platform implementation of interface T at runtime, using a dependency
resolution method that's been injected into Xamarin.Forms with the DependencyResolver class. If a dependency
resolution method hasn't been injected into Xamarin.Forms, the Resolve<T> method will fallback to calling the
Get<T> method to retrieve the platform implementation. For more information about injecting a dependency
resolution method into Xamarin.Forms, see Dependency resolution in Xamarin.Forms.
The following code shows an example of calling the Resolve<T> method to resolve the IDeviceOrientationService
interface, and then invoking its GetOrientation method:

IDeviceOrientationService service = DependencyService.Resolve<IDeviceOrientationService>();


DeviceOrientation orientation = service.GetOrientation();

Alternatively, this code can be condensed into a single line:

DeviceOrientation orientation = DependencyService.Resolve<IDeviceOrientationService>().GetOrientation();

NOTE
When the Resolve<T> method falls back to calling the Get<T> method, it creates an instance of the platform
implementation of interface T as a singleton, by default. However, this behavior can be changed. For more information, see
Manage the lifetime of resolved objects.

Manage the lifetime of resolved objects


The default behavior of the DependencyService class is to resolve platform implementations as singletons.
Therefore, platform implementations will live for the lifetime of an application.
This behavior is specified with the DependencyFetchTarget optional argument on the Get<T> and Resolve<T>
methods. The DependencyFetchTarget enumeration defines two members:
GlobalInstance , which returns the platform implementation as a singleton.
NewInstance , which returns a new instance of the platform implementation. The application is then responsible
for managing the lifetime of the platform implementation instance.
The Get<T> and Resolve<T> methods both set their optional arguments to DependencyFetchTarget.GlobalInstance ,
and so platform implementations are always resolved as singletons. This behavior can be changed, so that new
instances of platform implementations are created, by specifying DependencyFetchTarget.NewInstance as
arguments to the Get<T> and Resolve<T> methods:

ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);

In this example, the DependencyService creates a new instance of the platform implementation for the
ITextToSpeechService interface. Any subsequent calls to resolve the ITextToSpeechService will also create new
instances.
The consequence of always creating a new instance of a platform implementation is that the application becomes
responsible for managing the instances' lifetime. This means that if you subscribe to an event defined in a
platform implementation, you should unsubscribe from the event when the platform implementation is no longer
required. In addition, it means that it may be necessary for platform implementations to implement IDisposable ,
and cleanup their resources in Dispose methods. The sample application demonstrates this scenario in its
TextToSpeechService platform implementations.

When an application finishes using a platform implementation that implements IDisposable , it should call the
object's Dispose implementation. One way of accomplishing this is with a using statement:

ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);


using (service as IDisposable)
{
await service.SpeakAsync("Hello world");
}

In this example, after the SpeakAsync method is invoked, the using statement automatically disposes of the
platform implementation object. This results in the object's Dispose method being invoked, which performs the
required cleanup.
For more information about calling an object's Dispose method, see Using objects that implement IDisposable.

Related links
DependencyService Demos (sample)
Dependency resolution in Xamarin.Forms
Picking a Photo from the Picture Library
6 minutes to read • Edit Online

Download the sample


This article walks through the creation of an application that allows the user to pick a photo from the phone's
picture library. Because Xamarin.Forms does not include this functionality, it is necessary to use
DependencyService to access native APIs on each platform.

Creating the interface


First, create an interface in shared code that expresses the desired functionality. In the case of a photo-picking
application, just one method is required. This is defined in the IPhotoPickerService interface in the .NET Standard
library of the sample code:

namespace DependencyServiceDemos
{
public interface IPhotoPickerService
{
Task<Stream> GetImageStreamAsync();
}
}

The GetImageStreamAsync method is defined as asynchronous because the method must return quickly, but it can't
return a Stream object for the selected photo until the user has browsed the picture library and selected one.
This interface is implemented in all the platforms using platform-specific code.

iOS implementation
The iOS implementation of the IPhotoPickerService interface uses the UIImagePickerController as described in
the Choose a Photo from the Gallery recipe and sample code.
The iOS implementation is contained in the PhotoPickerService class in the iOS project of the sample code. To
make this class visible to the DependencyService manager, the class must be identified with an [ assembly ] attribute
of type Dependency , and the class must be public and explicitly implement the IPhotoPickerService interface:
[assembly: Dependency (typeof (PhotoPickerService))]
namespace DependencyServiceDemos.iOS
{
public class PhotoPickerService : IPhotoPickerService
{
TaskCompletionSource<Stream> taskCompletionSource;
UIImagePickerController imagePicker;

public Task<Stream> GetImageStreamAsync()


{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
MediaTypes =
UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
};

// Set event handlers


imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
imagePicker.Canceled += OnImagePickerCancelled;

// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);

// Return Task object


taskCompletionSource = new TaskCompletionSource<Stream>();
return taskCompletionSource.Task;
}
...
}
}

The GetImageStreamAsync method creates a UIImagePickerController and initializes it to select images from the
photo library. Two event handlers are required: One for when the user selects a photo and the other for when the
user cancels the display of the photo library. The PresentModalViewController then displays the photo library to
the user.
At this point, the GetImageStreamAsync method must return a Task<Stream> object to the code that's calling it. This
task is completed only when the user has finished interacting with the photo library and one of the event handlers
is called. For situations like this, the TaskCompletionSource class is essential. The class provides a Task object of
the proper generic type to return from the GetImageStreamAsync method, and the class can later be signaled when
the task is completed.
The FinishedPickingMedia event handler is called when the user has selected a picture. However, the handler
provides a UIImage object and the Task must return a .NET Stream object. This is done in two steps: The
UIImage object is first converted to an in memory PNG or JPEG file stored in an NSData object, and then the
NSData object is converted to a .NET Stream object. A call to the SetResult method of the TaskCompletionSource
object completes the task by providing the Stream object:
namespace DependencyServiceDemos.iOS
{
public class PhotoPickerService : IPhotoPickerService
{
TaskCompletionSource<Stream> taskCompletionSource;
UIImagePickerController imagePicker;
...
void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
{
UIImage image = args.EditedImage ?? args.OriginalImage;

if (image != null)
{
// Convert UIImage to .NET Stream object
NSData data;
if (args.ReferenceUrl.PathExtension.Equals("PNG") ||
args.ReferenceUrl.PathExtension.Equals("png"))
{
data = image.AsPNG();
}
else
{
data = image.AsJPEG(1);
}
Stream stream = data.AsStream();

UnregisterEventHandlers();

// Set the Stream as the completion of the Task


taskCompletionSource.SetResult(stream);
}
else
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}

void OnImagePickerCancelled(object sender, EventArgs args)


{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
imagePicker.DismissModalViewController(true);
}

void UnregisterEventHandlers()
{
imagePicker.FinishedPickingMedia -= OnImagePickerFinishedPickingMedia;
imagePicker.Canceled -= OnImagePickerCancelled;
}
}
}

An iOS application requires permission from the user to access the phone's photo library. Add the following to the
dict section of the Info.plist file:

<key>NSPhotoLibraryUsageDescription</key>
<string>Picture Picker uses photo library</string>

Android implementation
The Android implementation uses the technique described in the Select an Image recipe and the sample code.
However, the method that is called when the user has selected an image from the picture library is an
OnActivityResult override in a class that derives from Activity . For this reason, the normal MainActivity class
in the Android project has been supplemented with a field, a property, and an override of the OnActivityResult
method:

public class MainActivity : FormsAppCompatActivity


{
internal static MainActivity Instance { get; private set; }

protected override void OnCreate(Bundle savedInstanceState)


{
// ...
Instance = this;
}
// ...
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;

public TaskCompletionSource<Stream> PickImageTaskCompletionSource { set; get; }

protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)


{
base.OnActivityResult(requestCode, resultCode, intent);

if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Android.Net.Uri uri = intent.Data;
Stream stream = ContentResolver.OpenInputStream(uri);

// Set the Stream as the completion of the Task


PickImageTaskCompletionSource.SetResult(stream);
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}

The OnActivityResult override indicates the selected picture file with an Android Uri object, but this can be
converted into a .NET Stream object by calling the OpenInputStream method of the ContentResolver object that
was obtained from the activity's ContentResolver property.
Like the iOS implementation, the Android implementation uses a TaskCompletionSource to signal when the task
has been completed. This TaskCompletionSource object is defined as a public property in the MainActivity class.
This allows the property to be referenced in the PhotoPickerService class in the Android project. This is the class
with the GetImageStreamAsync method:
[assembly: Dependency(typeof(PhotoPickerService))]
namespace DependencyServiceDemos.Droid
{
public class PhotoPickerService : IPhotoPickerService
{
public Task<Stream> GetImageStreamAsync()
{
// Define the Intent for getting images
Intent intent = new Intent();
intent.SetType("image/*");
intent.SetAction(Intent.ActionGetContent);

// Start the picture-picker activity (resumes in MainActivity.cs)


MainActivity.Instance.StartActivityForResult(
Intent.CreateChooser(intent, "Select Picture"),
MainActivity.PickImageId);

// Save the TaskCompletionSource object as a MainActivity property


MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<Stream>();

// Return Task object


return MainActivity.Instance.PickImageTaskCompletionSource.Task;
}
}
}

This method accesses the MainActivity class for several purposes: for the Instance property, for the
PickImageId field, for the TaskCompletionSource property, and to call StartActivityForResult . This method is
defined by the FormsAppCompatActivity class, which is the base class of MainActivity .

UWP implementation
Unlike the iOS and Android implementations, the implementation of the photo picker for the Universal Windows
Platform does not require the TaskCompletionSource class. The PhotoPickerService class uses the FileOpenPicker
class to get access to the photo library. Because the PickSingleFileAsync method of FileOpenPicker is itself
asynchronous, the GetImageStreamAsync method can simply use await with that method (and other asynchronous
methods) and return a Stream object:
[assembly: Dependency(typeof(PhotoPickerService))]
namespace DependencyServiceDemos.UWP
{
public class PhotoPickerService : IPhotoPickerService
{
public async Task<Stream> GetImageStreamAsync()
{
// Create and initialize the FileOpenPicker
FileOpenPicker openPicker = new FileOpenPicker
{
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.PicturesLibrary,
};

openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");

// Get a file and return a Stream


StorageFile storageFile = await openPicker.PickSingleFileAsync();

if (storageFile == null)
{
return null;
}

IRandomAccessStreamWithContentType raStream = await storageFile.OpenReadAsync();


return raStream.AsStreamForRead();
}
}
}

Implementing in shared code


Now that the interface has been implemented for each platform, the shared code in the .NET Standard library can
take advantage of it.
The UI includes a Button that can be clicked to choose a photo:

<Button Text="Pick Photo"


Clicked="OnPickPhotoButtonClicked" />

The Clicked event handler uses the DependencyService class to call GetImageStreamAsync . This results in a call to
the platform project. If the method returns a Stream object, then the handler sets the Source property of the
image object to the Stream data:

async void OnPickPhotoButtonClicked(object sender, EventArgs e)


{
(sender as Button).IsEnabled = false;

Stream stream = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();


if (stream != null)
{
image.Source = ImageSource.FromStream(() => stream);
}

(sender as Button).IsEnabled = true;


}
Related links
DependencyService (sample)
Choose a Photo from the Gallery (iOS )
Select an Image (Android)
Xamarin.Forms Effects
2 minutes to read • Edit Online

Xamarin.Forms user interfaces are rendered using the native controls of the target platform, allowing
Xamarin.Forms applications to retain the appropriate look and feel for each platform. Effects allow the native
controls on each platform to be customized without having to resort to a custom renderer implementation.

Introduction to Effects
Effects allow the native controls on each platform to be customized, and are typically used for small styling
changes. This article provides an introduction to effects, outlines the boundary between effects and custom
renderers, and describes the PlatformEffect class.

Creating an Effect
Effects simplify the customization of a control. This article demonstrates how to create an effect that changes the
background color of the Entry control when the control gains focus.

Passing Parameters to an Effect


Creating an effect that's configured through parameters enables the effect to be reused. These articles
demonstrate using properties to pass parameters to an effect, and changing a parameter at runtime.

Invoking Events from an Effect


Effects can invoke events. This article shows how to create an event that implements low -level multi-touch finger
tracking and signals an application for touch presses, moves, and releases.

Reusable RoundEffect
RoundEffect is a reusable effect that can be applied to any control deriving from VisualElement to render the
control as a circle. This effect can be used to create circular images, circular buttons, or other circular controls.
Introduction to Effects
3 minutes to read • Edit Online

Effects allow the native controls on each platform to be customized, and are typically used for small styling
changes. This article provides an introduction to effects, outlines the boundary between effects and custom
renderers, and describes the PlatformEffect class.
Xamarin.Forms Pages, Layouts and Controls presents a common API to describe cross-platform mobile user
interfaces. Each page, layout, and control is rendered differently on each platform using a Renderer class that in
turn creates a native control (corresponding to the Xamarin.Forms representation), arranges it on the screen, and
adds the behavior specified in the shared code.
Developers can implement their own custom Renderer classes to customize the appearance and/or behavior of a
control. However, implementing a custom renderer class to perform a simple control customization is often a
heavy-weight response. Effects simplify this process, allowing the native controls on each platform to be more
easily customized.
Effects are created in platform-specific projects by subclassing the PlatformEffect control, and then the effects are
consumed by attaching them to an appropriate control in a Xamarin.Forms .NET Standard library or Shared
Library project.

Why Use an Effect over a Custom Renderer?


Effects simplify the customization of a control, are reusable, and can be parameterized to further increase reuse.
Anything that can be achieved with an effect can also be achieved with a custom renderer. However, custom
renderers offer more flexibility and customization than effects. The following guidelines list the circumstances in
which to choose an effect over a custom renderer:
An effect is recommended when changing the properties of a platform-specific control will achieve the desired
result.
A custom renderer is required when there's a need to override methods of a platform-specific control.
A custom renderer is required when there's a need to replace the platform-specific control that implements a
Xamarin.Forms control.

Subclassing the PlatformEffect Class


The following table lists the namespace for the PlatformEffect class on each platform, and the types of its
properties:

PLATFORM NAMESPACE CONTAINER CONTROL

iOS Xamarin.Forms.Platform.iOS UIView UIView

Android Xamarin.Forms.Platform.And ViewGroup View


roid

Universal Windows Platform Xamarin.Forms.Platform.UW FrameworkElement FrameworkElement


(UWP) P

Each platform-specific PlatformEffect class exposes the following properties:


Container – references the platform-specific control being used to implement the layout.
Control – references the platform-specific control being used to implement the Xamarin.Forms control.
Element – references the Xamarin.Forms control that's being rendered.

Effects do not have type information about the container, control, or element they are attached to because they can
be attached to any element. Therefore, when an effect is attached to an element that it doesn't support it should
degrade gracefully or throw an exception. However, the Container , Control , and Element properties can be cast
to their implementing type. For more information about these types see Renderer Base Classes and Native
Controls.
Each platform-specific PlatformEffect class exposes the following methods, which must be overridden to
implement an effect:
OnAttached – called when an effect is attached to a Xamarin.Forms control. An overridden version of this
method, in each platform-specific effect class, is the place to perform customization of the control, along with
exception handling in case the effect cannot be applied to the specified Xamarin.Forms control.
OnDetached – called when an effect is detached from a Xamarin.Forms control. An overridden version of this
method, in each platform-specific effect class, is the place to perform any effect cleanup such as de-registering
an event handler.
In addition, the PlatformEffect exposes the OnElementPropertyChanged method, which can also be overridden. This
method is called when a property of the element has changed. An overridden version of this method, in each
platform-specific effect class, is the place to respond to bindable property changes on the Xamarin.Forms control.
A check for the property that's changed should always be made, as this override can be called many times.

Related Links
Custom Renderers
Creating an Effect
6 minutes to read • Edit Online

Download the sample


Effects simplify the customization of a control. This article demonstrates how to create an effect that changes the
background color of the Entry control when the control gains focus.
The process for creating an effect in each platform-specific project is as follows:
1. Create a subclass of the PlatformEffect class.
2. Override the OnAttached method and write logic to customize the control.
3. Override the OnDetached method and write logic to clean up the control customization, if required.
4. Add a ResolutionGroupName attribute to the effect class. This attribute sets a company wide namespace for
effects, preventing collisions with other effects with the same name. Note that this attribute can only be applied
once per project.
5. Add an ExportEffect attribute to the effect class. This attribute registers the effect with a unique ID that's used
by Xamarin.Forms, along with the group name, to locate the effect prior to applying it to a control. The attribute
takes two parameters – the type name of the effect, and a unique string that will be used to locate the effect
prior to applying it to a control.
The effect can then be consumed by attaching it to the appropriate control.

NOTE
It's optional to provide an effect in each platform project. Attempting to use an effect when one isn't registered will return a
non-null value that does nothing.

The sample application demonstrates a FocusEffect that changes the background color of a control when it gains
focus. The following diagram illustrates the responsibilities of each project in the sample application, along with
the relationships between them:

An Entrycontrol on the HomePage is customized by the FocusEffect class in each platform-specific project. Each
FocusEffect class derives from the PlatformEffect class for each platform. This results in the Entry control
being rendered with a platform-specific background color, which changes when the control gains focus, as shown
in the following screenshots:
Creating the Effect on Each Platform
The following sections discuss the platform-specific implementation of the FocusEffect class.

iOS Project
The following code example shows the FocusEffect implementation for the iOS project:
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(EffectsDemo.iOS.FocusEffect), nameof(EffectsDemo.iOS.FocusEffect))]
namespace EffectsDemo.iOS
{
public class FocusEffect : PlatformEffect
{
UIColor backgroundColor;

protected override void OnAttached ()


{
try {
Control.BackgroundColor = backgroundColor = UIColor.FromRGB (204, 153, 255);
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}

protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged (args);

try {
if (args.PropertyName == "IsFocused") {
if (Control.BackgroundColor == backgroundColor) {
Control.BackgroundColor = UIColor.White;
} else {
Control.BackgroundColor = backgroundColor;
}
}
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}
}
}

The OnAttachedmethod sets the BackgroundColor property of the control to light purple with the
UIColor.FromRGB method, and also stores this color in a field. This functionality is wrapped in a try / catch block
in case the control the effect is attached to does not have a BackgroundColor property. No implementation is
provided by the OnDetached method because no cleanup is necessary.
The OnElementPropertyChanged override responds to bindable property changes on the Xamarin.Forms control.
When the IsFocused property changes, the BackgroundColor property of the control is changed to white if the
control has focus, otherwise it's changed to light purple. This functionality is wrapped in a try / catch block in
case the control the effect is attached to does not have a BackgroundColor property.

Android Project
The following code example shows the FocusEffect implementation for the Android project:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(EffectsDemo.Droid.FocusEffect), nameof(EffectsDemo.Droid.FocusEffect))]
namespace EffectsDemo.Droid
{
public class FocusEffect : PlatformEffect
{
Android.Graphics.Color originalBackgroundColor = new Android.Graphics.Color(0, 0, 0, 0);
Android.Graphics.Color backgroundColor;

protected override void OnAttached()


{
try
{
backgroundColor = Android.Graphics.Color.LightGreen;
Control.SetBackgroundColor(backgroundColor);
}
catch (Exception ex)
{
Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached()


{
}

protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(args);
try
{
if (args.PropertyName == "IsFocused")
{
if (((Android.Graphics.Drawables.ColorDrawable)Control.Background).Color ==
backgroundColor)
{
Control.SetBackgroundColor(originalBackgroundColor);
}
else
{
Control.SetBackgroundColor(backgroundColor);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}
}
}

The OnAttached method calls the SetBackgroundColor method to set the background color of the control to light
green, and also stores this color in a field. This functionality is wrapped in a try / catch block in case the control
the effect is attached to does not have a SetBackgroundColor property. No implementation is provided by the
OnDetached method because no cleanup is necessary.

The OnElementPropertyChanged override responds to bindable property changes on the Xamarin.Forms control.
When the IsFocused property changes, the background color of the control is changed to white if the control has
focus, otherwise it's changed to light green. This functionality is wrapped in a try / catch block in case the
control the effect is attached to does not have a BackgroundColor property.

Universal Windows Platform Projects


The following code example shows the FocusEffect implementation for Universal Windows Platform (UWP )
projects:

using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;

[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(EffectsDemo.UWP.FocusEffect), nameof(EffectsDemo.UWP.FocusEffect))]
namespace EffectsDemo.UWP
{
public class FocusEffect : PlatformEffect
{
protected override void OnAttached()
{
try
{
(Control as Windows.UI.Xaml.Controls.Control).Background = new SolidColorBrush(Colors.Cyan);
(Control as FormsTextBox).BackgroundFocusBrush = new SolidColorBrush(Colors.White);
}
catch (Exception ex)
{
Debug.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached()


{
}
}
}

The OnAttached method sets the Background property of the control to cyan, and sets the BackgroundFocusBrush
property to white. This functionality is wrapped in a try / catch block in case the control the effect is attached to
lacks these properties. No implementation is provided by the OnDetached method because no cleanup is
necessary.

Consuming the Effect


The process for consuming an effect from a Xamarin.Forms .NET Standard library or Shared Library project is as
follows:
1. Declare a control that will be customized by the effect.
2. Attach the effect to the control by adding it to the control's Effects collection.

NOTE
An effect instance can only be attached to a single control. Therefore, an effect must be resolved twice to use it on two
controls.

Consuming the Effect in XAML


The following XAML code example shows an Entry control to which the FocusEffect is attached:
<Entry Text="Effect attached to an Entry" ...>
<Entry.Effects>
<local:FocusEffect />
</Entry.Effects>
...
</Entry>

The FocusEffect class in the .NET Standard library supports effect consumption in XAML, and is shown in the
following code example:

public class FocusEffect : RoutingEffect


{
public FocusEffect () : base ($"MyCompany.{nameof(FocusEffect)}")
{
}
}

The FocusEffect class subclasses the RoutingEffect class, which represents a platform-independent effect that
wraps an inner effect that is usually platform-specific. The FocusEffect class calls the base class constructor,
passing in a parameter consisting of a concatenation of the resolution group name (specified using the
ResolutionGroupName attribute on the effect class), and the unique ID that was specified using the ExportEffect
attribute on the effect class. Therefore, when the Entry is initialized at runtime, a new instance of the
MyCompany.FocusEffect is added to the control's Effects collection.

Effects can also be attached to controls by using a behavior, or by using attached properties. For more information
about attaching an effect to a control by using a behavior, see Reusable EffectBehavior. For more information
about attaching an effect to a control by using attached properties, see Passing Parameters to an Effect.

Consuming the Effect in C#


The equivalent Entry in C# is shown in the following code example:

var entry = new Entry {


Text = "Effect attached to an Entry",
...
};

The FocusEffect is attached to the Entry instance by adding the effect to the control's Effects collection, as
demonstrated in the following code example:

public HomePageCS ()
{
...
entry.Effects.Add (Effect.Resolve ($"MyCompany.{nameof(FocusEffect)}"));
...
}

The Effect.Resolve returns an Effect for the specified name, which is a concatenation of the resolution group
name (specified using the ResolutionGroupName attribute on the effect class), and the unique ID that was specified
using the ExportEffect attribute on the effect class. If a platform doesn't provide the effect, the Effect.Resolve
method will return a non- null value.

Summary
This article demonstrated how to create an effect that changes the background color of the Entry control when
the control gains focus.

Related Links
Custom Renderers
Effect
PlatformEffect
Background Color Effect (sample)
Focus Effect (sample)
Passing Parameters to an Effect
2 minutes to read • Edit Online

Effect parameters can be defined by properties, enabling the effect to be reused. Parameters can then be passed to
the effect by specifying values for each property when instantiating the effect.

Passing Effect Parameters as Common Language Runtime Properties


Common Language Runtime (CLR ) properties can be used to define effect parameters that don't respond to
runtime property changes. This article demonstrates using CLR properties to pass parameters to an effect.

Passing Effect Parameters as Attached Properties


Attached properties can be used to define effect parameters that respond to runtime property changes. This article
demonstrates using attached properties to pass parameters to an effect, and changing a parameter at runtime.
Passing Effect Parameters as Common Language
Runtime Properties
5 minutes to read • Edit Online

Download the sample


Common Language Runtime (CLR ) properties can be used to define effect parameters that don't respond to
runtime property changes. This article demonstrates using CLR properties to pass parameters to an effect.
The process for creating effect parameters that don't respond to runtime property changes is as follows:
1. Create a public class that subclasses the RoutingEffect class. The RoutingEffect class represents a platform-
independent effect that wraps an inner effect that is usually platform-specific.
2. Create a constructor that calls the base class constructor, passing in a concatenation of the resolution group
name, and the unique ID that was specified on each platform-specific effect class.
3. Add properties to the class for each parameter to be passed to the effect.
Parameters can then be passed to the effect by specifying values for each property when instantiating the effect.
The sample application demonstrates a ShadowEffect that adds a shadow to the text displayed by a Label control.
The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationships between them:

A Label control on the HomePage is customized by the LabelShadowEffect in each platform-specific project.
Parameters are passed to each LabelShadowEffect through properties in the ShadowEffect class. Each
LabelShadowEffect class derives from the PlatformEffect class for each platform. This results in a shadow being
added to the text displayed by the Label control, as shown in the following screenshots:

Creating Effect Parameters


A public class that subclasses the RoutingEffect class should be created to represent effect parameters, as
demonstrated in the following code example:
public class ShadowEffect : RoutingEffect
{
public float Radius { get; set; }

public Color Color { get; set; }

public float DistanceX { get; set; }

public float DistanceY { get; set; }

public ShadowEffect () : base ("MyCompany.LabelShadowEffect")


{
}
}

The ShadowEffect contains four properties that represent parameters to be passed to each platform-specific
LabelShadowEffect . The class constructor calls the base class constructor, passing in a parameter consisting of a
concatenation of the resolution group name, and the unique ID that was specified on each platform-specific effect
class. Therefore, a new instance of the MyCompany.LabelShadowEffect will be added to a control's Effects collection
when a ShadowEffect is instantiated.

Consuming the Effect


The following XAML code example shows a Label control to which the ShadowEffect is attached:

<Label Text="Label Shadow Effect" ...>


<Label.Effects>
<local:ShadowEffect Radius="5" DistanceX="5" DistanceY="5">
<local:ShadowEffect.Color>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="Black" />
<On Platform="Android" Value="White" />
<On Platform="UWP" Value="Red" />
</OnPlatform>
</local:ShadowEffect.Color>
</local:ShadowEffect>
</Label.Effects>
</Label>

The equivalent Label in C# is shown in the following code example:


var label = new Label {
Text = "Label Shadow Effect",
...
};

Color color = Color.Default;


switch (Device.RuntimePlatform)
{
case Device.iOS:
color = Color.Black;
break;
case Device.Android:
color = Color.White;
break;
case Device.UWP:
color = Color.Red;
break;
}

label.Effects.Add (new ShadowEffect {


Radius = 5,
Color = color,
DistanceX = 5,
DistanceY = 5
});

In both code examples, an instance of the ShadowEffect class is instantiated with values being specified for each
property, before being added to the control's Effects collection. Note that the ShadowEffect.Color property uses
platform-specific color values. For more information, see Device Class.

Creating the Effect on each Platform


The following sections discuss the platform-specific implementation of the LabelShadowEffect class.
iOS Project
The following code example shows the LabelShadowEffect implementation for the iOS project:
[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.iOS
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached ()
{
try {
var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
if (effect != null) {
Control.Layer.CornerRadius = effect.Radius;
Control.Layer.ShadowColor = effect.Color.ToCGColor ();
Control.Layer.ShadowOffset = new CGSize (effect.DistanceX, effect.DistanceY);
Control.Layer.ShadowOpacity = 1.0f;
}
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
}
}

The OnAttached method retrieves the ShadowEffect instance, and sets Control.Layer properties to the specified
property values to create the shadow. This functionality is wrapped in a try / catch block in case the control that
the effect is attached to does not have the Control.Layer properties. No implementation is provided by the
OnDetached method because no cleanup is necessary.

Android Project
The following code example shows the LabelShadowEffect implementation for the Android project:

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.Droid
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached ()
{
try {
var control = Control as Android.Widget.TextView;
var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
if (effect != null) {
float radius = effect.Radius;
float distanceX = effect.DistanceX;
float distanceY = effect.DistanceY;
Android.Graphics.Color color = effect.Color.ToAndroid ();
control.SetShadowLayer (radius, distanceX, distanceY, color);
}
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
}
}
The OnAttached method retrieves the ShadowEffect instance, and calls the TextView.SetShadowLayer method to
create a shadow using the specified property values. This functionality is wrapped in a try / catch block in case
the control that the effect is attached to does not have the Control.Layer properties. No implementation is
provided by the OnDetached method because no cleanup is necessary.
Universal Windows Platform Project
The following code example shows the LabelShadowEffect implementation for the Universal Windows Platform
(UWP ) project:

[assembly: ResolutionGroupName ("Xamarin")]


[assembly: ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.UWP
{
public class LabelShadowEffect : PlatformEffect
{
bool shadowAdded = false;

protected override void OnAttached ()


{
try {
if (!shadowAdded) {
var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
if (effect != null) {
var textBlock = Control as Windows.UI.Xaml.Controls.TextBlock;
var shadowLabel = new Label ();
shadowLabel.Text = textBlock.Text;
shadowLabel.FontAttributes = FontAttributes.Bold;
shadowLabel.HorizontalOptions = LayoutOptions.Center;
shadowLabel.VerticalOptions = LayoutOptions.CenterAndExpand;
shadowLabel.TextColor = effect.Color;
shadowLabel.TranslationX = effect.DistanceX;
shadowLabel.TranslationY = effect.DistanceY;

((Grid)Element.Parent).Children.Insert (0, shadowLabel);


shadowAdded = true;
}
}
} catch (Exception ex) {
Debug.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
}
}

The Universal Windows Platform doesn't provide a shadow effect, and so the LabelShadowEffect implementation
on both platforms simulates one by adding a second offset Label behind the primary Label . The OnAttached
method retrieves the ShadowEffect instance, creates the new Label , and sets some layout properties on the
Label . It then creates the shadow by setting the TextColor , TranslationX , and TranslationY properties to
control the color and location of the Label . The shadowLabel is then inserted offset behind the primary Label .
This functionality is wrapped in a try / catch block in case the control that the effect is attached to does not have
the Control.Layer properties. No implementation is provided by the OnDetached method because no cleanup is
necessary.

Summary
This article has demonstrated using CLR properties to pass parameters to an effect. CLR properties can be used to
define effect parameters that don't respond to runtime property changes.

Related Links
Custom Renderers
Effect
PlatformEffect
RoutingEffect
Shadow Effect (sample)
Passing Effect Parameters as Attached Properties
10 minutes to read • Edit Online

Download the sample


Attached properties can be used to define effect parameters that respond to runtime property changes. This article
demonstrates using attached properties to pass parameters to an effect, and changing a parameter at runtime.
The process for creating effect parameters that respond to runtime property changes is as follows:
1. Create a static class that contains an attached property for each parameter to be passed to the effect.
2. Add an additional attached property to the class that will be used to control the addition or removal of the
effect to the control that the class will be attached to. Ensure that this attached property registers a
propertyChanged delegate that will be executed when the value of the property changes.
3. Create static getters and setters for each attached property.
4. Implement logic in the propertyChanged delegate to add and remove the effect.
5. Implement a nested class inside the static class, named after the effect, which subclasses the RoutingEffect
class. For the constructor, call the base class constructor, passing in a concatenation of the resolution group
name, and the unique ID that was specified on each platform-specific effect class.
Parameters can then be passed to the effect by adding the attached properties, and property values, to the
appropriate control. In addition, parameters can be changed at runtime by specifying a new attached property
value.

NOTE
An attached property is a special type of bindable property, defined in one class but attached to other objects, and
recognizable in XAML as attributes that contain a class and a property name separated by a period. For more information,
see Attached Properties.

The sample application demonstrates a ShadowEffect that adds a shadow to the text displayed by a Label control.
In addition, the color of the shadow can be changed at runtime. The following diagram illustrates the
responsibilities of each project in the sample application, along with the relationships between them:

A Label control on the HomePage is customized by the LabelShadowEffect in each platform-specific project.
Parameters are passed to each LabelShadowEffect through attached properties in the ShadowEffect class. Each
LabelShadowEffect class derives from the PlatformEffect class for each platform. This results in a shadow being
added to the text displayed by the Label control, as shown in the following screenshots:
Creating Effect Parameters
A static class should be created to represent effect parameters, as demonstrated in the following code example:

public static class ShadowEffect


{
public static readonly BindableProperty HasShadowProperty =
BindableProperty.CreateAttached ("HasShadow", typeof(bool), typeof(ShadowEffect), false, propertyChanged:
OnHasShadowChanged);
public static readonly BindableProperty ColorProperty =
BindableProperty.CreateAttached ("Color", typeof(Color), typeof(ShadowEffect), Color.Default);
public static readonly BindableProperty RadiusProperty =
BindableProperty.CreateAttached ("Radius", typeof(double), typeof(ShadowEffect), 1.0);
public static readonly BindableProperty DistanceXProperty =
BindableProperty.CreateAttached ("DistanceX", typeof(double), typeof(ShadowEffect), 0.0);
public static readonly BindableProperty DistanceYProperty =
BindableProperty.CreateAttached ("DistanceY", typeof(double), typeof(ShadowEffect), 0.0);

public static bool GetHasShadow (BindableObject view)


{
return (bool)view.GetValue (HasShadowProperty);
}

public static void SetHasShadow (BindableObject view, bool value)


{
view.SetValue (HasShadowProperty, value);
}
...

static void OnHasShadowChanged (BindableObject bindable, object oldValue, object newValue)


{
var view = bindable as View;
if (view == null) {
return;
}

bool hasShadow = (bool)newValue;


if (hasShadow) {
view.Effects.Add (new LabelShadowEffect ());
} else {
var toRemove = view.Effects.FirstOrDefault (e => e is LabelShadowEffect);
if (toRemove != null) {
view.Effects.Remove (toRemove);
}
}
}

class LabelShadowEffect : RoutingEffect


{
public LabelShadowEffect () : base ("MyCompany.LabelShadowEffect")
{
}
}
}

The ShadowEffect contains five attached properties, with static getters and setters for each attached property.
Four of these properties represent parameters to be passed to each platform-specific LabelShadowEffect . The
ShadowEffect class also defines a HasShadow attached property that is used to control the addition or removal of
the effect to the control that the ShadowEffect class is attached to. This attached property registers the
OnHasShadowChanged method that will be executed when the value of the property changes. This method adds or
removes the effect based on the value of the HasShadow attached property.
The nested LabelShadowEffect class, which subclasses the RoutingEffect class, supports effect addition and
removal. The RoutingEffect class represents a platform-independent effect that wraps an inner effect that is
usually platform-specific. This simplifies the effect removal process, since there is no compile-time access to the
type information for a platform-specific effect. The LabelShadowEffect constructor calls the base class constructor,
passing in a parameter consisting of a concatenation of the resolution group name, and the unique ID that was
specified on each platform-specific effect class. This enables effect addition and removal in the OnHasShadowChanged
method, as follows:
Effect addition – a new instance of the LabelShadowEffect is added to the control's Effects collection. This
replaces using the Effect.Resolve method to add the effect.
Effect removal – the first instance of the LabelShadowEffect in the control's Effects collection is retrieved
and removed.

Consuming the Effect


Each platform-specific LabelShadowEffect can be consumed by adding the attached properties to a Label control,
as demonstrated in the following XAML code example:

<Label Text="Label Shadow Effect" ...


local:ShadowEffect.HasShadow="true" local:ShadowEffect.Radius="5"
local:ShadowEffect.DistanceX="5" local:ShadowEffect.DistanceY="5">
<local:ShadowEffect.Color>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="Black" />
<On Platform="Android" Value="White" />
<On Platform="UWP" Value="Red" />
</OnPlatform>
</local:ShadowEffect.Color>
</Label>

The equivalent Label in C# is shown in the following code example:


var label = new Label {
Text = "Label Shadow Effect",
...
};

Color color = Color.Default;


switch (Device.RuntimePlatform)
{
case Device.iOS:
color = Color.Black;
break;
case Device.Android:
color = Color.White;
break;
case Device.UWP:
color = Color.Red;
break;
}

ShadowEffect.SetHasShadow (label, true);


ShadowEffect.SetRadius (label, 5);
ShadowEffect.SetDistanceX (label, 5);
ShadowEffect.SetDistanceY (label, 5);
ShadowEffect.SetColor (label, color));

Setting the ShadowEffect.HasShadow attached property to true executes the ShadowEffect.OnHasShadowChanged


method that adds or removes the LabelShadowEffect to the Label control. In both code examples, the
ShadowEffect.Color attached property provides platform -specific color values. For more information, see Device
Class.
In addition, a Button allows the shadow color to be changed at runtime. When the Button is clicked, the following
code changes the shadow color by setting the ShadowEffect.Color attached property:

ShadowEffect.SetColor (label, Color.Teal);

Consuming the Effect with a Style


Effects that can be consumed by adding attached properties to a control can also be consumed by a style. The
following XAML code example shows an explicit style for the shadow effect, that can be applied to Label controls:

<Style x:Key="ShadowEffectStyle" TargetType="Label">


<Style.Setters>
<Setter Property="local:ShadowEffect.HasShadow" Value="True" />
<Setter Property="local:ShadowEffect.Radius" Value="5" />
<Setter Property="local:ShadowEffect.DistanceX" Value="5" />
<Setter Property="local:ShadowEffect.DistanceY" Value="5" />
</Style.Setters>
</Style>

The Stylecan be applied to a Label by setting its Style property to the Style instance using the
StaticResource markup extension, as demonstrated in the following code example:

<Label Text="Label Shadow Effect" ... Style="{StaticResource ShadowEffectStyle}" />

For more information about styles, see Styles.

Creating the Effect on each Platform


The following sections discuss the platform-specific implementation of the LabelShadowEffect class.
iOS Project
The following code example shows the LabelShadowEffect implementation for the iOS project:

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.iOS
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached ()
{
try {
UpdateRadius ();
UpdateColor ();
UpdateOffset ();
Control.Layer.ShadowOpacity = 1.0f;
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
...

void UpdateRadius ()
{
Control.Layer.CornerRadius = (nfloat)ShadowEffect.GetRadius (Element);
}

void UpdateColor ()
{
Control.Layer.ShadowColor = ShadowEffect.GetColor (Element).ToCGColor ();
}

void UpdateOffset ()
{
Control.Layer.ShadowOffset = new CGSize (
(double)ShadowEffect.GetDistanceX (Element),
(double)ShadowEffect.GetDistanceY (Element));
}
}

The OnAttached method calls methods that retrieve the attached property values using the ShadowEffect getters,
and which set Control.Layer properties to the property values to create the shadow. This functionality is wrapped
in a try / catch block in case the control that the effect is attached to does not have the Control.Layer properties.
No implementation is provided by the OnDetached method because no cleanup is necessary.
Responding to Property Changes
If any of the ShadowEffect attached property values change at runtime, the effect needs to respond by displaying
the changes. An overridden version of the OnElementPropertyChanged method, in the platform-specific effect class,
is the place to respond to bindable property changes, as demonstrated in the following code example:
public class LabelShadowEffect : PlatformEffect
{
...
protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
{
if (args.PropertyName == ShadowEffect.RadiusProperty.PropertyName) {
UpdateRadius ();
} else if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
UpdateColor ();
} else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
UpdateOffset ();
}
}
...
}

The OnElementPropertyChanged method updates the radius, color, or offset of the shadow, provided that the
appropriate ShadowEffect attached property value has changed. A check for the property that's changed should
always be made, as this override can be called many times.
Android Project
The following code example shows the LabelShadowEffect implementation for the Android project:
[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.Droid
{
public class LabelShadowEffect : PlatformEffect
{
Android.Widget.TextView control;
Android.Graphics.Color color;
float radius, distanceX, distanceY;

protected override void OnAttached ()


{
try {
control = Control as Android.Widget.TextView;
UpdateRadius ();
UpdateColor ();
UpdateOffset ();
UpdateControl ();
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
...

void UpdateControl ()
{
if (control != null) {
control.SetShadowLayer (radius, distanceX, distanceY, color);
}
}

void UpdateRadius ()
{
radius = (float)ShadowEffect.GetRadius (Element);
}

void UpdateColor ()
{
color = ShadowEffect.GetColor (Element).ToAndroid ();
}

void UpdateOffset ()
{
distanceX = (float)ShadowEffect.GetDistanceX (Element);
distanceY = (float)ShadowEffect.GetDistanceY (Element);
}
}

The OnAttached method calls methods that retrieve the attached property values using the ShadowEffect getters,
and calls a method that calls the TextView.SetShadowLayer method to create a shadow using the property values.
This functionality is wrapped in a try / catch block in case the control that the effect is attached to does not have
the Control.Layer properties. No implementation is provided by the OnDetached method because no cleanup is
necessary.
Responding to Property Changes
If any of the ShadowEffect attached property values change at runtime, the effect needs to respond by displaying
the changes. An overridden version of the OnElementPropertyChanged method, in the platform-specific effect class,
is the place to respond to bindable property changes, as demonstrated in the following code example:
public class LabelShadowEffect : PlatformEffect
{
...
protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
{
if (args.PropertyName == ShadowEffect.RadiusProperty.PropertyName) {
UpdateRadius ();
UpdateControl ();
} else if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
UpdateColor ();
UpdateControl ();
} else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
UpdateOffset ();
UpdateControl ();
}
}
...
}

The OnElementPropertyChanged method updates the radius, color, or offset of the shadow, provided that the
appropriate ShadowEffect attached property value has changed. A check for the property that's changed should
always be made, as this override can be called many times.
Universal Windows Platform Project
The following code example shows the LabelShadowEffect implementation for the Universal Windows Platform
(UWP ) project:
[assembly: ResolutionGroupName ("MyCompany")]
[assembly: ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.UWP
{
public class LabelShadowEffect : PlatformEffect
{
Label shadowLabel;
bool shadowAdded = false;

protected override void OnAttached ()


{
try {
if (!shadowAdded) {
var textBlock = Control as Windows.UI.Xaml.Controls.TextBlock;

shadowLabel = new Label ();


shadowLabel.Text = textBlock.Text;
shadowLabel.FontAttributes = FontAttributes.Bold;
shadowLabel.HorizontalOptions = LayoutOptions.Center;
shadowLabel.VerticalOptions = LayoutOptions.CenterAndExpand;

UpdateColor ();
UpdateOffset ();

((Grid)Element.Parent).Children.Insert (0, shadowLabel);


shadowAdded = true;
}
} catch (Exception ex) {
Debug.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
...

void UpdateColor ()
{
shadowLabel.TextColor = ShadowEffect.GetColor (Element);
}

void UpdateOffset ()
{
shadowLabel.TranslationX = ShadowEffect.GetDistanceX (Element);
shadowLabel.TranslationY = ShadowEffect.GetDistanceY (Element);
}
}
}

The Universal Windows Platform doesn't provide a shadow effect, and so the LabelShadowEffect implementation
on both platforms simulates one by adding a second offset Label behind the primary Label . The OnAttached
method creates the new Label and sets some layout properties on the Label . It then calls methods that retrieve
the attached property values using the ShadowEffect getters, and creates the shadow by setting the TextColor ,
TranslationX , and TranslationY properties to control the color and location of the Label . The shadowLabel is
then inserted offset behind the primary Label . This functionality is wrapped in a try / catch block in case the
control that the effect is attached to does not have the Control.Layer properties. No implementation is provided
by the OnDetached method because no cleanup is necessary.
Responding to Property Changes
If any of the ShadowEffect attached property values change at runtime, the effect needs to respond by displaying
the changes. An overridden version of the OnElementPropertyChanged method, in the platform-specific effect class,
is the place to respond to bindable property changes, as demonstrated in the following code example:
public class LabelShadowEffect : PlatformEffect
{
...
protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
{
if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
UpdateColor ();
} else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
UpdateOffset ();
}
}
...
}

The OnElementPropertyChanged method updates the color or offset of the shadow, provided that the appropriate
ShadowEffect attached property value has changed. A check for the property that's changed should always be
made, as this override can be called many times.

Summary
This article has demonstrated using attached properties to pass parameters to an effect, and changing a parameter
at runtime. Attached properties can be used to define effect parameters that respond to runtime property changes.

Related Links
Custom Renderers
Effect
PlatformEffect
RoutingEffect
Shadow Effect (sample)
Invoking Events from Effects
21 minutes to read • Edit Online

Download the sample


An effect can define and invoke an event, signaling changes in the underlying native view. This article shows how
to implement low -level multi-touch finger tracking, and how to generate events that signal touch activity.
The effect described in this article provides access to low -level touch events. These low -level events are not
available through the existing GestureRecognizer classes, but they are vital to some types of applications. For
example, a finger-paint application needs to track individual fingers as they move on the screen. A music keyboard
needs to detect taps and releases on the individual keys, as well as a finger gliding from one key to another in a
glissando.
An effect is ideal for multi-touch finger tracking because it can be attached to any Xamarin.Forms element.

Platform Touch Events


The iOS, Android, and Universal Windows Platform all include a low -level API that allows applications to detect
touch activity. These platforms all distinguish between three basic types of touch events:
Pressed, when a finger touches the screen
Moved, when a finger touching the screen moves
Released, when the finger is released from the screen
In a multi-touch environment, multiple fingers can touch the screen at the same time. The various platforms
include an identification (ID ) number that applications can use to distinguish between multiple fingers.
In iOS, the UIView class defines three overridable methods, TouchesBegan , TouchesMoved , and TouchesEnded
corresponding to these three basic events. The article Multi-Touch Finger Tracking describes how to use these
methods. However, an iOS program does not need to override a class that derives from UIView to use these
methods. The iOS UIGestureRecognizer also defines these same three methods, and you can attach an instance of
a class that derives from UIGestureRecognizer to any UIView object.
In Android, the View class defines an overridable method named OnTouchEvent to process all the touch activity.
The type of the touch activity is defined by enumeration members Down , PointerDown , Move , Up , and PointerUp
as described in the article Multi-Touch Finger Tracking. The Android View also defines an event named Touch
that allows an event handler to be attached to any View object.
In the Universal Windows Platform (UWP ), the UIElement class defines events named PointerPressed ,
PointerMoved , and PointerReleased . These are described in the article Handle Pointer Input article on MSDN and
the API documentation for the UIElement class.
The Pointer API in the Universal Windows Platform is intended to unify mouse, touch, and pen input. For that
reason, the PointerMoved event is invoked when the mouse moves across an element even when a mouse button
is not pressed. The PointerRoutedEventArgs object that accompanies these events has a property named Pointer
that has a property named IsInContact which indicates if a mouse button is pressed or a finger is in contact with
the screen.
In addition, the UWP defines two more events named PointerEntered and PointerExited . These indicate when a
mouse or finger moves from one element to another. For example, consider two adjacent elements named A and
B. Both elements have installed handlers for the pointer events. When a finger presses on A, the PointerPressed
event is invoked. As the finger moves, A invokes PointerMoved events. If the finger moves from A to B, A invokes a
PointerExited event and B invokes a PointerEntered event. If the finger is then released, B invokes a
PointerReleased event.

The iOS and Android platforms are different from the UWP: The view that first gets the call to TouchesBegan or
OnTouchEvent when a finger touches the view continues to get all the touch activity even if the finger moves to
different views. The UWP can behave similarly if the application captures the pointer: In the PointerEntered event
handler, the element calls CapturePointer and then gets all touch activity from that finger.
The UWP approach proves to be very useful for some types of applications, for example, a music keyboard. Each
key can handle the touch events for that key and detect when a finger has slid from one key to another using the
PointerEntered and PointerExited events.

For that reason, the touch-tracking effect described in this article implements the UWP approach.

The Touch-Tracking Effect API


The Touch Tracking Effect Demos sample contains the classes (and an enumeration) that implement the low -
level touch-tracking. These types belong to the namespace TouchTracking and begin with the word Touch . The
TouchTrackingEffectDemos .NET Standard library project includes the TouchActionType enumeration for the
type of touch events:

public enum TouchActionType


{
Entered,
Pressed,
Moved,
Released,
Exited,
Cancelled
}

All the platforms also include an event that indicates that the touch event has been cancelled.
The TouchEffect class in the .NET Standard library derives from RoutingEffect and defines an event named
TouchAction and a method named OnTouchAction that invokes the TouchAction event:

public class TouchEffect : RoutingEffect


{
public event TouchActionEventHandler TouchAction;

public TouchEffect() : base("XamarinDocs.TouchEffect")


{
}

public bool Capture { set; get; }

public void OnTouchAction(Element element, TouchActionEventArgs args)


{
TouchAction?.Invoke(element, args);
}
}

Also notice the Capture property. To capture touch events, an application must set this property to true prior to
a Pressed event. Otherwise, the touch events behave like those in the Universal Windows Platform.
The TouchActionEventArgs class in the .NET Standard library contains all the information that accompanies each
event:
public class TouchActionEventArgs : EventArgs
{
public TouchActionEventArgs(long id, TouchActionType type, Point location, bool isInContact)
{
Id = id;
Type = type;
Location = location;
IsInContact = isInContact;
}

public long Id { private set; get; }

public TouchActionType Type { private set; get; }

public Point Location { private set; get; }

public bool IsInContact { private set; get; }


}

An application can use the Id property for tracking individual fingers. Notice the IsInContact property. This
property is always true for Pressed events and false for Released events. It's also always true for Moved
events on iOS and Android. The IsInContact property might be false for Moved events on the Universal
Windows Platform when the program is running on the desktop and the mouse pointer moves without a button
pressed.
You can use the TouchEffect class in your own applications by including the file in the solution's .NET Standard
library project, and by adding an instance to the Effects collection of any Xamarin.Forms element. Attach a
handler to the TouchAction event to obtain the touch events.
To use TouchEffect in your own application, you'll also need the platform implementations included in
TouchTrackingEffectDemos solution.

The Touch-Tracking Effect Implementations


The iOS, Android, and UWP implementations of the TouchEffect are described below beginning with the simplest
implementation (UWP ) and ending with the iOS implementation because it is more structurally complex than the
others.
The UWP Implementation
The UWP implementation of TouchEffect is the simplest. As usual, the class derives from PlatformEffect and
includes two assembly attributes:

[assembly: ResolutionGroupName("XamarinDocs")]
[assembly: ExportEffect(typeof(TouchTracking.UWP.TouchEffect), "TouchEffect")]

namespace TouchTracking.UWP
{
public class TouchEffect : PlatformEffect
{
...
}
}

The OnAttached override saves some information as fields and attaches handlers to all the pointer events:
public class TouchEffect : PlatformEffect
{
FrameworkElement frameworkElement;
TouchTracking.TouchEffect effect;
Action<Element, TouchActionEventArgs> onTouchAction;

protected override void OnAttached()


{
// Get the Windows FrameworkElement corresponding to the Element that the effect is attached to
frameworkElement = Control == null ? Container : Control;

// Get access to the TouchEffect class in the .NET Standard library


effect = (TouchTracking.TouchEffect)Element.Effects.
FirstOrDefault(e => e is TouchTracking.TouchEffect);

if (effect != null && frameworkElement != null)


{
// Save the method to call on touch events
onTouchAction = effect.OnTouchAction;

// Set event handlers on FrameworkElement


frameworkElement.PointerEntered += OnPointerEntered;
frameworkElement.PointerPressed += OnPointerPressed;
frameworkElement.PointerMoved += OnPointerMoved;
frameworkElement.PointerReleased += OnPointerReleased;
frameworkElement.PointerExited += OnPointerExited;
frameworkElement.PointerCanceled += OnPointerCancelled;
}
}
...
}

The OnPointerPressed handler invokes the effect event by calling the onTouchAction field in the CommonHandler
method:

public class TouchEffect : PlatformEffect


{
...
void OnPointerPressed(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Pressed, args);

// Check setting of Capture property


if (effect.Capture)
{
(sender as FrameworkElement).CapturePointer(args.Pointer);
}
}
...
void CommonHandler(object sender, TouchActionType touchActionType, PointerRoutedEventArgs args)
{
PointerPoint pointerPoint = args.GetCurrentPoint(sender as UIElement);
Windows.Foundation.Point windowsPoint = pointerPoint.Position;

onTouchAction(Element, new TouchActionEventArgs(args.Pointer.PointerId,


touchActionType,
new Point(windowsPoint.X, windowsPoint.Y),
args.Pointer.IsInContact));
}
}

OnPointerPressed also checks the value of the Capture property in the effect class in the .NET Standard library
and calls CapturePointer if it is true .
The other UWP event handlers are even simpler:

public class TouchEffect : PlatformEffect


{
...
void OnPointerEntered(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Entered, args);
}
...
}

The Android Implementation


The Android and iOS implementations are necessarily more complex because they must implement the Exited
and Entered events when a finger moves from one element to another. Both implementations are structured
similarly.
The Android TouchEffect class installs a handler for the Touch event:

view = Control == null ? Container : Control;


...
view.Touch += OnTouch;

The class also defines two static dictionaries:

public class TouchEffect : PlatformEffect


{
...
static Dictionary<Android.Views.View, TouchEffect> viewDictionary =
new Dictionary<Android.Views.View, TouchEffect>();

static Dictionary<int, TouchEffect> idToEffectDictionary =


new Dictionary<int, TouchEffect>();
...

The viewDictionary gets a new entry every time the OnAttached override is called:

viewDictionary.Add(view, this);

The entry is removed from the dictionary in OnDetached . Every instance of TouchEffect is associated with a
particular view that the effect is attached to. The static dictionary allows any TouchEffect instance to enumerate
through all the other views and their corresponding TouchEffect instances. This is necessary to allow for
transferring the events from one view to another.
Android assigns an ID code to touch events that allows an application to track individual fingers. The
idToEffectDictionary associates this ID code with a TouchEffect instance. An item is added to this dictionary
when the Touch handler is called for a finger press:
void OnTouch(object sender, Android.Views.View.TouchEventArgs args)
{
...
switch (args.Event.ActionMasked)
{
case MotionEventActions.Down:
case MotionEventActions.PointerDown:
FireEvent(this, id, TouchActionType.Pressed, screenPointerCoords, true);

idToEffectDictionary.Add(id, this);

capture = libTouchEffect.Capture;
break;

The item is removed from the idToEffectDictionary when the finger is released from the screen. The FireEvent
method simply accumulates all the information necessary to call the OnTouchAction method:

void FireEvent(TouchEffect touchEffect, int id, TouchActionType actionType, Point pointerLocation, bool
isInContact)
{
// Get the method to call for firing events
Action<Element, TouchActionEventArgs> onTouchAction = touchEffect.libTouchEffect.OnTouchAction;

// Get the location of the pointer within the view


touchEffect.view.GetLocationOnScreen(twoIntArray);
double x = pointerLocation.X - twoIntArray[0];
double y = pointerLocation.Y - twoIntArray[1];
Point point = new Point(fromPixels(x), fromPixels(y));

// Call the method


onTouchAction(touchEffect.formsElement,
new TouchActionEventArgs(id, actionType, point, isInContact));
}

All the other touch types are processed in two different ways: If the Capture property is true , the touch event is a
fairly simple translation to the TouchEffect information. It gets more complicated when Capture is false
because the touch events might need to be moved from one view to another. This is the responsibility of the
CheckForBoundaryHop method, which is called during move events. This method makes use of both static
dictionaries. It enumerates through the viewDictionary to determine the view that the finger is currently touching,
and it uses idToEffectDictionary to store the current TouchEffect instance (and hence, the current view )
associated with a particular ID:
void CheckForBoundaryHop(int id, Point pointerLocation)
{
TouchEffect touchEffectHit = null;

foreach (Android.Views.View view in viewDictionary.Keys)


{
// Get the view rectangle
try
{
view.GetLocationOnScreen(twoIntArray);
}
catch // System.ObjectDisposedException: Cannot access a disposed object.
{
continue;
}
Rectangle viewRect = new Rectangle(twoIntArray[0], twoIntArray[1], view.Width, view.Height);

if (viewRect.Contains(pointerLocation))
{
touchEffectHit = viewDictionary[view];
}
}

if (touchEffectHit != idToEffectDictionary[id])
{
if (idToEffectDictionary[id] != null)
{
FireEvent(idToEffectDictionary[id], id, TouchActionType.Exited, pointerLocation, true);
}
if (touchEffectHit != null)
{
FireEvent(touchEffectHit, id, TouchActionType.Entered, pointerLocation, true);
}
idToEffectDictionary[id] = touchEffectHit;
}
}

If there's been a change in the idToEffectDictionary , the method potentially calls FireEvent for Exited and
Entered to transfer from one view to another. However, the finger might have been moved to an area occupied by
a view without an attached TouchEffect , or from that area to a view with the effect attached.
Notice the try and catch block when the view is accessed. In a page that is navigated to that then navigates
back to the home page, the OnDetached method is not called and items remain in the viewDictionary but Android
considers them disposed.
The iOS Implementation
The iOS implementation is similar to the Android implementation except that the iOS TouchEffect class must
instantiate a derivative of UIGestureRecognizer . This is a class in the iOS project named TouchRecognizer . This
class maintains two static dictionaries that store TouchRecognizer instances:

static Dictionary<UIView, TouchRecognizer> viewDictionary =


new Dictionary<UIView, TouchRecognizer>();

static Dictionary<long, TouchRecognizer> idToTouchDictionary =


new Dictionary<long, TouchRecognizer>();

Much of the structure of this TouchRecognizer class is similar to the Android TouchEffect class.
IMPORTANT
Many of the views in do not have touch enabled by default. Touch can be enabled by adding
UIKit
view.UserInteractionEnabled = true; to the OnAttached override in the TouchEffect class in the iOS project. This
should occur after the UIView is obtained that corresponds to the element the effect is attached to.

Putting the Touch Effect to Work


The TouchTrackingEffectDemos program contains five pages that test the touch-tracking effect for common
tasks.
The BoxView Dragging page allows you to add BoxView elements to an AbsoluteLayout and then drag them
around the screen. The XAML file instantiates two Button views for adding BoxView elements to the
AbsoluteLayout and clearing the AbsoluteLayout .

The method in the code-behind file that adds a new BoxView to the AbsoluteLayout also adds a TouchEffect
object to the BoxView and attaches an event handler to the effect:

void AddBoxViewToLayout()
{
BoxView boxView = new BoxView
{
WidthRequest = 100,
HeightRequest = 100,
Color = new Color(random.NextDouble(),
random.NextDouble(),
random.NextDouble())
};

TouchEffect touchEffect = new TouchEffect();


touchEffect.TouchAction += OnTouchEffectAction;
boxView.Effects.Add(touchEffect);
absoluteLayout.Children.Add(boxView);
}

The TouchAction event handler processes all the touch events for all the BoxView elements, but it needs to
exercise some caution: It can't allow two fingers on a single BoxView because the program only implements
dragging, and the two fingers would interfere with each other. For this reason, the page defines an embedded class
for each finger currently being tracked:

class DragInfo
{
public DragInfo(long id, Point pressPoint)
{
Id = id;
PressPoint = pressPoint;
}

public long Id { private set; get; }

public Point PressPoint { private set; get; }


}

Dictionary<BoxView, DragInfo> dragDictionary = new Dictionary<BoxView, DragInfo>();

The dragDictionary contains an entry for every BoxView currently being dragged.
The Pressed touch action adds an item to this dictionary, and the Released action removes it. The Pressed logic
must check if there's already an item in the dictionary for that BoxView . If so, the BoxView is already being
dragged and the new event is a second finger on that same BoxView . For the Moved and Released actions, the
event handler must check if the dictionary has an entry for that BoxView and that the touch Id property for that
dragged BoxView matches the one in the dictionary entry:

void OnTouchEffectAction(object sender, TouchActionEventArgs args)


{
BoxView boxView = sender as BoxView;

switch (args.Type)
{
case TouchActionType.Pressed:
// Don't allow a second touch on an already touched BoxView
if (!dragDictionary.ContainsKey(boxView))
{
dragDictionary.Add(boxView, new DragInfo(args.Id, args.Location));

// Set Capture property to true


TouchEffect touchEffect = (TouchEffect)boxView.Effects.FirstOrDefault(e => e is TouchEffect);
touchEffect.Capture = true;
}
break;

case TouchActionType.Moved:
if (dragDictionary.ContainsKey(boxView) && dragDictionary[boxView].Id == args.Id)
{
Rectangle rect = AbsoluteLayout.GetLayoutBounds(boxView);
Point initialLocation = dragDictionary[boxView].PressPoint;
rect.X += args.Location.X - initialLocation.X;
rect.Y += args.Location.Y - initialLocation.Y;
AbsoluteLayout.SetLayoutBounds(boxView, rect);
}
break;

case TouchActionType.Released:
if (dragDictionary.ContainsKey(boxView) && dragDictionary[boxView].Id == args.Id)
{
dragDictionary.Remove(boxView);
}
break;
}
}

The Pressed logic sets the Capture property of the TouchEffect object to true . This has the effect of delivering
all subsequent events for that finger to the same event handler.
The Moved logic moves the BoxView by altering the LayoutBounds attached property. The Location property of
the event arguments is always relative to the BoxView being dragged, and if the BoxView is being dragged at a
constant rate, the Location properties of the consecutive events will be approximately the same. For example, if a
finger presses the BoxView in its center, the Pressed action stores a PressPoint property of (50, 50), which
remains the same for subsequent events. If the BoxView is dragged diagonally at a constant rate, the subsequent
Location properties during the Moved action might be values of (55, 55 ), in which case the Moved logic adds 5 to
the horizontal and vertical position of the BoxView . This moves the BoxView so that its center is again directly
under the finger.
You can move multiple BoxView elements simultaneously using different fingers.
Subclassing the View
Often, it's easier for a Xamarin.Forms element to handle its own touch events. The Draggable BoxView
Dragging page functions the same as the BoxView Dragging page, but the elements that the user drags are
instances of a DraggableBoxView class that derives from BoxView :
class DraggableBoxView : BoxView
{
bool isBeingDragged;
long touchId;
Point pressPoint;

public DraggableBoxView()
{
TouchEffect touchEffect = new TouchEffect
{
Capture = true
};
touchEffect.TouchAction += OnTouchEffectAction;
Effects.Add(touchEffect);
}

void OnTouchEffectAction(object sender, TouchActionEventArgs args)


{
switch (args.Type)
{
case TouchActionType.Pressed:
if (!isBeingDragged)
{
isBeingDragged = true;
touchId = args.Id;
pressPoint = args.Location;
}
break;

case TouchActionType.Moved:
if (isBeingDragged && touchId == args.Id)
{
TranslationX += args.Location.X - pressPoint.X;
TranslationY += args.Location.Y - pressPoint.Y;
}
break;

case TouchActionType.Released:
if (isBeingDragged && touchId == args.Id)
{
isBeingDragged = false;
}
break;
}
}
}

The constructor creates and attaches the TouchEffect , and sets the Capture property when that object is first
instantiated. No dictionary is required because the class itself stores isBeingDragged , pressPoint , and touchId
values associated with each finger. The Moved handling alters the TranslationX and TranslationY properties so
the logic will work even if the parent of the DraggableBoxView is not an AbsoluteLayout .
Integrating with SkiaSharp
The next two demonstrations require graphics, and they use SkiaSharp for this purpose. You might want to learn
about Using SkiaSharp in Xamarin.Forms before you study these examples. The first two articles ("SkiaSharp
Drawing Basics" and "SkiaSharp Lines and Paths") cover everything that you'll need here.
The Ellipse Drawing page allows you to draw an ellipse by swiping your finger on the screen. Depending how
you move your finger, you can draw the ellipse from the upper-left to the lower-right, or from any other corner to
the opposite corner. The ellipse is drawn with a random color and opacity.
If you then touch one of the ellipses, you can drag it to another location. This requires a technique known as "hit-
testing," which involves searching for the graphical object at a particular point. The SkiaSharp ellipses are not
Xamarin.Forms elements, so they cannot perform their own TouchEffect processing. The TouchEffect must apply
to the entire SKCanvasView object.
The EllipseDrawPage.xaml file instantiates the SKCanvasView in a single-cell Grid . The TouchEffect object is
attached to that Grid :

<Grid x:Name="canvasViewGrid"
Grid.Row="1"
BackgroundColor="White">

<skia:SKCanvasView x:Name="canvasView"
PaintSurface="OnCanvasViewPaintSurface" />
<Grid.Effects>
<tt:TouchEffect Capture="True"
TouchAction="OnTouchEffectAction" />
</Grid.Effects>
</Grid>

In Android and the Universal Windows Platform, the TouchEffect can be attached directly to the SKCanvasView ,
but on iOS that doesn't work. Notice that the Capture property is set to true .
Each ellipse that SkiaSharp renders is represented by an object of type EllipseDrawingFigure :
class EllipseDrawingFigure
{
SKPoint pt1, pt2;

public EllipseDrawingFigure()
{
}

public SKColor Color { set; get; }

public SKPoint StartPoint


{
set
{
pt1 = value;
MakeRectangle();
}
}

public SKPoint EndPoint


{
set
{
pt2 = value;
MakeRectangle();
}
}

void MakeRectangle()
{
Rectangle = new SKRect(pt1.X, pt1.Y, pt2.X, pt2.Y).Standardized;
}

public SKRect Rectangle { set; get; }

// For dragging operations


public Point LastFingerLocation { set; get; }

// For the dragging hit-test


public bool IsInEllipse(SKPoint pt)
{
SKRect rect = Rectangle;

return (Math.Pow(pt.X - rect.MidX, 2) / Math.Pow(rect.Width / 2, 2) +


Math.Pow(pt.Y - rect.MidY, 2) / Math.Pow(rect.Height / 2, 2)) < 1;
}
}

The StartPoint and EndPoint properties are used when the program is processing touch input; the Rectangle
property is used for drawing the ellipse. The LastFingerLocation property comes into play when the ellipse is
being dragged, and the IsInEllipse method aids in hit-testing. The method returns true if the point is inside the
ellipse.
The code-behind file maintains three collections:

Dictionary<long, EllipseDrawingFigure> inProgressFigures = new Dictionary<long, EllipseDrawingFigure>();


List<EllipseDrawingFigure> completedFigures = new List<EllipseDrawingFigure>();
Dictionary<long, EllipseDrawingFigure> draggingFigures = new Dictionary<long, EllipseDrawingFigure>();

The draggingFigure dictionary contains a subset of the completedFigures collection. The SkiaSharp PaintSurface
event handler simply renders the objects in these the completedFigures and inProgressFigures collections:
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Fill
};
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKCanvas canvas = args.Surface.Canvas;
canvas.Clear();

foreach (EllipseDrawingFigure figure in completedFigures)


{
paint.Color = figure.Color;
canvas.DrawOval(figure.Rectangle, paint);
}
foreach (EllipseDrawingFigure figure in inProgressFigures.Values)
{
paint.Color = figure.Color;
canvas.DrawOval(figure.Rectangle, paint);
}
}

The trickiest part of the touch processing is the Pressed handling. This is where the hit-testing is performed, but if
the code detects an ellipse under the user's finger, that ellipse can only be dragged if it's not currently being
dragged by another finger. If there is no ellipse under the user's finger, then the code begins the process of drawing
a new ellipse:
case TouchActionType.Pressed:
bool isDragOperation = false;

// Loop through the completed figures


foreach (EllipseDrawingFigure fig in completedFigures.Reverse<EllipseDrawingFigure>())
{
// Check if the finger is touching one of the ellipses
if (fig.IsInEllipse(ConvertToPixel(args.Location)))
{
// Tentatively assume this is a dragging operation
isDragOperation = true;

// Loop through all the figures currently being dragged


foreach (EllipseDrawingFigure draggedFigure in draggingFigures.Values)
{
// If there's a match, we'll need to dig deeper
if (fig == draggedFigure)
{
isDragOperation = false;
break;
}
}

if (isDragOperation)
{
fig.LastFingerLocation = args.Location;
draggingFigures.Add(args.Id, fig);
break;
}
}
}

if (isDragOperation)
{
// Move the dragged ellipse to the end of completedFigures so it's drawn on top
EllipseDrawingFigure fig = draggingFigures[args.Id];
completedFigures.Remove(fig);
completedFigures.Add(fig);
}
else // start making a new ellipse
{
// Random bytes for random color
byte[] buffer = new byte[4];
random.NextBytes(buffer);

EllipseDrawingFigure figure = new EllipseDrawingFigure


{
Color = new SKColor(buffer[0], buffer[1], buffer[2], buffer[3]),
StartPoint = ConvertToPixel(args.Location),
EndPoint = ConvertToPixel(args.Location)
};
inProgressFigures.Add(args.Id, figure);
}
canvasView.InvalidateSurface();
break;

The other SkiaSharp example is the Finger Paint page. You can select a stroke color and stroke width from two
Picker views and then draw with one or more fingers:
This example also requires a separate class to represent each line painted on the screen:

class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new SKPath();
}

public SKPath Path { set; get; }

public Color StrokeColor { set; get; }

public float StrokeWidth { set; get; }


}

An SKPath object is used to render each line. The FingerPaint.xaml.cs file maintains two collections of these
objects, one for those polylines currently being drawn and another for the completed polylines:

Dictionary<long, FingerPaintPolyline> inProgressPolylines = new Dictionary<long, FingerPaintPolyline>();


List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();

The Pressed processing creates a new FingerPaintPolyline , calls MoveTo on the path object to store the initial
point, and adds that object to the inProgressPolylines dictionary. The Moved processing calls LineTo on the path
object with the new finger position, and the Released processing transfers the completed polyline from
inProgressPolylines to completedPolylines . Once again, the actual SkiaSharp drawing code is relatively simple:
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
StrokeCap = SKStrokeCap.Round,
StrokeJoin = SKStrokeJoin.Round
};
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKCanvas canvas = args.Surface.Canvas;
canvas.Clear();

foreach (FingerPaintPolyline polyline in completedPolylines)


{
paint.Color = polyline.StrokeColor.ToSKColor();
paint.StrokeWidth = polyline.StrokeWidth;
canvas.DrawPath(polyline.Path, paint);
}

foreach (FingerPaintPolyline polyline in inProgressPolylines.Values)


{
paint.Color = polyline.StrokeColor.ToSKColor();
paint.StrokeWidth = polyline.StrokeWidth;
canvas.DrawPath(polyline.Path, paint);
}
}

Tracking View-to -View Touch


All the previous examples have set the Capture property of the TouchEffect to true , either when the
TouchEffect was created or when the Pressed event occurred. This ensures that the same element receives all the
events associated with the finger that first pressed the view. The final sample does not set Capture to true . This
causes different behavior when a finger in contact with the screen moves from one element to another. The
element that the finger moves from receives an event with a Type property set to TouchActionType.Exited and the
second element receives an event with a Type setting of TouchActionType.Entered .
This type of touch processing is very useful for a music keyboard. A key should be able to detect when it's pressed,
but also when a finger slides from one key to another.
The Silent Keyboard page defines small WhiteKey and BlackKey classes that derive from Key , which derives
from BoxView .
The Keyclass is ready to be used in an actual music program. It defines public properties named IsPressed and
KeyNumber , which is intended to be set to the key code established by the MIDI standard. The Key class also
defines an event named StatusChanged , which is invoked when the IsPressed property changes.
Multiple fingers are allowed on each key. For this reason, the Key class maintains a List of the touch ID
numbers of all the fingers currently touching that key:

List<long> ids = new List<long>();

The TouchAction event handler adds an ID to the ids list for both a Pressed event type and an Entered type,
but only when the IsInContact property is true for the Entered event. The ID is removed from the List for a
Released or Exited event:
void OnTouchEffectAction(object sender, TouchActionEventArgs args)
{
switch (args.Type)
{
case TouchActionType.Pressed:
AddToList(args.Id);
break;

case TouchActionType.Entered:
if (args.IsInContact)
{
AddToList(args.Id);
}
break;

case TouchActionType.Moved:
break;

case TouchActionType.Released:
case TouchActionType.Exited:
RemoveFromList(args.Id);
break;
}
}

The AddToList and RemoveFromList methods both check if the List has changed between empty and non-empty,
and if so, invokes the StatusChanged event.
The various WhiteKey and BlackKey elements are arranged in the page's XAML file, which looks best when the
phone is held in a landscape mode:

If you sweep your finger across the keys, you'll see by the slight changes in color that the touch events are
transferred from one key to another.

Summary
This article has demonstrated how to invoke events in an effect, and how to write and use an effect that
implements low -level multi-touch processing.

Related Links
Multi-Touch Finger Tracking in iOS
Multi-Touch Finger Tracking in Android
Touch Tracking Effect (sample)
Xamarin.Forms Reusable RoundEffect
4 minutes to read • Edit Online

Download the sample


The RoundEffect simplifies rendering any control that derives from VisualElement as a circle. This effect can be
used to create circular images, buttons, and other controls:

Create a shared RoutingEffect


An effect class must be created in the shared project to create a cross-platform effect. The sample application
creates an empty RoundEffect class that derives from the RoutingEffect class:

public class RoundEffect : RoutingEffect


{
public RoundEffect() : base($"Xamarin.{nameof(RoundEffect)}")
{
}
}

This class allows the shared project to resolve the references to the effect in code or XAML but does not provide
any functionality. The effect must have implementations for each platform.

Implement the Android effect


The Android platform project defines a RoundEffect class that derives from PlatformEffect . This class is tagged
with assembly attributes that allow Xamarin.Forms to resolve the effect class:
[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(RoundEffectDemo.Droid.RoundEffect), nameof(RoundEffectDemo.Droid.RoundEffect))]
namespace RoundEffectDemo.Droid
{
public class RoundEffect : PlatformEffect
{
// ...
}
}

The Android platform uses the concept of an OutlineProvider to define the edges of a control. The sample project
includes a CornerRadiusProvider class that derives from the ViewOutlineProvider class:

class CornerRadiusOutlineProvider : ViewOutlineProvider


{
Element element;

public CornerRadiusOutlineProvider(Element formsElement)


{
element = formsElement;
}

public override void GetOutline(Android.Views.View view, Outline outline)


{
float scale = view.Resources.DisplayMetrics.Density;
double width = (double)element.GetValue(VisualElement.WidthProperty) * scale;
double height = (double)element.GetValue(VisualElement.HeightProperty) * scale;
float minDimension = (float)Math.Min(height, width);
float radius = minDimension / 2f;
Rect rect = new Rect(0, 0, (int)width, (int)height);
outline.SetRoundRect(rect, radius);
}
}

This class uses the Width and Height properties of the Xamarin.Forms Element instance to calculate a radius that
is half of the shortest dimension.
Once an outline provider is defined the RoundEffect class can consume it to implement the effect:
public class RoundEffect : PlatformEffect
{
ViewOutlineProvider originalProvider;
Android.Views.View effectTarget;

protected override void OnAttached()


{
try
{
effectTarget = Control ?? Container;
originalProvider = effectTarget.OutlineProvider;
effectTarget.OutlineProvider = new CornerRadiusOutlineProvider(Element);
effectTarget.ClipToOutline = true;
}
catch (Exception ex)
{
Console.WriteLine($"Failed to set corner radius: {ex.Message}");
}
}

protected override void OnDetached()


{
if(effectTarget != null)
{
effectTarget.OutlineProvider = originalProvider;
effectTarget.ClipToOutline = false;
}
}
}

The OnAttached method is called when the effect is attached to an element. The existing OutlineProvider object is
saved so it can be restored when the effect is detached. A new instance of the CornerRadiusOutlineProvider is used
as the OutlineProvider and ClipToOutline is set to true to clip overflowing elements to the outline borders.
The OnDetatched method is called when the effect is removed from an element and restores the original
OutlineProvider value.

NOTE
Depending on the element type, the Control property may or may not be null. If the Control property is not null, the
rounded corners can be applied directly to the control. However, if it is null the rounded corners must be applied to the
Container object. The effectTarget field allows the effect to be applied to the appropriate object.

Implement the iOS effect


The iOS platform project defines a RoundEffect class that derives from PlatformEffect . This class is tagged with
assembly attributes that allow Xamarin.Forms to resolve the effect class:

[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(RoundEffectDemo.iOS.RoundEffect), nameof(RoundEffectDemo.iOS.RoundEffect))]
namespace RoundEffectDemo.iOS
{
public class RoundEffect : PlatformEffect
{
// ...
}

On iOS, controls have a Layer property, which has a CornerRadius property. The RoundEffect class
implementation on iOS calculates the appropriate corner radius and updates the layer's CornerRadius property:
public class RoundEffect : PlatformEffect
{
nfloat originalRadius;
UIKit.UIView effectTarget;

protected override void OnAttached()


{
try
{
effectTarget = Control ?? Container;
originalRadius = effectTarget.Layer.CornerRadius;
effectTarget.ClipsToBounds = true;
effectTarget.Layer.CornerRadius = CalculateRadius();
}
catch (Exception ex)
{
Console.WriteLine($"Failed to set corner radius: {ex.Message}");
}
}

protected override void OnDetached()


{
if (effectTarget != null)
{
effectTarget.ClipsToBounds = false;
if (effectTarget.Layer != null)
{
effectTarget.Layer.CornerRadius = originalRadius;
}
}
}

float CalculateRadius()
{
double width = (double)Element.GetValue(VisualElement.WidthRequestProperty);
double height = (double)Element.GetValue(VisualElement.HeightRequestProperty);
float minDimension = (float)Math.Min(height, width);
float radius = minDimension / 2f;

return radius;
}
}

The CalculateRadiusmethod calculates a radius based on the minimum dimension of the Xamarin.Forms
Element . The OnAttached method is called when the effect is attached to a control, and updates the layer's
CornerRadius property. It sets the ClipToBounds property to true so overflowing elements are clipped to the
borders of the control. The OnDetatched method is called when the effect is removed from a control and reverses
these changes, restoring the original corner radius.

NOTE
Depending on the element type, the Control property may or may not be null. If the Control property is not null, the
rounded corners can be applied directly to the control. However, if it is null the rounded corners must be applied to the
Container object. The effectTarget field allows the effect to be applied to the appropriate object.

Consume the effect


Once the effect is implemented across platforms, it can be consumed by Xamarin.Forms controls. A common
application of the RoundEffect is making an Image object circular. The following XAML shows the effect being
applied to an Image instance:
<Image Source=outdoors"
HeightRequest="100"
WidthRequest="100">
<Image.Effects>
<local:RoundEffect />
</Image.Effects>
</Image>

The effect can also be applied in code:

var image = new Image


{
Source = ImageSource.FromFile("outdoors"),
HeightRequest = 100,
WidthRequest = 100
};
image.Effects.Add(new RoundEffect());

The RoundEffect class can be applied to any control that derives from VisualElement .

NOTE
For the effect to calculate the correct radius, the control it's applied to must have explicit sizing. Therefore, the
HeightRequest and WidthRequest properties should be defined. If the affected control appears in a StackLayout , its
HorizontalOptions property should not use one of the Expand values such as LayoutOptions.CenterAndExpand or it
will not have accurate dimensions.

Related links
RoundEffect sample application
Introduction to Effects
Creating an Effect
Xamarin.Forms gestures
2 minutes to read • Edit Online

Gesture recognizers can be used to detect user interaction with views in a Xamarin.Forms application.
The Xamarin.Forms GestureRecognizer class supports tap, pinch, pan, and swipe gestures on View instances.

Adding a tap gesture recognizer


A tap gesture is used for tap detection and is recognized with the TapGestureRecognizer class.

Adding a pinch gesture recognizer


A pinch gesture is used for performing interactive zoom and is recognized with the PinchGestureRecognizer class.

Adding a pan gesture recognizer


A pan gesture is used for detecting the movement of fingers around the screen and applying that movement to
content, and is recognized with the PanGestureRecognizer class.

Adding a swipe gesture recognizer


A swipe gesture occurs when a finger is moved across the screen in a horizontal or vertical direction, and is often
used to initiate navigation through content. Swipe gestures are recognized with the SwipeGestureRecognizer class.
Adding a tap gesture recognizer
2 minutes to read • Edit Online

Download the sample


The tap gesture is used for tap detection and is implemented with the TapGestureRecognizer class.
To make a user interface element clickable with the tap gesture, create a TapGestureRecognizer instance, handle the
Tapped event and add the new gesture recognizer to the GestureRecognizers collection on the user interface
element. The following code example shows a TapGestureRecognizer attached to an Image element:

var tapGestureRecognizer = new TapGestureRecognizer();


tapGestureRecognizer.Tapped += (s, e) => {
// handle the tap
};
image.GestureRecognizers.Add(tapGestureRecognizer);

By default the image will respond to single taps. Set the NumberOfTapsRequired property to wait for a double-tap
(or more taps if required).

tapGestureRecognizer.NumberOfTapsRequired = 2; // double-tap

When NumberOfTapsRequired is set above one, the event handler will only be executed if the taps occur within a set
period of time (this period is not configurable). If the second (or subsequent) taps do not occur within that period
they are effectively ignored and the 'tap count' restarts.

Using Xaml
A gesture recognizer can be added to a control in Xaml using attached properties. The syntax to add a
TapGestureRecognizer to an image is shown below (in this case defining a double tap event):

<Image Source="tapped.jpg">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped"
NumberOfTapsRequired="2" />
</Image.GestureRecognizers>
</Image>

The code for the event handler (in the sample) increments a counter and changes the image from color to black &
white.
void OnTapGestureRecognizerTapped(object sender, EventArgs args)
{
tapCount++;
var imageSender = (Image)sender;
// watch the monkey go from color to black&white!
if (tapCount % 2 == 0) {
imageSender.Source = "tapped.jpg";
} else {
imageSender.Source = "tapped_bw.jpg";
}
}

Using ICommand
Applications that use the Model-View -ViewModel (MVVM ) pattern typically use ICommand rather than wiring up
event handlers directly. The TapGestureRecognizer can easily support ICommand either by setting the binding in
code:

var tapGestureRecognizer = new TapGestureRecognizer();


tapGestureRecognizer.SetBinding (TapGestureRecognizer.CommandProperty, "TapCommand");
image.GestureRecognizers.Add(tapGestureRecognizer);

or using Xaml:

<Image Source="tapped.jpg">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="Image1" />
</Image.GestureRecognizers>
</Image>

The complete code for this view model can be found in the sample. The relevant Command implementation details
are shown below:

public class TapViewModel : INotifyPropertyChanged


{
int taps = 0;
ICommand tapCommand;
public TapViewModel () {
// configure the TapCommand with a method
tapCommand = new Command (OnTapped);
}
public ICommand TapCommand {
get { return tapCommand; }
}
void OnTapped (object s) {
taps++;
Debug.WriteLine ("parameter: " + s);
}
//region INotifyPropertyChanged code omitted
}

Related Links
TapGesture (sample)
GestureRecognizer
TapGestureRecognizer
Adding a pinch gesture recognizer
3 minutes to read • Edit Online

Download the sample


The pinch gesture is used for performing interactive zoom and is implemented with the PinchGestureRecognizer
class. A common scenario for the pinch gesture is to perform interactive zoom of an image at the pinch location.
This is accomplished by scaling the content of the viewport, and is demonstrated in this article.
To make a user interface element zoomable with the pinch gesture, create a PinchGestureRecognizer instance,
handle the PinchUpdated event, and add the new gesture recognizer to the GestureRecognizers collection on the
user interface element. The following code example shows a PinchGestureRecognizer attached to an Image
element:

var pinchGesture = new PinchGestureRecognizer();


pinchGesture.PinchUpdated += (s, e) => {
// Handle the pinch
};
image.GestureRecognizers.Add(pinchGesture);

This can also be achieved in XAML, as shown in the following code example:

<Image Source="waterfront.jpg">
<Image.GestureRecognizers>
<PinchGestureRecognizer PinchUpdated="OnPinchUpdated" />
</Image.GestureRecognizers>
</Image>

The code for the OnPinchUpdated event handler is then added to the code-behind file:

void OnPinchUpdated (object sender, PinchGestureUpdatedEventArgs e)


{
// Handle the pinch
}

Creating a PinchToZoom container


Handling the pinch gesture to perform a zoom operation requires some math to transform the user interface. This
section contains a generalized helper class to perform the math, which can be used to interactively zoom any user
interface element. The following code example shows the PinchToZoomContainer class:
public class PinchToZoomContainer : ContentView
{
...

public PinchToZoomContainer ()
{
var pinchGesture = new PinchGestureRecognizer ();
pinchGesture.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add (pinchGesture);
}

void OnPinchUpdated (object sender, PinchGestureUpdatedEventArgs e)


{
...
}
}

This class can be wrapped around a user interface element so that the pinch gesture will zoom the wrapped user
interface element. The following XAML code example shows the PinchToZoomContainer wrapping an Image
element:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:PinchGesture;assembly=PinchGesture"
x:Class="PinchGesture.HomePage">
<ContentPage.Content>
<Grid Padding="20">
<local:PinchToZoomContainer>
<local:PinchToZoomContainer.Content>
<Image Source="waterfront.jpg" />
</local:PinchToZoomContainer.Content>
</local:PinchToZoomContainer>
</Grid>
</ContentPage.Content>
</ContentPage>

The following code example shows how the PinchToZoomContainer wraps an Image element in a C# page:

public class HomePageCS : ContentPage


{
public HomePageCS ()
{
Content = new Grid {
Padding = new Thickness (20),
Children = {
new PinchToZoomContainer {
Content = new Image { Source = ImageSource.FromFile ("waterfront.jpg") }
}
}
};
}
}

When the Image element receives a pinch gesture, the displayed image will be zoomed-in or out. The zoom is
performed by the PinchZoomContainer.OnPinchUpdated method, which is shown in the following code example:
void OnPinchUpdated (object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started) {
// Store the current scale factor applied to the wrapped user interface element,
// and zero the components for the center point of the translate transform.
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
}
if (e.Status == GestureStatus.Running) {
// Calculate the scale factor to be applied.
currentScale += (e.Scale - 1) * startScale;
currentScale = Math.Max (1, currentScale);

// The ScaleOrigin is in relative coordinates to the wrapped user interface element,


// so get the X pixel coordinate.
double renderedX = Content.X + xOffset;
double deltaX = renderedX / Width;
double deltaWidth = Width / (Content.Width * startScale);
double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

// The ScaleOrigin is in relative coordinates to the wrapped user interface element,


// so get the Y pixel coordinate.
double renderedY = Content.Y + yOffset;
double deltaY = renderedY / Height;
double deltaHeight = Height / (Content.Height * startScale);
double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

// Calculate the transformed element pixel coordinates.


double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);

// Apply translation based on the change in origin.


Content.TranslationX = targetX.Clamp (-Content.Width * (currentScale - 1), 0);
Content.TranslationY = targetY.Clamp (-Content.Height * (currentScale - 1), 0);

// Apply scale factor.


Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed) {
// Store the translation delta's of the wrapped user interface element.
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
}
}

This method updates the zoom level of the wrapped user interface element based on the user's pinch gesture. This
is achieved by using the values of the Scale , ScaleOrigin and Status properties of the
PinchGestureUpdatedEventArgs instance to calculate the scale factor to be applied at the origin of the pinch gesture.
The wrapped user element is then zoomed at the origin of the pinch gesture by setting its TranslationX ,
TranslationY , and Scale properties to the calculated values.

Related Links
PinchGesture (sample)
GestureRecognizer
PinchGestureRecognizer
Adding a pan gesture recognizer
3 minutes to read • Edit Online

Download the sample


The pan gesture is used for detecting the movement of fingers around the screen and applying that movement to
content, and is implemented with the PanGestureRecognizer class. A common scenario for the pan gesture is to
horizontally and vertically pan an image, so that all of the image content can be viewed when it's being displayed
in a viewport smaller than the image dimensions. This is accomplished by moving the image within the viewport,
and is demonstrated in this article.
To make a user interface element moveable with the pan gesture, create a PanGestureRecognizer instance, handle
the PanUpdated event, and add the new gesture recognizer to the GestureRecognizers collection on the user
interface element. The following code example shows a PanGestureRecognizer attached to an Image element:

var panGesture = new PanGestureRecognizer();


panGesture.PanUpdated += (s, e) => {
// Handle the pan
};
image.GestureRecognizers.Add(panGesture);

This can also be achieved in XAML, as shown in the following code example:

<Image Source="MonoMonkey.jpg">
<Image.GestureRecognizers>
<PanGestureRecognizer PanUpdated="OnPanUpdated" />
</Image.GestureRecognizers>
</Image>

The code for the OnPanUpdated event handler is then added to the code-behind file:

void OnPanUpdated (object sender, PanUpdatedEventArgs e)


{
// Handle the pan
}

Creating a pan container


This section contains a generalized helper class that performs freeform panning, which is typically suited to
navigating within images or maps. Handling the pan gesture to perform this operation requires some math to
transform the user interface. This math is used to pan only within the bounds of the wrapped user interface
element. The following code example shows the PanContainer class:
public class PanContainer : ContentView
{
double x, y;

public PanContainer ()
{
// Set PanGestureRecognizer.TouchPoints to control the
// number of touch points needed to pan
var panGesture = new PanGestureRecognizer ();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add (panGesture);
}

void OnPanUpdated (object sender, PanUpdatedEventArgs e)


{
...
}
}

This class can be wrapped around a user interface element so that the gesture will pan the wrapped user interface
element. The following XAML code example shows the PanContainer wrapping an Image element:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:PanGesture"
x:Class="PanGesture.HomePage">
<ContentPage.Content>
<AbsoluteLayout>
<local:PanContainer>
<Image Source="MonoMonkey.jpg" WidthRequest="1024" HeightRequest="768" />
</local:PanContainer>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>

The following code example shows how the PanContainer wraps an Image element in a C# page:

public class HomePageCS : ContentPage


{
public HomePageCS ()
{
Content = new AbsoluteLayout {
Padding = new Thickness (20),
Children = {
new PanContainer {
Content = new Image {
Source = ImageSource.FromFile ("MonoMonkey.jpg"),
WidthRequest = 1024,
HeightRequest = 768
}
}
}
};
}
}

In both examples, the WidthRequest and HeightRequest properties are set to the width and height values of the
image being displayed.
When the element receives a pan gesture, the displayed image will be panned. The pan is performed by the
Image
PanContainer.OnPanUpdated method, which is shown in the following code example:
void OnPanUpdated (object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType) {
case GestureStatus.Running:
// Translate and ensure we don't pan beyond the wrapped user interface element bounds.
Content.TranslationX =
Math.Max (Math.Min (0, x + e.TotalX), -Math.Abs (Content.Width - App.ScreenWidth));
Content.TranslationY =
Math.Max (Math.Min (0, y + e.TotalY), -Math.Abs (Content.Height - App.ScreenHeight));
break;

case GestureStatus.Completed:
// Store the translation applied during the pan
x = Content.TranslationX;
y = Content.TranslationY;
break;
}
}

This method updates the viewable content of the wrapped user interface element, based on the user's pan gesture.
This is achieved by using the values of the TotalX and TotalY properties of the PanUpdatedEventArgs instance to
calculate the direction and distance of the pan. The App.ScreenWidth and App.ScreenHeight properties provide the
height and width of the viewport, and are set to the screen width and screen height values of the device by the
respective platform-specific projects. The wrapped user element is then panned by setting its TranslationX and
TranslationY properties to the calculated values.

When panning content in an element that does not occupy the full screen, the height and width of the viewport can
be obtained from the element's Height and Width properties.

NOTE
Displaying high-resolution images can greatly increase an app's memory footprint. Therefore, they should only be created
when required and should be released as soon as the app no longer requires them. For more information, see Optimize
Image Resources.

Related Links
PanGesture (sample)
GestureRecognizer
PanGestureRecognizer
Adding a swipe gesture recognizer
5 minutes to read • Edit Online

Download the sample


A swipe gesture occurs when a finger is moved across the screen in a horizontal or vertical direction, and is often
used to initiate navigation through content. The code examples in this article are taken from the Swipe Gesture
sample.
To make a View recognize a swipe gesture, create a SwipeGestureRecognizer instance, set the Direction property
to a SwipeDirection enumeration value ( Left , Right , Up , or Down ), optionally set the Threshold property,
handle the Swiped event, and add the new gesture recognizer to the GestureRecognizers collection on the view.
The following code example shows a SwipeGestureRecognizer attached to a BoxView :

<BoxView Color="Teal" ...>


<BoxView.GestureRecognizers>
<SwipeGestureRecognizer Direction="Left" Swiped="OnSwiped"/>
</BoxView.GestureRecognizers>
</BoxView>

Here is the equivalent C# code:

var boxView = new BoxView { Color = Color.Teal, ... };


var leftSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Left };
leftSwipeGesture.Swiped += OnSwiped;

boxView.GestureRecognizers.Add(leftSwipeGesture);

The SwipeGestureRecognizer class also includes a Threshold property, that can be optionally set to a uint value
that represents the minimum swipe distance that must be achieved for a swipe to be recognized, in device-
independent units. The default value of this property is 100, meaning that any swipes that are less than 100 device-
independent units will be ignored.

Recognizing the swipe direction


In the examples above, the Direction property is set to single a value from the SwipeDirection enumeration.
However, it's also possible to set this property to multiple values from the SwipeDirection enumeration, so that
the Swiped event is fired in response to a swipe in more than one direction. However, the constraint is that a single
SwipeGestureRecognizer can only recognize swipes that occur on the same axis. Therefore, swipes that occur on the
horizontal axis can be recognized by setting the Direction property to Left and Right :

<SwipeGestureRecognizer Direction="Left,Right" Swiped="OnSwiped"/>

Similarly, swipes that occur on the vertical axis can be recognized by setting the Direction property to Up and
Down :

var swipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Up | SwipeDirection.Down };

Alternatively, a SwipeGestureRecognizer for each swipe direction can be created to recognize swipes in every
direction:

<BoxView Color="Teal" ...>


<BoxView.GestureRecognizers>
<SwipeGestureRecognizer Direction="Left" Swiped="OnSwiped"/>
<SwipeGestureRecognizer Direction="Right" Swiped="OnSwiped"/>
<SwipeGestureRecognizer Direction="Up" Swiped="OnSwiped"/>
<SwipeGestureRecognizer Direction="Down" Swiped="OnSwiped"/>
</BoxView.GestureRecognizers>
</BoxView>

Here is the equivalent C# code:

var boxView = new BoxView { Color = Color.Teal, ... };


var leftSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Left };
leftSwipeGesture.Swiped += OnSwiped;
var rightSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Right };
rightSwipeGesture.Swiped += OnSwiped;
var upSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Up };
upSwipeGesture.Swiped += OnSwiped;
var downSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Down };
downSwipeGesture.Swiped += OnSwiped;

boxView.GestureRecognizers.Add(leftSwipeGesture);
boxView.GestureRecognizers.Add(rightSwipeGesture);
boxView.GestureRecognizers.Add(upSwipeGesture);
boxView.GestureRecognizers.Add(downSwipeGesture);

NOTE
In the above examples, the same event handler responds to the Swiped event firing. However, each
SwipeGestureRecognizer instance can use a different event handler if required.

Responding to the swipe


An event handler for the Swiped event is shown in the following example:

void OnSwiped(object sender, SwipedEventArgs e)


{
switch (e.Direction)
{
case SwipeDirection.Left:
// Handle the swipe
break;
case SwipeDirection.Right:
// Handle the swipe
break;
case SwipeDirection.Up:
// Handle the swipe
break;
case SwipeDirection.Down:
// Handle the swipe
break;
}
}

The SwipedEventArgs can be examined to determine the direction of the swipe, with custom logic responding to the
swipe as required. The direction of the swipe can be obtained from the Direction property of the event
arguments, which will be set to one of the values of the SwipeDirection enumeration. In addition, the event
arguments also have a Parameter property that will be set to the value of the CommandParameter property, if
defined.

Using commands
The SwipeGestureRecognizer class also includes Command and CommandParameter properties. These properties are
typically used in applications that use the Model-View -ViewModel (MVVM ) pattern. The Command property
defines the ICommand to be invoked when a swipe gesture is recognized, with the CommandParameter property
defining an object to be passed to the ICommand. The following code example shows how to bind the Command
property to an ICommand defined in the view model whose instance is set as the page BindingContext :

var boxView = new BoxView { Color = Color.Teal, ... };


var leftSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Left, CommandParameter = "Left"
};
leftSwipeGesture.SetBinding(SwipeGestureRecognizer.CommandProperty, "SwipeCommand");
boxView.GestureRecognizers.Add(leftSwipeGesture);

The equivalent XAML code is:

<BoxView Color="Teal" ...>


<BoxView.GestureRecognizers>
<SwipeGestureRecognizer Direction="Left" Command="{Binding SwipeCommand}" CommandParameter="Left" />
</BoxView.GestureRecognizers>
</BoxView>

SwipeCommand is a property of type ICommand defined in the view model instance that is set as the page
BindingContext . When a swipe gesture is recognized, the Execute method of the SwipeCommand object will be
executed. The argument to the Execute method is the value of the CommandParameter property. For more
information about commands, see The Command Interface.

Creating a swipe container


The SwipeContainer class, which is shown in the following code example, is a generalized swipe recognition class
that be wrapped around a View to perform swipe gesture recognition:

public class SwipeContainer : ContentView


{
public event EventHandler<SwipedEventArgs> Swipe;

public SwipeContainer()
{
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Left));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Right));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Up));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Down));
}

SwipeGestureRecognizer GetSwipeGestureRecognizer(SwipeDirection direction)


{
var swipe = new SwipeGestureRecognizer { Direction = direction };
swipe.Swiped += (sender, e) => Swipe?.Invoke(this, e);
return swipe;
}
}

The SwipeContainer class creates SwipeGestureRecognizer objects for all four swipe directions, and attaches Swipe
event handlers. These event handlers invoke the Swipe event defined by the SwipeContainer .
The following XAML code example shows the SwipeContainer class wrapping a BoxView :

<ContentPage ...>
<StackLayout>
<local:SwipeContainer Swipe="OnSwiped" ...>
<BoxView Color="Teal" ... />
</local:SwipeContainer>
</StackLayout>
</ContentPage>

The following code example shows how the SwipeContainer wraps a BoxView in a C# page:

public class SwipeContainerPageCS : ContentPage


{
public SwipeContainerPageCS()
{
var boxView = new BoxView { Color = Color.Teal, ... };
var swipeContainer = new SwipeContainer { Content = boxView, ... };
swipeContainer.Swipe += (sender, e) =>
{
// Handle the swipe
};

Content = new StackLayout


{
Children = { swipeContainer }
};
}
}

When the BoxView receives a swipe gesture, the Swiped event in the SwipeGestureRecognizer is fired. This is
handled by the SwipeContainer class, which fires its own Swipe event. This Swipe event is handled on the page.
The SwipedEventArgs can then be examined to determine the direction of the swipe, with custom logic responding
to the swipe as required.

Related links
Swipe Gesture (sample)
GestureRecognizer
SwipeGestureRecognizer
Local notifications in Xamarin.Forms
7 minutes to read • Edit Online

Download the sample


Local notifications are alerts sent by applications installed on a mobile device. Local notifications are often used for
features such as:
Calendar events
Reminders
Location-based triggers
Each platform handles the creation, display, and consumption of local notifications differently. This article explains
how to create a cross-platform abstraction to send and receive local notifications with Xamarin.Forms.

Create a cross-platform interface


The Xamarin.Forms application should create and consume notifications without concern for the underlying
platform implementations. The following INotificationManager interface is implemented in the shared code library,
and defines a cross-platform API that the application can use to interact with notifications:

public interface INotificationManager


{
event EventHandler NotificationReceived;

void Initialize();

int ScheduleNotification(string title, string message);

void ReceiveNotification(string title, string message);


}

This interface will be implemented in each platform project. The NotificationReceived event allows the application
to handle incoming notifications. The Initialize method should perform any native platform logic needed to
prepare the notification system. The ScheduleNotification method should send a notification. The
ReceiveNotification method should be called by the underlying platform when a message is received.

Consume the interface in Xamarin.Forms


Once an interface has been created, it can be consumed in the shared Xamarin.Forms project even though platform
implementations haven't been created yet. The sample application contains a ContentPage called MainPage.xaml
with the following content:

<StackLayout Margin="0,35,0,0"
x:Name="stackLayout">
<Label Text="Click the button to create a local notification."
TextColor="Red"
HorizontalOptions="Center"
VerticalOptions="Start" />
<Button Text="Create Notification"
HorizontalOptions="Center"
VerticalOptions="Start"
Clicked="OnScheduleClick"/>
</StackLayout>

The layout contains a Label element with instructions for the user and a Button that should schedule a
notification when tapped.
The MainPage class code-behind handles the sending and receiving of notifications:

public partial class MainPage : ContentPage


{
INotificationManager notificationManager;
int notificationNumber = 0;

public MainPage()
{
InitializeComponent();

notificationManager = DependencyService.Get<INotificationManager>();
notificationManager.NotificationReceived += (sender, eventArgs) =>
{
var evtData = (NotificationEventArgs)eventArgs;
ShowNotification(evtData.Title, evtData.Message);
};
}

void OnScheduleClick(object sender, EventArgs e)


{
notificationNumber++;
string title = $"Local Notification #{notificationNumber}";
string message = $"You have now received {notificationNumber} notifications!";
notificationManager.ScheduleNotification(title, message);
}

void ShowNotification(string title, string message)


{
Device.BeginInvokeOnMainThread(() =>
{
var msg = new Label()
{
Text = $"Notification Received:\nTitle: {title}\nMessage: {message}"
};
stackLayout.Children.Add(msg);
});
}
}

The MainPage class constructor uses the Xamarin.Forms DependencyService to retrieve a platform-specific instance
of the INotificationManager . The OnScheduleClicked method uses the INotificationManager instance to schedule a
new notification. The ShowNotification method is called from the event handler attached to the
NotificationReceived event, and will insert a new Label into the page when the event is invoked.

For more information about the Xamarin.Forms DependencyService , see Xamarin.Forms DependencyService.
Create the Android interface implementation
For the Xamarin.Forms application to send and receive notifications on Android, the application must provide an
implementation of the INotificationManager interface.
Create the AndroidNotificationManager class
The AndroidNotificationManager class implements the INotificationManager interface:

using Android.Support.V4.App;
using Xamarin.Forms;
using AndroidApp = Android.App.Application;

[assembly: Dependency(typeof(LocalNotifications.Droid.AndroidNotificationManager))]
namespace LocalNotifications.Droid
{
public class AndroidNotificationManager : INotificationManager
{
const string channelId = "default";
const string channelName = "Default";
const string channelDescription = "The default channel for notifications.";
const int pendingIntentId = 0;

public const string TitleKey = "title";


public const string MessageKey = "message";

bool channelInitialized = false;


int messageId = -1;
NotificationManager manager;

public event EventHandler NotificationReceived;

public void Initialize()


{
CreateNotificationChannel();
}

public int ScheduleNotification(string title, string message)


{
if (!channelInitialized)
{
CreateNotificationChannel();
}

messageId++;

Intent intent = new Intent(AndroidApp.Context, typeof(MainActivity));


intent.PutExtra(TitleKey, title);
intent.PutExtra(MessageKey, message);

PendingIntent pendingIntent = PendingIntent.GetActivity(AndroidApp.Context, pendingIntentId,


intent, PendingIntentFlags.OneShot);

NotificationCompat.Builder builder = new NotificationCompat.Builder(AndroidApp.Context, channelId)


.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetLargeIcon(BitmapFactory.DecodeResource(AndroidApp.Context.Resources,
Resource.Drawable.xamagonBlue))
.SetSmallIcon(Resource.Drawable.xamagonBlue)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate);

var notification = builder.Build();


manager.Notify(messageId, notification);

return messageId;
}
public void ReceiveNotification(string title, string message)
{
var args = new NotificationEventArgs()
{
Title = title,
Message = message,
};
NotificationReceived?.Invoke(null, args);
}

void CreateNotificationChannel()
{
manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);

if (Build.VERSION.SdkInt >= BuildVersionCodes.O)


{
var channelNameJava = new Java.Lang.String(channelName);
var channel = new NotificationChannel(channelId, channelNameJava,
NotificationImportance.Default)
{
Description = channelDescription
};
manager.CreateNotificationChannel(channel);
}

channelInitialized = true;
}
}
}

The assembly attribute above the namespace registers the INotificationManager interface implementation with
the DependencyService .
Android allows applications to define multiple channels for notifications. The Initialize method creates a basic
channel the sample application uses to send notifications. The ScheduleNotification method defines the platform-
specific logic required to create and send a notification. Finally, the ReceiveNotification method is called by the
Android OS when a message is received, and invokes the event handler.

NOTE
The Application class is defined in both the Xamarin.Forms and Android.App namespaces so the AndroidApp alias is
defined in the using statements to differentiate the two.

Handle incoming notifications on Android


The MainActivity class must detect incoming notifications and notify the AndroidNotificationManager instance.
The Activity attribute on the MainActivity class should specify a LaunchMode value of LaunchMode.SingleTop :

[Activity(
//...
LaunchMode = LaunchMode.SingleTop]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
// ...
}

The SingleTop mode prevents multiple instances of an Activity from being started while the application is in the
foreground. This LaunchMode may not be appropriate for applications that launch multiple activities in more
complex notification scenarios. For more information about LaunchMode enumeration values, see Android Activity
LaunchMode.
In the MainActivity class is modified to receive incoming notifications:

protected override void OnCreate(Bundle savedInstanceState)


{
// ...

global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
CreateNotificationFromIntent(Intent);
}

protected override void OnNewIntent(Intent intent)


{
CreateNotificationFromIntent(intent);
}

void CreateNotificationFromIntent(Intent intent)


{
if (intent?.Extras != null)
{
string title = intent.Extras.GetString(AndroidNotificationManager.TitleKey);
string message = intent.Extras.GetString(AndroidNotificationManager.MessageKey);
DependencyService.Get<INotificationManager>().ReceiveNotification(title, message);
}
}

The CreateNotificationFromIntent method extracts notification data from the intent argument and provides it to
the AndroidNotificationManager using the ReceiveNotification method. The CreateNotificationFromIntent
method is called from both the OnCreate method and the OnNewIntent method:
When the application is started by notification data, the Intent data will be passed to the OnCreate method.
If the application is already in the foreground, the Intent data will be passed to the OnNewIntent method.

Android offers many advanced options for notifications. For more information, see Notifications in
Xamarin.Android.

Create the iOS interface implementation


For the Xamarin.Forms application to send and receive notifications on iOS, the application must provide an
implementation of the INotificationManager .
Create the iOSNotificationManager class
The iOSNotificationManager class implements the INotificationManager interface:
[assembly: Dependency(typeof(LocalNotifications.iOS.iOSNotificationManager))]
namespace LocalNotifications.iOS
{
public class iOSNotificationManager : INotificationManager
{
int messageId = -1;

bool hasNotificationsPermission;

public event EventHandler NotificationReceived;

public void Initialize()


{
// request the permission to use local notifications
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err)
=>
{
hasNotificationsPermission = approved;
});
}

public int ScheduleNotification(string title, string message)


{
// EARLY OUT: app doesn't have permissions
if(!hasNotificationsPermission)
{
return -1;
}

messageId++;

var content = new UNMutableNotificationContent()


{
Title = title,
Subtitle = "",
Body = message,
Badge = 1
};

// Local notifications can be time or location based


// Create a time-based trigger, interval is in seconds and must be greater than 0
var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(0.25, false);

var request = UNNotificationRequest.FromIdentifier(messageId.ToString(), content, trigger);


UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
{
if (err != null)
{
throw new Exception($"Failed to schedule notification: {err}");
}
});

return messageId;
}

public void ReceiveNotification(string title, string message)


{
var args = new NotificationEventArgs()
{
Title = title,
Message = message
};
NotificationReceived?.Invoke(null, args);
}
}
}
The assembly attribute above the namespace registers the INotificationManager interface implementation with
the DependencyService .
On iOS, you must request permission to use notifications before attempting to schedule a notification. The
Initialize method requests authorization to use local notifications. The ScheduleNotification method defines the
logic required to create and send a notification. Finally, the ReceiveNotification method will be called by iOS when
a message is received, and invokes the event handler.
Handle incoming notifications on iOS
On iOS, you must create a delegate that subclasses UNUserNotificationCenterDelegate to handle incoming
messages. The sample application defines an iOSNotificationReceiver class:

public class iOSNotificationReceiver : UNUserNotificationCenterDelegate


{
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification,
Action<UNNotificationPresentationOptions> completionHandler)
{
DependencyService.Get<INotificationManager>().ReceiveNotification(notification.Request.Content.Title,
notification.Request.Content.Body);

// alerts are always shown for demonstration but this can be set to "None"
// to avoid showing alerts if the app is in the foreground
completionHandler(UNNotificationPresentationOptions.Alert);
}
}

This class uses the DependencyService to get an instance of the iOSNotificationManager class and provides
incoming notification data to the ReceiveNotification method.
The AppDelegate class must specify the custom delegate during application startup. The AppDelegate class must
specify an iOSNotificationReceiver object as the UNUserNotificationCenter delegate during application startup.
This occurs in the FinishedLaunching method:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)


{
global::Xamarin.Forms.Forms.Init();

UNUserNotificationCenter.Current.Delegate = new iOSNotificationReceiver();

LoadApplication(new App());
return base.FinishedLaunching(app, options);
}

iOS offers many advanced options for notifications. For more information, see Notifications in Xamarin.iOS.

Test the application


Once the platform projects contain a registered implementation of the INotificationManager interface, the
application can be tested on both platforms. Run the application and click the Schedule Notification button to
create a notification.
On Android, the notification will appear in the notification area. When the notification is tapped, the application
receives the notification and displays a message below the Schedule Notification button:
On iOS, incoming notifications are automatically received by the application without requiring user input. The
application receives the notification and displays a message below the Schedule Notification button:

Related links
Sample project
Notifications in Xamarin.Android
Notifications in Xamarin.iOS
Xamarin.Forms Dependency.Service
Xamarin.Forms Localization
2 minutes to read • Edit Online

The built-in .NET localization framework can be used to build cross-platform multilingual applications with
Xamarin.Forms.

Xamarin.Forms String and Image Localization


The built-in mechanism for localizing .NET applications uses RESX files and the classes in the System.Resources
and System.Globalization namespaces. The RESX files containing translated strings are embedded in the
Xamarin.Forms assembly, along with a compiler-generated class that provides strongly-typed access to the
translations. The translated text can then be retrieved in code.

Right-to-Left Localization
Flow direction is the direction in which the UI elements on the page are scanned by the eye. Right-to-left
localization adds support for right-to-left flow direction to Xamarin.Forms applications.
Xamarin.Forms String and Image Localization
8 minutes to read • Edit Online

Download the sample


Localization is the process of adapting an application to meet the specific language or cultural requirements of a
target market. To accomplish localization, the text and images in an application may need to be translated into
multiple languages. A localized application automatically displays translated text based on the culture settings of
the mobile device:

The .NET framework includes a built-in mechanism for localizing applications using Resx resource files. A resource
file stores text and other content as name/value pairs that allow the application to retrieve content for a provided
key. Resource files allow localized content to be separated from application code.
Using resource files to localize Xamarin.Forms applications requires you to perform the following steps:
1. Create Resx files containing translated text.
2. Specify the default culture in the shared project.
3. Localize text in Xamarin.Forms.
4. Localize images based on culture settings for each platform.
5. Localize the application name on each platform.
6. Test localization on each platform.

Create Resx files


Resource files are XML files with a .resx extension that are compiled into binary resource (.resources) files during
the build process. Visual Studio 2019 generates a class that provides an API used to retrieve resources. A localized
application typically contains a default resource file with all strings used in the application, as well as resource files
for each supported language. The sample application has a Resx folder in the shared project that contains the
resource files, and its default resource file called AppResources.resx.
Resource files contain the following information for each item:
Name specifies the key used to access the text in code.
Value specifies the translated text.
Comment is an optional field containing additional information.
A resource file is added with the Add New Item dialog in Visual Studio 2019:

Once the file is added, rows can be added for each text resource:

The Access Modifier drop down setting determines how Visual Studio generates the class used to access
resources. Setting the Access Modifier to Public or Internal results in a generated class with the specified
accessibility level. Setting the Access Modifier to No code generation does not generate a class file. The default
resource file should be configured to generate a class file, which results in a file with the .designer.cs extension
being added to the project.
Once the default resource file is created, additional files can be created for each culture the application supports.
Each additional resource file should include the translation culture in the filename and should have the Access
Modifier set to No code generation.
At runtime, the application attempts to resolve a resource request in order of specificity. For example, if the device
culture is en-US the application looks for resource files in this order:
1. AppResources.en-US.resx
2. AppResources.en.resx
3. AppResources.resx (default)
The following screenshot shows a Spanish translation file named AppResources.es.cs:
The translation file uses the same Name values specified in the default file but contains Spanish language strings
in the Value column. Additionally, the Access Modifier is set to No code generation.
A resource file is added with the Add New File dialog in Visual Studio 2019 for Mac:

Once a default resource file has been created, text can be added by creating data elements within the root
element in the resource file:

<?xml version="1.0" encoding="utf-8"?>


<root>
...
<data name="AddButton" xml:space="preserve">
<value>Add Note</value>
</data>
<data name="NotesLabel" xml:space="preserve">
<value>Notes:</value>
</data>
<data name="NotesPlaceholder" xml:space="preserve">
<value>e.g. Get Milk</value>
</data>
</root>

A .designer.cs class file can be created by setting a Custom Tool property in the resource file options:
Setting the Custom Tool to PublicResXFileCodeGenerator will result in generated class with public access.
Setting the Custom Tool to InternalResXFileCodeGenerator will result in a generated class with internal
access. An empty Custom Tool value will not generate a class. The generated class name will match the resource
file name. For example, the AppResources.resx file will result in the creation of an AppResources class in a file
called AppResources.designer.cs.
Additional resource files can be created for each supported culture. Each language file should include the
translation culture in the filename so a file targeting es-MX should be named AppResources.es-MX.resx.
At runtime, the application attempts to resolve a resource request in order of specificity. For example, if the device
culture is en-US the application looks for resource files in this order:
1. AppResources.en-US.resx
2. AppResources.en.resx
3. AppResources.resx (default)
Language translation files should have the same Name values specified as the default file. The following XML
shows the Spanish translation file named AppResources.es.resx:

<?xml version="1.0" encoding="utf-8"?>


<root>
...
<data name="NotesLabel" xml:space="preserve">
<value>Notas:</value>
</data>
<data name="NotesPlaceholder" xml:space="preserve">
<value>por ejemplo . comprar leche</value>
</data>
<data name="AddButton" xml:space="preserve">
<value>Agregar nuevo elemento</value>
</data>
</root>

Specify the default culture


For resource files to work correctly, the application must have an NeutralResourcesLanguage specified. In the shared
project, the AssemblyInfo.cs file should be customized to specify the default culture. The following code shows
how to set the NeutralResourcesLanguage to en-US in the AssemblyInfo.cs file:

using System.Resources;

[assembly: NeutralResourcesLanguage("en-US")]
WARNING
If you do not specify the NeutralResourcesLanguage attribute, the ResourceManager class returns null values for any
cultures without a specific resource file. When the default culture is specified, the ResourceManager returns results from the
default Resx file for unsupported cultures. Therefore, it is recommended that you always specify the
NeutralResourcesLanguage so that text is displayed for unsupported cultures.

Once a default resource file has been created and the default culture specified in the AssemblyInfo.cs file, the
application can retrieve localized strings at runtime.
For more information about resource files, see Create resource files for .NET apps.

Localize text in Xamarin.Forms


Text is localized in Xamarin.Forms using the generated AppResources class. This class is named based on the
default resource file name. Since the sample project resource file is named AppResources.cs, Visual Studio
generates a matching class called AppResources . Static properties are generated in the AppResources class for each
row in the resource file. The following static properties are generated in the sample application's AppResources
class:
AddButton
NotesLabel
NotesPlaceholder
Accessing these values as x:Static properties allows localized text to be displayed in XAML:

<ContentPage ...
xmlns:resources="clr-namespace:LocalizationDemo.Resx">
<Label Text="{x:Static resources:AppResources.NotesLabel}" />
<Entry Placeholder="{x:Static resources:AppResources.NotesPlaceholder}" />
<Button Text="{x:Static resources:AppResources.AddButton}" />
</ContentPage>

Localized text can also be retrieved in code:


public LocalizedCodePage()
{
Label notesLabel = new Label
{
Text = AppResources.NotesLabel,
// ...
};

Entry notesEntry = new Entry


{
Placeholder = AppResources.NotesPlaceholder,
//...
};

Button addButton = new Button


{
Text = AppResources.AddButton,
// ...
};

Content = new StackLayout


{
Children = {
notesLabel,
notesEntry,
addButton
}
};
}

The properties in the AppResourcesclass use the current value of the


System.Globalization.CultureInfo.CurrentUICulture to determine which culture resource file to retrieve values
from.

Localize images
In addition to storing text, Resx files are capable of storing more than just text, they can also store images and
binary data. However, mobile devices have a range of screen sizes and densities and each mobile platform has
functionality for displaying density-dependent images. Therefore, platform image localization functionality should
be used instead of storing images in resource files.
Localize images on Android
On Android, localized drawables (images) are stored using a naming convention for folders in the Resources
directory. Folders are named drawable with a suffix for the target language. For example, the Spanish-language
folder is named drawable-es.
When a four-letter locale code is required, Android requires an additional r following the dash. For example, the
Mexico locale (es-MX) folder should be named drawable-es-rMX. The image file names in each locale folder
should be identical:
For more information, see Android Localization.
Localize images on iOS
On iOS, localized images are stored using a naming convention for folders in the Resources directory. The default
folder is named Base.lproj. Language-specific folders are named with the language or locale name, followed by
.lproj. For example, the Spanish-language folder is named es.lproj.
Four-letter local codes work just like two-letter language codes. For example, the Mexico locale (es-MX) folder
should be named es-MX.lproj. The image file names in each locale folder should be identical:

NOTE
iOS supports creating a localized Asset Catalog instead of using the .lproj folder structure. However, these must be created
and managed in Xcode.

For more information, see iOS Localization.


Localize images on UWP
On UWP, localized images are stored using a naming convention for folders in the Assets/Images directory.
Folders are named with the language or locale. For example, the Spanish-language folder is named es and the
Mexico locale folder should be named es-MX. The image file names in each locale folder should be identical:

For more information, see UWP Localization.


Consume localized images
Since each platform stores images with a unique file structure, the XAML uses the OnPlatform class to set the
ImageSource property based on the current platform:

<Image>
<Image.Source>
<OnPlatform x:TypeArguments="ImageSource">
<On Platform="iOS, Android" Value="flag.png" />
<On Platform="UWP" Value="Assets/Images/flag.png" />
</OnPlatform>
</Image.Source>
</Image>

NOTE
The OnPlatform markup extension offers a more concise way of specifying platform-specific values. For more information,
see OnPlatform markup extension.

The image source can be set based on the Device.RuntimePlatform property in code:

string imgSrc = Device.RuntimePlatform == Device.UWP ? "Assets/Images/flag.png" : "flag.png";


Image flag = new Image
{
Source = ImageSource.FromFile(imgSrc),
WidthRequest = 100
};

Localize the application name


The application name is specified per-platform and does not use Resx resource files. To localize the application
name on Android, see Localize app name on Android. To localize the application name on iOS, see Localize app
name on iOS. To localize the application name on UWP, see Localize strings in the UWP package manifest.

Test localization
Testing localization is best accomplished by changing your device language. It is possible to set the value of
System.Globalization.CultureInfo.CurrentUICulture in code but behavior is inconsistent across platforms so this is
not recommended for testing.
On iOS, in the settings app, you can set the language for each app specifically without changing your device
language.
On Android, the language settings are detected and cached when the application starts. If you change languages,
you may need to exit and restart the application to see the changes applied.

Related links
Localization Sample Project
Create resource files for .NET apps
Cross-Platform Localization
Using the CultureInfo class (MSDN )
Android Localization
iOS Localization
UWP Localization
Locating and Using Resources for a Specific Culture (MSDN )
Right-to-left localization
5 minutes to read • Edit Online

Download the sample


Right-to -left localization adds support for right-to -left flow direction to Xamarin.Forms applications.

NOTE
Right-to-left localization requires the use of iOS 9 or higher, and API 17 or higher on Android.

Flow direction is the direction in which the UI elements on the page are scanned by the eye. Some languages, such
as Arabic and Hebrew, require that UI elements are laid out in a right-to-left flow direction. This can be achieved
by setting the VisualElement.FlowDirection property. This property gets or sets the direction in which UI elements
flow within any parent element that controls their layout, and should be set to one of the FlowDirection
enumeration values:
LeftToRight
RightToLeft
MatchParent

Setting the FlowDirection property to RightToLeft on an element generally sets the alignment to the right, the
reading order to right-to-left, and the layout of the control to flow from right-to-left:

TIP
You should only set the FlowDirection property on initial layout. Changing this value at runtime causes an expensive
layout process that will affect performance.

The default FlowDirectionproperty value for an element without a parent is LeftToRight , while the default
FlowDirection for an element with a parent is MatchParent . Therefore, an element inherits the FlowDirection
property value from its parent in the visual tree, and any element can override the value it gets from its parent.
TIP
When localizing an app for right-to-left languages, set the FlowDirection property on a page or root layout. This causes
all of the elements contained within the page, or root layout, to respond appropriately to the flow direction.

Respecting device flow direction


Respecting the device's flow direction based on the selected language and region is an explicit developer choice
and does not happen automatically. It can be achieved by setting the FlowDirection property on a page, or root
layout, to the static Device.FlowDirection value:

<ContentPage ... FlowDirection="{x:Static Device.FlowDirection}"> />

this.FlowDirection = Device.FlowDirection;

All child elements of the page, or root layout, will by default then inherit the Device.FlowDirection value.

Platform setup
Specific platform setup is required to enable right-to-left locales.
iOS
The required right-to-left locale should be added as a supported language to the array items for the
CFBundleLocalizations key in Info.plist. The following example shows Arabic having been added to the array for
the CFBundleLocalizations key:

<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>ar</string>
</array>

For more information, see Localization Basics in iOS.


Right-to-left localization can then be tested by changing the language and region on the device/simulator to a
right-to-left locale that was specified in Info.plist.

WARNING
Please note that when changing the language and region to a right-to-left locale on iOS, any DatePicker views will throw
an exception if you do not include the resources required for the locale. For example, when testing an app in Arabic that has
a DatePicker , ensure that mideast is selected in the Internationalization section of the iOS Build pane.

Android
The app's AndroidManifest.xml file should be updated so that the <uses-sdk> node sets the
android:minSdkVersion attribute to 17, and the <application> node sets the android:supportsRtl attribute to
true :
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<uses-sdk android:minSdkVersion="17" ... />
<application ... android:supportsRtl="true">
</application>
</manifest>

Right-to-left localization can then be tested by changing the device/emulator to use the right-to-left language, or
by enabling Force RTL layout direction in Settings > Developer Options.
Universal Windows Platform (UWP)
The required language resources should be specified in the <Resources> node of the Package.appxmanifest file.
The following example shows Arabic having been added to the <Resources> node:

<Resources>
<Resource Language="x-generate"/>
<Resource Language="en" />
<Resource Language="ar" />
</Resources>

In addition, UWP requires that the app's default culture is explicitly defined in the .NET Standard library. This can
be accomplished by setting the NeutralResourcesLanguage attribute in AssemblyInfo.cs , or in another class, to the
default culture:

using System.Resources;

[assembly: NeutralResourcesLanguage("en")]

Right-to-left localization can then be tested by changing the language and region on the device to the appropriate
right-to-left locale.

Limitations
Xamarin.Forms right-to-left localization currently has a number of limitations:
NavigationPage button location, toolbar item location, and transition animation is controlled by the device
locale, rather than the FlowDirection property.
CarouselPage swipe direction does not flip.
Image visual content does not flip.
DisplayAlert and DisplayActionSheet orientation is controlled by the device locale, rather than the
FlowDirection property.
WebView content does not respect the FlowDirection property.
A TextDirection property needs to be added, to control text alignment.
iOS
Stepper orientation is controlled by the device locale, rather than the FlowDirection property.
EntryCell text alignment is controlled by the device locale, rather than the FlowDirection property.
ContextActions gestures and alignment are not reversed.

Android
SearchBar orientation is controlled by the device locale, rather than the FlowDirection property.
ContextActions placement is controlled by the device locale, rather than the FlowDirection property.
UWP
Editor text alignment is controlled by the device locale, rather than the FlowDirection property.
FlowDirection property is not inherited by MasterDetailPage children.
ContextActions text alignment is controlled by the device locale, rather than the FlowDirection property.

Force right-to-left layout


Xamarin.iOS and Xamarin.Android applications can be forced to always use a right-to-left layout, regardless of
device settings, by modifying the respective platform projects.
iOS
Xamarin.iOS applications can be forced to always use a right-to-left layout by modifying the AppDelegate class
as follows:
1. Declare the IntPtr_objc_msgSend function as the first line in your AppDelegate class:

[System.Runtime.InteropServices.DllImport(ObjCRuntime.Constants.ObjectiveCLibrary, EntryPoint =
"objc_msgSend")]
internal extern static IntPtr IntPtr_objc_msgSend(IntPtr receiver, IntPtr selector,
UISemanticContentAttribute arg1);

2. Call the IntPtr_objc_msgSend function from the FinishedLaunching method, before returning from the
FinshedLaunching method:

bool result = base.FinishedLaunching(app, options);

ObjCRuntime.Selector selector = new ObjCRuntime.Selector("setSemanticContentAttribute:");


IntPtr_objc_msgSend(UIView.Appearance.Handle, selector.Handle,
UISemanticContentAttribute.ForceRightToLeft);

return result;

This approach is useful for applications that always require a right-to-left layout, and removes the requirement to
set the FlowDirection property.
For more information about the IntrPtr_objc_msgSend method, see Objective-C selectors in Xamarin.iOS.
Android
Xamarin.Android applications can be forced to always use a right-to-left layout by modifying the MainActivity
class to include the following line:

Window.DecorView.LayoutDirection = LayoutDirection.Rtl;

This approach is useful for applications that always require a right-to-left layout, and removes the requirement to
set the FlowDirection property.

Right to left language support with Xamarin.University


Xamarin.Forms 3.0 Right-to-Left Support video

Related links
TodoLocalizedRTL Sample App
Xamarin.Forms MessagingCenter
4 minutes to read • Edit Online

Download the sample


The publish-subscribe pattern is a messaging pattern in which publishers send messages without having
knowledge of any receivers, known as subscribers. Similarly, subscribers listen for specific messages, without
having knowledge of any publishers.
Events in .NET implement the publish-subscribe pattern, and are the most simple and straightforward approach
for a communication layer between components if loose coupling is not required, such as a control and the page
that contains it. However, the publisher and subscriber lifetimes are coupled by object references to each other, and
the subscriber type must have a reference to the publisher type. This can create memory management issues,
especially when there are short lived objects that subscribe to an event of a static or long-lived object. If the event
handler isn't removed, the subscriber will be kept alive by the reference to it in the publisher, and this will prevent
or delay the garbage collection of the subscriber.
The Xamarin.Forms MessagingCenter class implements the publish-subscribe pattern, allowing message-based
communication between components that are inconvenient to link by object and type references. This mechanism
allows publishers and subscribers to communicate without having a reference to each other, helping to reduce
dependencies between them.
The MessagingCenter class provides multicast publish-subscribe functionality. This means that there can be
multiple publishers that publish a single message, and there can be multiple subscribers listening for the same
message:

Publishers send messages using the MessagingCenter.Send method, while subscribers listen for messages using the
MessagingCenter.Subscribe method. In addition, subscribers can also unsubscribe from message subscriptions, if
required, with the MessagingCenter.Unsubscribe method.

IMPORTANT
Internally, the MessagingCenter class uses weak references. This means that it will not keep objects alive, and will allow
them to be garbage collected. Therefore, it should only be necessary to unsubscribe from a message when a class no longer
wishes to receive the message.

Publish a message
MessagingCenter messages are strings. Publishers notify subscribers of a message with one of the
MessagingCenter.Send overloads. The following code example publishes a Hi message:
MessagingCenter.Send<MainPage>(this, "Hi");

In this example the Send method specifies a generic argument that represents the sender. To receive the message,
a subscriber must also specify the same generic argument, indicating that they are listening for a message from
that sender. In addition, this example specifies two method arguments:
The first argument specifies the sender instance.
The second argument specifies the message.
Payload data can also be sent with a message:

MessagingCenter.Send<MainPage, string>(this, "Hi", "John");

In this example, the Send method specifies two generic arguments. The first is the type that's sending the message,
and the second is the type of the payload data being sent. To receive the message, a subscriber must also specify
the same generic arguments. This enables multiple messages that share a message identity but send different
payload data types to be received by different subscribers. In addition, this example specifies a third method
argument that represents the payload data to be sent to the subscriber. In this case the payload data is a string .
The Send method will publish the message, and any payload data, using a fire-and-forget approach. Therefore, the
message is sent even if there are no subscribers registered to receive the message. In this situation, the sent
message is ignored.

Subscribe to a message
Subscribers can register to receive a message using one of the MessagingCenter.Subscribe overloads. The following
code example shows an example of this:

MessagingCenter.Subscribe<MainPage> (this, "Hi", (sender) =>


{
// Do something whenever the "Hi" message is received
});

In this example, the Subscribe method subscribes the this object to Hi messages that are sent by the MainPage
type, and executes a callback delegate in response to receiving the message. The callback delegate, specified as a
lambda expression, could be code that updates the UI, saves some data, or triggers some other operation.

NOTE
A subscriber might not need to handle every instance of a published message, and this can be controlled by the generic type
arguments that are specified on the Subscribe method.

The following example shows how to subscribe to a message that contains payload data:

MessagingCenter.Subscribe<MainPage, string>(this, "Hi", async (sender, arg) =>


{
await DisplayAlert("Message received", "arg=" + arg, "OK");
});

In this example, the Subscribe method subscribes to Hi messages that are sent by the MainPage type, whose
payload data is a string . A callback delegate is executed in response to receiving such a message, that displays the
payload data in an alert.
IMPORTANT
The delegate that's executed by the Subscribe method will be executed on the same thread that publishes the message
using the Send method.

Unsubscribe from a message


Subscribers can unsubscribe from messages they no longer want to receive. This is achieved with one of the
MessagingCenter.Unsubscribe overloads:

MessagingCenter.Unsubscribe<MainPage>(this, "Hi");

In this example, the Unsubscribe method unsubscribes the this object from the Hi message sent by the
MainPage type.

Messages containing payload data should be unsubscribed from using the Unsubscribe overload that specifies two
generic arguments:

MessagingCenter.Unsubscribe<MainPage, string>(this, "Hi");

In this example, the Unsubscribe method unsubscribes the this object from the Hi message sent by the
MainPage type, whose payload data is a string .

Related links
MessagingCenterSample
Xamarin.Forms Navigation
2 minutes to read • Edit Online

Xamarin.Forms provides a number of different page navigation experiences, depending upon the Page type being
used.

Alternatively, Xamarin.Forms Shell applications use a URI-based navigation experience that doesn't enforce a set
navigation hierarchy. For more information, see Xamarin.Forms Shell Navigation.

Hierarchical Navigation
The NavigationPage class provides a hierarchical navigation experience where the user is able to navigate through
pages, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO ) stack of
Page objects.

TabbedPage
The Xamarin.Forms TabbedPage consists of a list of tabs and a larger detail area, with each tab loading content into
the detail area.

CarouselPage
The Xamarin.Forms CarouselPage is a page that users can swipe from side to side to navigate through pages of
content, like a gallery.

MasterDetailPage
The Xamarin.Forms MasterDetailPage is a page that manages two pages of related information – a master page
that presents items, and a detail page that presents details about items on the master page.

Modal Pages
Xamarin.Forms also provides support for modal pages. A modal page encourages users to complete a self-
contained task that cannot be navigated away from until the task is completed or cancelled.
Hierarchical Navigation
10 minutes to read • Edit Online

Download the sample


The NavigationPage class provides a hierarchical navigation experience where the user is able to navigate
through pages, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO )
stack of Page objects. This article demonstrates how to use the NavigationPage class to perform navigation in a
stack of pages.
To move from one page to another, an application will push a new page onto the navigation stack, where it will
become the active page, as shown in the following diagram:

To return back to the previous page, the application will pop the current page from the navigation stack, and the
new topmost page becomes the active page, as shown in the following diagram:

Navigation methods are exposed by the Navigation property on any Page derived types. These methods provide
the ability to push pages onto the navigation stack, to pop pages from the navigation stack, and to perform stack
manipulation.

Performing Navigation
In hierarchical navigation, the NavigationPage class is used to navigate through a stack of ContentPage objects.
The following screenshots show the main components of the NavigationPage on each platform:

The layout of a NavigationPage is dependent on the platform:


On iOS, a navigation bar is present at the top of the page that displays a title, and that has a Back button that
returns to the previous page.
On Android, a navigation bar is present at the top of the page that displays a title, an icon, and a Back button
that returns to the previous page. The icon is defined in the [Activity] attribute that decorates the
MainActivityclass in the Android platform-specific project.
On the Universal Windows Platform, a navigation bar is present at the top of the page that displays a title.
On all the platforms, the value of the Page.Title property will be displayed as the page title.

NOTE
It's recommended that a NavigationPage should be populated with ContentPage instances only.

Creating the Root Page


The first page added to a navigation stack is referred to as the root page of the application, and the following code
example shows how this is accomplished:

public App ()
{
MainPage = new NavigationPage (new Page1Xaml ());
}

This causes the Page1Xaml ContentPage instance to be pushed onto the navigation stack, where it becomes the
active page and the root page of the application. This is shown in the following screenshots:

NOTE
The RootPage property of a NavigationPage instance provides access to the first page in the navigation stack.

Pushing Pages to the Navigation Stack


To navigate to Page2Xaml , it is necessary to invoke the PushAsync method on the Navigation property of the
current page, as demonstrated in the following code example:

async void OnNextPageButtonClicked (object sender, EventArgs e)


{
await Navigation.PushAsync (new Page2Xaml ());
}

This causes the Page2Xaml instance to be pushed onto the navigation stack, where it becomes the active page. This
is shown in the following screenshots:
When the PushAsync method is invoked, the following events occur:
The page calling PushAsync has its OnDisappearing override invoked.
The page being navigated to has its OnAppearing override invoked.
The PushAsync task completes.
However, the precise order in which these events occur is platform dependent. For more information, see Chapter
24 of Charles Petzold's Xamarin.Forms book.

NOTE
Calls to the OnDisappearing and OnAppearing overrides cannot be treated as guaranteed indications of page navigation.
For example, on iOS, the OnDisappearing override is called on the active page when the application terminates.

Popping Pages from the Navigation Stack


The active page can be popped from the navigation stack by pressing the Back button on the device, regardless of
whether this is a physical button on the device or an on-screen button.
To programmatically return to the original page, the Page2Xaml instance must invoke the PopAsync method, as
demonstrated in the following code example:

async void OnPreviousPageButtonClicked (object sender, EventArgs e)


{
await Navigation.PopAsync ();
}

This causes the Page2Xaml instance to be removed from the navigation stack, with the new topmost page
becoming the active page. When the PopAsync method is invoked, the following events occur:
The page calling PopAsync has its OnDisappearing override invoked.
The page being returned to has its OnAppearing override invoked.
The PopAsync task returns.

However, the precise order in which these events occur is platform dependent. For more information see Chapter
24 of Charles Petzold's Xamarin.Forms book.
As well as PushAsync and PopAsync methods, the Navigation property of each page also provides a
PopToRootAsync method, which is shown in the following code example:

async void OnRootPageButtonClicked (object sender, EventArgs e)


{
await Navigation.PopToRootAsync ();
}

This method pops all but the root Page off the navigation stack, therefore making the root page of the application
the active page.
Animating Page Transitions
The Navigation property of each page also provides overridden push and pop methods that include a boolean
parameter that controls whether to display a page animation during navigation, as shown in the following code
example:

async void OnNextPageButtonClicked (object sender, EventArgs e)


{
// Page appearance not animated
await Navigation.PushAsync (new Page2Xaml (), false);
}

async void OnPreviousPageButtonClicked (object sender, EventArgs e)


{
// Page appearance not animated
await Navigation.PopAsync (false);
}

async void OnRootPageButtonClicked (object sender, EventArgs e)


{
// Page appearance not animated
await Navigation.PopToRootAsync (false);
}

Setting the boolean parameter to false disables the page-transition animation, while setting the parameter to
true enables the page-transition animation, provided that it is supported by the underlying platform. However,
the push and pop methods that lack this parameter enable the animation by default.

Passing Data when Navigating


Sometimes it's necessary for a page to pass data to another page during navigation. Two techniques for
accomplishing this are passing data through a page constructor, and by setting the new page's BindingContext to
the data. Each will now be discussed in turn.
Passing Data through a Page Constructor
The simplest technique for passing data to another page during navigation is through a page constructor
parameter, which is shown in the following code example:

public App ()
{
MainPage = new NavigationPage (new MainPage (DateTime.Now.ToString ("u")));
}

This code creates a MainPage instance, passing in the current date and time in ISO8601 format, which is wrapped
in a NavigationPage instance.
The MainPage instance receives the data through a constructor parameter, as shown in the following code
example:
public MainPage (string date)
{
InitializeComponent ();
dateLabel.Text = date;
}

The data is then displayed on the page by setting the Label.Text property, as shown in the following screenshots:

Passing Data through a BindingContext


An alternative approach for passing data to another page during navigation is by setting the new page's
BindingContext to the data, as shown in the following code example:

async void OnNavigateButtonClicked (object sender, EventArgs e)


{
var contact = new Contact {
Name = "Jane Doe",
Age = 30,
Occupation = "Developer",
Country = "USA"
};

var secondPage = new SecondPage ();


secondPage.BindingContext = contact;
await Navigation.PushAsync (secondPage);
}

This code sets the BindingContext of the SecondPage instance to the Contact instance, and then navigates to the
SecondPage .

The SecondPage then uses data binding to display the Contact instance data, as shown in the following XAML
code example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PassingData.SecondPage"
Title="Second Page">
<ContentPage.Content>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Label Text="Name:" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" />
</StackLayout>
...
<Button x:Name="navigateButton" Text="Previous Page" Clicked="OnNavigateButtonClicked" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

The following code example shows how the data binding can be accomplished in C#:
public class SecondPageCS : ContentPage
{
public SecondPageCS ()
{
var nameLabel = new Label {
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
FontAttributes = FontAttributes.Bold
};
nameLabel.SetBinding (Label.TextProperty, "Name");
...
var navigateButton = new Button { Text = "Previous Page" };
navigateButton.Clicked += OnNavigateButtonClicked;

Content = new StackLayout {


HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Children = {
new StackLayout {
Orientation = StackOrientation.Horizontal,
Children = {
new Label{ Text = "Name:", FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.FillAndExpand },
nameLabel
}
},
...
navigateButton
}
};
}

async void OnNavigateButtonClicked (object sender, EventArgs e)


{
await Navigation.PopAsync ();
}
}

The data is then displayed on the page by a series of Label controls, as shown in the following screenshots:

For more information about data binding, see Data Binding Basics.

Manipulating the Navigation Stack


The Navigation property exposes a NavigationStack property from which the pages in the navigation stack can
be obtained. While Xamarin.Forms maintains access to the navigation stack, the Navigation property provides
the InsertPageBefore and RemovePage methods for manipulating the stack by inserting pages or removing them.
The InsertPageBefore method inserts a specified page in the navigation stack before an existing specified page, as
shown in the following diagram:
The RemovePage method removes the specified page from the navigation stack, as shown in the following
diagram:

These methods enable a custom navigation experience, such as replacing a login page with a new page, following
a successful login. The following code example demonstrates this scenario:

async void OnLoginButtonClicked (object sender, EventArgs e)


{
...
var isValid = AreCredentialsCorrect (user);
if (isValid) {
App.IsUserLoggedIn = true;
Navigation.InsertPageBefore (new MainPage (), this);
await Navigation.PopAsync ();
} else {
// Login failed
}
}

Provided that the user's credentials are correct, the MainPage instance is inserted into the navigation stack before
the current page. The PopAsync method then removes the current page from the navigation stack, with the
MainPage instance becoming the active page.

Displaying Views in the Navigation Bar


Any Xamarin.Forms View can be displayed in the navigation bar of a NavigationPage . This is accomplished by
setting the NavigationPage.TitleView attached property to a View . This attached property can be set on any Page
, and when the Page is pushed onto a NavigationPage , the NavigationPage will respect the value of the property.
The following example, taken from the Title View sample, shows how to set the NavigationPage.TitleView
attached property from XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="NavigationPageTitleView.TitleViewPage">
<NavigationPage.TitleView>
<Slider HeightRequest="44" WidthRequest="300" />
</NavigationPage.TitleView>
...
</ContentPage>

Here is the equivalent C# code:


public class TitleViewPage : ContentPage
{
public TitleViewPage()
{
var titleView = new Slider { HeightRequest = 44, WidthRequest = 300 };
NavigationPage.SetTitleView(this, titleView);
...
}
}

This results in a Slider being displayed in the navigation bar on the NavigationPage :

IMPORTANT
Many views won't appear in the navigation bar unless the size of the view is specified with the WidthRequest and
HeightRequest properties. Alternatively, the view can be wrapped in a StackLayout with the HorizontalOptions and
VerticalOptions properties set to appropriate values.

Note that, because the Layout class derives from the View class, the TitleView attached property can be set to
display a layout class that contains multiple views. On iOS and the Universal Windows Platform (UWP ), the
height of the navigation bar can't be changed, and so clipping will occur if the view displayed in the navigation bar
is larger than the default size of the navigation bar. However, on Android, the height of the navigation bar can be
changed by setting the NavigationPage.BarHeight bindable property to a double representing the new height. For
more information, see Setting the Navigation Bar Height on a NavigationPage.
Alternatively, an extended navigation bar can be suggested by placing some of the content in the navigation bar,
and some in a view at the top of the page content that you color match to the navigation bar. In addition, on iOS
the separator line and shadow that's at the bottom of the navigation bar can be removed by setting the
NavigationPage.HideNavigationBarSeparator bindable property to true . For more information, see Hiding the
Navigation Bar Separator on a NavigationPage.

NOTE
The BackButtonTitle , Title , TitleIcon , and TitleView properties can all define values that occupy space on the
navigation bar. While the navigation bar size varies by platform and screen size, setting all of these properties will result in
conflicts due to the limited space available. Instead of attempting to use a combination of these properties, you may find
that you can better achieve your desired navigation bar design by only setting the TitleView property.

Limitations
There are a number of limitations to be aware of when displaying a View in the navigation bar of a
NavigationPage :

On iOS, views placed in the navigation bar of a NavigationPage appear in a different position depending on
whether large titles are enabled. For more information about enabling large titles, see Displaying Large Titles.
On Android, placing views in the navigation bar of a NavigationPage can only be accomplished in apps that use
app-compat.
It's not recommended to place large and complex views, such as ListView and TableView , in the navigation
bar of a NavigationPage .

Related Links
Page Navigation
Hierarchical (sample)
PassingData (sample)
LoginFlow (sample)
TitleView (sample)
How to Create a Sign In Screen Flow in Xamarin.Forms video
NavigationPage
Xamarin.Forms TabbedPage
6 minutes to read • Edit Online

Download the sample


The Xamarin.Forms TabbedPage consists of a list of tabs and a larger detail area, with each tab loading content into
the detail area. The following screenshots show a TabbedPage on iOS and Android:

On iOS, the list of tabs appears at the bottom of the screen, and the detail area is above. Each tab consists of a title
and an icon, which should be a PNG file with an alpha channel. In portrait orientation, tab bar icons appear above
tab titles. In landscape orientation, icons and titles appear side by side. In addition, a regular or compact tab bar
may be displayed, depending on the device and orientation. If there are more than five tabs, a More tab will
appear, which can be used to access the additional tabs. For information about icon requirements, see Tab Bar Icon
Size on developer.apple.com.

TIP
The TabbedRenderer for iOS has an overridable GetIcon method that can be used to load tab icons from a specified
source. This override makes it possible to use SVG images as icons on a TabbedPage . In addition, selected and unselected
versions of an icon can be provided.

On Android, the list of tabs appears at the top of the screen, and the detail area is below. Each tab consists of a title
and an icon, which should be a PNG file with an alpha channel. However, the tabs can be moved to the bottom of
the screen with a platform-specific. If there are more than five tabs, and the tab list is at the bottom of the screen, a
More tab will appear that can be used to access the additional tabs. For information about icon requirements, see
Tabs on material.io and Support different pixel densities on developer.android.com. For information about moving
the tabs to the bottom of the screen, see Setting TabbedPage Toolbar Placement and Color.
TIP
The TabbedPageRenderer for Android AppCompat has an overridable GetIconDrawable method that can be used to load
tab icons from a custom Drawable . This override makes it possible to use SVG images as icons on a TabbedPage , and
works with both top and bottom tab bars. Alternatively, the overridable SetTabIcon method can be used to load tab icons
from a custom Drawable for top tab bars.

On the Universal Windows Platform (UWP ), the list of tabs appears at the top of the screen, and the details area is
below. Each tab consists of a title. However, icons can be added to each tab with a platform-specific. For more
information, see TabbedPage Icons on Windows.

Create a TabbedPage
Two approaches can be used to create a TabbedPage :
Populate the TabbedPage with a collection of child Page objects, such as a collection of ContentPage objects.
For more information, see Populate a TabbedPage with a Page Collection.
Assign a collection to the ItemsSource property and assign a DataTemplate to the ItemTemplate property to
return pages for objects in the collection. For more information, see Populate a TabbedPage with a template.
With both approaches, the TabbedPage will display each page as the user selects each tab.

IMPORTANT
It's recommended that a TabbedPage should be populated with NavigationPage and ContentPage instances only. This
will help to ensure a consistent user experience across all platforms.

In addition, TabbedPage defines the following properties:


BarBackgroundColor , of type Color , the background color of the tab bar.
BarTextColor , of type Color , the color of text on the tab bar.
SelectedTabColor , of type Color , the color of the tab when it's selected.
UnselectedTabColor , of type Color , the color of the tab when it's unselected.

All of these properties are backed by BindableProperty objects, which means that they can be styled, and the
properties can be the targets of data bindings.

WARNING
In a TabbedPage , each Page object is created when the TabbedPage is constructed. This can lead to a poor user
experience, particularly if the TabbedPage is the root page of the application. However, Xamarin.Forms Shell enables pages
accessed through a tab bar to be created on demand, in response to navigation. For more information, see Xamarin.Forms
Shell.

Populate a TabbedPage with a Page collection


A TabbedPage can be populated with a collection of child Page objects, such as a collection of ContentPage
objects. This is achieved by adding the Page objects to the TabbedPage.Children collection. This is accomplished in
XAML as follows:
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabbedPageWithNavigationPage;assembly=TabbedPageWithNavigationPage"
x:Class="TabbedPageWithNavigationPage.MainPage">
<local:TodayPage />
<NavigationPage Title="Schedule" IconImageSource="schedule.png">
<x:Arguments>
<local:SchedulePage />
</x:Arguments>
</NavigationPage>
</TabbedPage>

NOTE
The Children property of the MultiPage<T> class, from which TabbedPage derives, is the ContentProperty of
MultiPage<T> . Therefore, in XAML it's not necessary to explicitly assign the Page objects to the Children property.

The equivalent C# code is:

public class MainPageCS : TabbedPage


{
public MainPageCS ()
{
NavigationPage navigationPage = new NavigationPage (new SchedulePageCS ());
navigationPage.IconImageSource = "schedule.png";
navigationPage.Title = "Schedule";

Children.Add (new TodayPageCS ());


Children.Add (navigationPage);
}
}

In this example, the TabbedPage is populated with two Page objects. The first child is a ContentPage object, and
the second child is a NavigationPage containing a ContentPage object.
The following screenshots show a ContentPage object in a TabbedPage :
Selecting another tab displays the ContentPage object that represents the tab:

On the Schedule tab, the ContentPage object is wrapped in a NavigationPage object.

WARNING
While a NavigationPage can be placed in a TabbedPage , it's not recommended to place a TabbedPage into a
NavigationPage . This is because, on iOS, a UITabBarController always acts as a wrapper for the
UINavigationController . For more information, see Combined View Controller Interfaces in the iOS Developer Library.

Navigate within a tab


Navigation can be performed within a tab, provided that the ContentPage object is wrapped in a NavigationPage
object. This is accomplished by invoking the PushAsync method on the Navigation property of the ContentPage
object:

await Navigation.PushAsync (new UpcomingAppointmentsPage ());

The page being navigated to is specified as the argument to the PushAsync method. In this example, the
UpcomingAppointmentsPage page is pushed onto the navigation stack, where it becomes the active page:
For more information about performing navigation using the NavigationPage class, see Hierarchical Navigation.

Populate a TabbedPage with a template


A TabbedPage can be populated with pages by assigning a collection of data to the ItemsSource property, and by
assigning a DataTemplate to the ItemTemplate property that templates the data as Page objects. This is
accomplished in XAML as follows:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TabbedPageDemo;assembly=TabbedPageDemo"
x:Class="TabbedPageDemo.TabbedPageDemoPage"
ItemsSource="{x:Static local:MonkeyDataModel.All}">
<TabbedPage.Resources>
<ResourceDictionary>
<local:NonNullToBooleanConverter x:Key="booleanConverter" />
</ResourceDictionary>
</TabbedPage.Resources>
<TabbedPage.ItemTemplate>
<DataTemplate>
<ContentPage Title="{Binding Name}" IconImageSource="monkeyicon.png">
<StackLayout Padding="5, 25">
<Label Text="{Binding Name}" Font="Bold,Large" HorizontalOptions="Center" />
<Image Source="{Binding PhotoUrl}" WidthRequest="200" HeightRequest="200" />
<StackLayout Padding="50, 10">
<StackLayout Orientation="Horizontal">
<Label Text="Family:" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Family}" Font="Bold,Medium" />
</StackLayout>
...
</StackLayout>
</StackLayout>
</ContentPage>
</DataTemplate>
</TabbedPage.ItemTemplate>
</TabbedPage>

The equivalent C# code is:


public class TabbedPageDemoPageCS : TabbedPage
{
public TabbedPageDemoPageCS ()
{
var booleanConverter = new NonNullToBooleanConverter ();

ItemTemplate = new DataTemplate (() =>


{
var nameLabel = new Label
{
FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Center
};
nameLabel.SetBinding (Label.TextProperty, "Name");

var image = new Image { WidthRequest = 200, HeightRequest = 200 };


image.SetBinding (Image.SourceProperty, "PhotoUrl");

var familyLabel = new Label


{
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
FontAttributes = FontAttributes.Bold
};
familyLabel.SetBinding (Label.TextProperty, "Family");
...

var contentPage = new ContentPage


{
IconImageSource = "monkeyicon.png",
Content = new StackLayout {
Padding = new Thickness (5, 25),
Children =
{
nameLabel,
image,
new StackLayout
{
Padding = new Thickness (50, 10),
Children =
{
new StackLayout
{
Orientation = StackOrientation.Horizontal,
Children =
{
new Label { Text = "Family:", HorizontalOptions = LayoutOptions.FillAndExpand },
familyLabel
}
},
// ...
}
}
}
}
};
contentPage.SetBinding (TitleProperty, "Name");
return contentPage;
});
ItemsSource = MonkeyDataModel.All;
}
}

In this example, each tab consists of a ContentPage object that uses Image and Label objects to display data for
the tab:
Selecting another tab displays the ContentPage object that represents the tab.

Related links
TabbedPageWithNavigationPage (sample)
TabbedPage (sample)
Hierarchical Navigation
Page Varieties
TabbedPage API
Xamarin.Forms Carousel Page
3 minutes to read • Edit Online

Download the sample


The Xamarin.Forms CarouselPage is a page that users can swipe from side to side to navigate through pages of
content, like a gallery. This article demonstrates how to use a CarouselPage to navigate through a collection of
pages.

IMPORTANT
The CarouselPage has been superseded by the CarouselView , which provides a scrollable layout where users can swipe
to move through a collection of items. For more information about the CarouselView , see Xamarin.Forms CarouselView.

The following screenshots show a CarouselPage on each platform:

The layout of a CarouselPage is identical on each platform. Pages can be navigated through by swiping right to left
to navigate forwards through the collection, and by swiping left to right to navigate backwards through the
collection. The following screenshots show the first page in a CarouselPage instance:
Swiping from right to left moves to the second page, as shown in the following screenshots:

Swiping from right to left again moves to the third page, while swiping from left to right returns to the previous
page.

NOTE
The CarouselPage does not support UI virtualization. Therefore, performance may be affected if the CarouselPage
contains too many child elements.

If a is embedded into the Detail page of a MasterDetailPage , the


CarouselPage
MasterDetailPage.IsGestureEnabled property should be set to false to prevent gesture conflicts between the
CarouselPage and the MasterDetailPage .

For more information about the CarouselPage , see Chapter 25 of Charles Petzold's Xamarin.Forms book.

Create a CarouselPage
Two approaches can be used to create a CarouselPage :
Populate the CarouselPage with a collection of child ContentPage instances.
Assign a collection to the ItemsSource property and assign a DataTemplate to the ItemTemplate property to
return ContentPage instances for objects in the collection.
With both approaches, the CarouselPage will then display each page in turn, with a swipe interaction moving to
the next page to be displayed.

NOTE
A CarouselPage can only be populated with ContentPage instances, or ContentPage derivatives.

Populate a CarouselPage with a Page collection


The following XAML code example shows a CarouselPage that displays three ContentPage instances:
<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CarouselPageNavigation.MainPage">
<ContentPage>
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS, Android" Value="0,40,0,0" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout>
<Label Text="Red" FontSize="Medium" HorizontalOptions="Center" />
<BoxView Color="Red" WidthRequest="200" HeightRequest="200" HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
<ContentPage>
...
</ContentPage>
<ContentPage>
...
</ContentPage>
</CarouselPage>

The following code example shows the equivalent UI in C#:


public class MainPageCS : CarouselPage
{
public MainPageCS ()
{
Thickness padding;
switch (Device.RuntimePlatform)
{
case Device.iOS:
case Device.Android:
padding = new Thickness(0, 40, 0, 0);
break;
default:
padding = new Thickness();
break;
}

var redContentPage = new ContentPage {


Padding = padding,
Content = new StackLayout {
Children = {
new Label {
Text = "Red",
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.Center
},
new BoxView {
Color = Color.Red,
WidthRequest = 200,
HeightRequest = 200,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
}
}
}
};
var greenContentPage = new ContentPage {
Padding = padding,
Content = new StackLayout {
...
}
};
var blueContentPage = new ContentPage {
Padding = padding,
Content = new StackLayout {
...
}
};

Children.Add (redContentPage);
Children.Add (greenContentPage);
Children.Add (blueContentPage);
}
}

Each ContentPage simply displays a Label for a particular color and a BoxView of that color.
Populate a CarouselPage with a template
The following XAML code example shows a CarouselPage constructed by assigning a DataTemplate to the
ItemTemplate property to return pages for objects in the collection:
<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CarouselPageNavigation.MainPage">
<CarouselPage.ItemTemplate>
<DataTemplate>
<ContentPage>
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS, Android" Value="0,40,0,0" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout>
<Label Text="{Binding Name}" FontSize="Medium" HorizontalOptions="Center" />
<BoxView Color="{Binding Color}" WidthRequest="200" HeightRequest="200"
HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
</DataTemplate>
</CarouselPage.ItemTemplate>
</CarouselPage>

The CarouselPage is populated with data by setting the ItemsSource property in the constructor for the code-
behind file:

public MainPage ()
{
...
ItemsSource = ColorsDataModel.All;
}

The following code example shows the equivalent CarouselPage created in C#:
public class MainPageCS : CarouselPage
{
public MainPageCS ()
{
Thickness padding;
switch (Device.RuntimePlatform)
{
case Device.iOS:
case Device.Android:
padding = new Thickness(0, 40, 0, 0);
break;
default:
padding = new Thickness();
break;
}

ItemTemplate = new DataTemplate (() => {


var nameLabel = new Label {
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.Center
};
nameLabel.SetBinding (Label.TextProperty, "Name");

var colorBoxView = new BoxView {


WidthRequest = 200,
HeightRequest = 200,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
colorBoxView.SetBinding (BoxView.ColorProperty, "Color");

return new ContentPage {


Padding = padding,
Content = new StackLayout {
Children = {
nameLabel,
colorBoxView
}
}
};
});

ItemsSource = ColorsDataModel.All;
}
}

Each ContentPage simply displays a Label for a particular color and a BoxView of that color.

Related links
Page Varieties
CarouselPage (sample)
CarouselPageTemplate (sample)
CarouselPage
Xamarin.Forms Master-Detail Page
8 minutes to read • Edit Online

Download the sample


The Xamarin.Forms MasterDetailPage is a page that manages two related pages of information – a master page
that presents items, and a detail page that presents details about items on the master page. This article explains
how to use a MasterDetailPage and navigate between its pages of information.

Overview
A master page typically displays a list of items, as shown in the following screenshots:

The location of the list of items is identical on each platform, and selecting one of the items will navigate to the
corresponding detail page. In addition, the master page also features a navigation bar that contains a button that
can be used to navigate to the active detail page:
On iOS, the navigation bar is present at the top of the page and has a button that navigates to the detail page.
In addition, the active detail page can be navigated to by swiping the master page to the left.
On Android, the navigation bar is present at the top of the page and displays a title, an icon, and a button that
navigates to the detail page. The icon is defined in the [Activity] attribute that decorates the MainActivity
class in the Android platform-specific project. In addition, the active detail page can be navigated to by swiping
the master page to the left, by tapping the detail page at the far right of the screen, and by tapping the Back
button at the bottom of the screen.
On the Universal Windows Platform (UWP ), the navigation bar is present at the top of the page and has a
button that navigates to the detail page.
A detail page displays data that corresponds to the item selected on the master page, and the main components of
the detail page are shown in the following screenshots:
The detail page contains a navigation bar, whose contents are platform-dependent:
On iOS, the navigation bar is present at the top of the page and displays a title, and has a button that returns to
the master page, provided that the detail page instance is wrapped in the NavigationPage instance. In addition,
the master page can be returned to by swiping the detail page to the right.
On Android, a navigation bar is present at the top of the page and displays a title, an icon, and a button that
returns to the master page. The icon is defined in the [Activity] attribute that decorates the MainActivity
class in the Android platform-specific project.
On UWP, the navigation bar is present at the top of the page and displays a title, and has a button that returns
to the master page.
Navigation Behavior
The behavior of the navigation experience between master and detail pages is platform dependent:
On iOS, the detail page slides to the right as the master page slides from the left, and the left part of the detail
page is still visible.
On Android, the detail and master pages are overlaid on each other.
On UWP, the master page slides from the left over part of the detail page, provided that the MasterBehavior
property is set to Popover . For more information, see Controlling the Detail Page Display Behavior.
Similar behavior will be observed in landscape mode, except that the master page on iOS and Android has a
similar width as the master page in portrait mode, so more of the detail page will be visible.
For information about controlling the navigation behavior, see Controlling the Detail Page Display Behavior.

Creating a MasterDetailPage
A MasterDetailPage contains Master and Detail properties that are both of type Page , which are used to get
and set the master and detail pages respectively.

IMPORTANT
A MasterDetailPage is designed to be a root page, and using it as a child page in other page types could result in
unexpected and inconsistent behavior. In addition, it's recommended that the master page of a MasterDetailPage should
always be a ContentPage instance, and that the detail page should only be populated with TabbedPage , NavigationPage
, and ContentPage instances. This will help to ensure a consistent user experience across all platforms.

The following XAML code example shows a MasterDetailPage that sets the Master and Detail properties:

<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
x:Class="MasterDetailPageNavigation.MainPage">
<MasterDetailPage.Master>
<local:MasterPage x:Name="masterPage" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<local:ContactsPage />
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>

The following code example shows the equivalent MasterDetailPage created in C#:
public class MainPageCS : MasterDetailPage
{
MasterPageCS masterPage;

public MainPageCS ()
{
masterPage = new MasterPageCS ();
Master = masterPage;
Detail = new NavigationPage (new ContactsPageCS ());
...
}
...
}

The MasterDetailPage.Master property is set to a ContentPage instance. The MasterDetailPage.Detail property is


set to a NavigationPage containing a ContentPage instance.
Creating the Master Page
The following XAML code example shows the declaration of the MasterPage object, which is referenced through
the MasterDetailPage.Master property:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:MasterDetailPageNavigation"
x:Class="MasterDetailPageNavigation.MasterPage"
Padding="0,40,0,0"
IconImageSource="hamburger.png"
Title="Personal Organiser">
<StackLayout>
<ListView x:Name="listView" x:FieldModifier="public">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:MasterPageItem}">
<local:MasterPageItem Title="Contacts" IconSource="contacts.png" TargetType="{x:Type
local:ContactsPage}" />
<local:MasterPageItem Title="TodoList" IconSource="todo.png" TargetType="{x:Type
local:TodoListPage}" />
<local:MasterPageItem Title="Reminders" IconSource="reminders.png" TargetType="{x:Type
local:ReminderPage}" />
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding IconSource}" />
<Label Grid.Column="1" Text="{Binding Title}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>

The page consists of a ListView that's populated with data in XAML by setting its ItemsSource property to an
array of MasterPageItem instances. Each MasterPageItem defines Title , IconSource , and TargetType properties.
A DataTemplate is assigned to the ListView.ItemTemplate property, to display each MasterPageItem . The
DataTemplate contains a ViewCell that consists of an Image and a Label . The Image displays the IconSource
property value, and the Label displays the Title property value, for each MasterPageItem .
The page has its Title and IconImageSource properties set. The icon will appear on the detail page, provided that
the detail page has a title bar. This must be enabled on iOS by wrapping the detail page instance in a
NavigationPage instance.

NOTE
The MasterDetailPage.Master page must have its Title property set, or an exception will occur.

The following code example shows the equivalent page created in C#:
public class MasterPageCS : ContentPage
{
public ListView ListView { get { return listView; } }

ListView listView;

public MasterPageCS ()
{
var masterPageItems = new List<MasterPageItem> ();
masterPageItems.Add (new MasterPageItem {
Title = "Contacts",
IconSource = "contacts.png",
TargetType = typeof(ContactsPageCS)
});
masterPageItems.Add (new MasterPageItem {
Title = "TodoList",
IconSource = "todo.png",
TargetType = typeof(TodoListPageCS)
});
masterPageItems.Add (new MasterPageItem {
Title = "Reminders",
IconSource = "reminders.png",
TargetType = typeof(ReminderPageCS)
});

listView = new ListView {


ItemsSource = masterPageItems,
ItemTemplate = new DataTemplate (() => {
var grid = new Grid { Padding = new Thickness(5, 10) };
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(30) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });

var image = new Image();


image.SetBinding(Image.SourceProperty, "IconSource");
var label = new Label { VerticalOptions = LayoutOptions.FillAndExpand };
label.SetBinding(Label.TextProperty, "Title");

grid.Children.Add(image);
grid.Children.Add(label, 1, 0);

return new ViewCell { View = grid };


}),
SeparatorVisibility = SeparatorVisibility.None
};

IconImageSource = "hamburger.png";
Title = "Personal Organiser";
Content = new StackLayout
{
Children = { listView }
};
}
}

The following screenshots show the master page on each platform:


Creating and Displaying the Detail Page
The MasterPage instance contains a ListView property that exposes its ListView instance so that the MainPage
MasterDetailPage instance can register an event-handler to handle the ItemSelected event. This enables the
MainPage instance to set the Detail property to the page that represents the selected ListView item. The
following code example shows the event-handler:

public partial class MainPage : MasterDetailPage


{
public MainPage ()
{
...
masterPage.listView.ItemSelected += OnItemSelected;
}

void OnItemSelected (object sender, SelectedItemChangedEventArgs e)


{
var item = e.SelectedItem as MasterPageItem;
if (item != null) {
Detail = new NavigationPage ((Page)Activator.CreateInstance (item.TargetType));