Xaml PDF
Xaml PDF
Xamarin.Forms
Get Started
Requirements
Installation
Build your first app
Single page quickstart
Multi-page quickstart
Local database quickstart
Styling quickstart
Deep dive
XAML
XAML Controls
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 Compilation
XAML Toolbox
XAML Previewer
Design-time data
Custom controls
XAML Namespaces
XAML Custom Namespace Schemas
XAML Namespace Recommended Prefixes
XAML Markup Extensions
Consuming XAML Markup Extensions
Creating XAML Markup Extensions
Field Modifiers
Passing Arguments
Bindable Properties
Attached Properties
Resource Dictionaries
XAML Standard (Preview)
Controls
Loading XAML at Runtime
Application Fundamentals
Accessibility
Automation Properties
Keyboard Navigation
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
Highlighting a Region on a Map
Highlighting a Route on a Map
Customizing a ListView
Customizing a ViewCell
Implementing a View
Implementing a HybridWebView
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
Binding Fallbacks
The Command Interface
Compiled Bindings
DependencyService
Introduction
Implementing Text-to-Speech
Checking Device Orientation
Checking Battery Status
Picking from the Photo Library
Effects
Introduction
Effect Creation
Passing Parameters
Parameters as CLR Properties
Parameters as Attached Properties
Invoking Events
Files
Gestures
Tap
Pinch
Pan
Swipe
Localization
String and Image Localization
Right-to-Left Localization
Local Databases
MessagingCenter
Navigation
Hierarchical Navigation
TabbedPage
CarouselPage
MasterDetailPage
Modal Pages
Displaying Pop-Ups
Shell
Templates
Control Templates
Introduction
Control Template Creation
Template Bindings
Data Templates
Introduction
Data Template Creation
Data Template Selection
Triggers
User Interface
Animation
Animation
Simple Animations
Easing Functions
Custom Animations
BoxView
Button
CollectionView
Data
Layout
Selection
EmptyView
Scrolling
Colors
Controls Reference
Pages
Layouts
Views
Cells
DataPages
Get Started
Controls Reference
DatePicker
Graphics with SkiaSharp
Images
ImageButton
Layouts
StackLayout
AbsoluteLayout
RelativeLayout
Grid
FlexLayout
ScrollView
LayoutOptions
Margin and Padding
Device Orientation
Tablet & Desktop
Bindable Layouts
Creating a Custom Layout
Layout Compression
ListView
Data Sources
Cell Appearance
List Appearance
Interactivity
Performance
Maps
Picker
Setting a Picker's ItemsSource Property
Adding Data to a Picker's Items Collection
Slider
Stepper
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)
TableView
Text
Label
Entry
Editor
Fonts
Styles
Themes
Light Theme
Dark Theme
Creating a Custom Theme
TimePicker
Visual
Material Visual
Create a Visual Renderer
Visual State Manager
WebView
Platform Features
Android
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
TabbedPage Page Swiping
TabbedPage Page Transition Animations
TabbedPage Toolbar Placement and Color
VisualElement Elevation
VisualElement Legacy Color Mode
WebView Mixed Content
Device Class
iOS
Cell Background Color
Entry Cursor Color
Entry Font Size
Formatting
iPad 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 Status Bar Visibility
Picker Item Selection
Safe Area Layout Guide
ScrollView Content Touches
Simultaneous Pan Gesture Recognition
Slider Thumb Tap
VisualElement Blur
VisualElement Drop Shadows
VisualElement Legacy Color Mode
Native Forms
Native Views
Native Views in XAML
Native Views in C#
Other Platforms
GTK#
Mac
Tizen
WPF
Platform Specifics
Windows
InputView Reading Order
ListView SelectionMode
MasterDetailPage Navigation Bar
Page Toolbar Placement
Platform Setup
SearchBar Spell Check
TabbedPage Icons
VisualElement Access Keys
VisualElement Legacy Color Mode
WebView JavaScript Alerts
Xamarin.Essentials
Get Started
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
Troubleshooting
Data & Cloud Services
Understanding the Sample
Consuming Web Services
ASMX
WCF
REST
Azure Mobile Apps
Authenticating Access to Web Services
REST
OAuth
Azure Mobile Apps
Azure Active Directory B2C
Integrating Azure Active Directory B2C with Azure Mobile Apps
Synchronizing Data with Web Services
Azure Mobile Apps
Sending Push Notifications
Azure
Storing Files in the Cloud
Azure Storage
Searching Data in the Cloud
Azure Search
Serverless Applications
Azure Functions
Storing Data in a Document Database
Consuming an Azure Cosmos DB Document Database
Authenticating Users with an Azure Cosmos DB Document Database
Adding Intelligence with Cognitive Services
Speech Recognition
Spell Check
Text Translation
Emotion Recognition
Deployment & Testing
Publishing iOS apps
Publishing Android apps
Publishing UWP apps
Publishing Mac apps
Performance
Automated Testing with Visual Studio App Center
Advanced Concepts and Internals
Dependency Resolution
Fast Renderers
.NET Standard
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
Xamarin.Forms Requirements
5/1/2019 • 2 minutes to read • Edit Online
Target platforms
Xamarin.Forms applications can be written for the following operating systems:
iOS 8 or higher
Android 5.0 (API 21) or higher (more details)
Windows 10 Universal Windows Platform (more details)
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
NOTE
Windows apps cannot be developed on macOS.
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
4/2/2019 • 2 minutes to read • Edit Online
How to set up Visual Studio and Xamarin to start building mobile apps with .NET.
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:
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:
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
Build your first Xamarin.Forms App
4/16/2019 • 2 minutes to read • Edit Online
Watch this video and follow along to create your first mobile app with Xamarin.Forms.
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. Launch Android emulator by pressing the debug button (or the Debug > Start Debugging menu item).
7. Edit MainPage.xaml, adding this XAML before the end of the </StackLayout> :
int count = 0;
void Button_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}
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.
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> :
int count = 0;
void Button_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}
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> :
int count = 0;
void Handle_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}
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.
Create a Single Page Xamarin.Forms Application
4/2/2019 • 12 minutes to read • Edit Online
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.
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:
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);
}
}
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:
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:
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.
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);
}
}
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:
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:
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:
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);
}
}
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:
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
4/2/2019 • 14 minutes to read • Edit Online
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.
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();
}
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();
}
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:
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();
}
listView.ItemsSource = notes
.OrderBy(d => d.Date)
.ToList();
}
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.
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();
}
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();
}
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:
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();
}
listView.ItemsSource = notes
.OrderBy(d => d.Date)
.ToList();
}
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
4/2/2019 • 9 minutes to read • Edit Online
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.
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;
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 App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
...
}
}
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:
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:
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.
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;
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 App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
...
}
}
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:
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:
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
1/30/2019 • 5 minutes to read • Edit Online
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.
<Thickness x:Key="PageMargin">20</Thickness>
</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 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="BorderRadius" Value="5" />
</Style>
</ContentPage.Resources>
</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.
<Thickness x:Key="PageMargin">20</Thickness>
</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 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 choosing File > Save (or by pressing ⌘ + 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="BorderRadius" Value="5" />
</Style>
</ContentPage.Resources>
</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
4/2/2019 • 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.
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.
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());
}
}
}
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 :
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.
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 :
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:
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:
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();
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()
});
}
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:
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>
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>
For more information about XAML markup extensions, see XAML Markup Extensions. For information
about the OnPlatform markup extension, see OnPlatform Markup Extension.
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)
eXtensible Application Markup Language (XAML)
5/2/2019 • 2 minutes to read • Edit Online
XAML is a declarative markup language that can be used to define user interfaces. The user interface is defined in
an XML file using the XAML syntax, while runtime behavior is defined in a separate code-behind file.
XAML Controls
All of the views that are defined in Xamarin.Forms can be referenced from XAML files.
XAML Basics
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 toolable, and is often more visually coherent and
more succinct than equivalent code. XAML is particularly well suited for use with the popular Model-View -
ViewModel (MVVM ) application architecture: XAML defines the View that is linked to ViewModel code through
XAML -based data bindings.
XAML Compilation
XAML can be optionally compiled directly into intermediate language (IL ) with the XAML compiler (XAMLC ). This
articles describes how to use XAMLC, and its benefits.
XAML Previewer
The XAML Previewer renders a live preview of a page side-by-side with the XAML markup, allowing you to see
your user interface rendered as you type.
XAML Namespaces
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.
Field Modifiers
The x:FieldModifier namespace attribute specifies the access level for generated fields for named XAML
elements.
Passing Arguments
XAML can be used to pass arguments to non-default constructors or to factory methods. This article demonstrates
using the XAML attributes that can be used to pass arguments to constructors, to call factory methods, and to
specify the type of a generic argument.
Bindable Properties
In Xamarin.Forms, the functionality of common language runtime (CLR ) properties is extended by bindable
properties. A bindable property is a special type of property, where the property's value is tracked by the
Xamarin.Forms property system. This article provides an introduction to bindable properties, and demonstrates
how to create and consume them.
Attached Properties
An attached property is a special type of bindable property, defined in one class but attached to other objects, and
recognizable in XAML as an attribute that contains a class and a property name separated by a period. This article
provides an introduction to attached properties, and demonstrates how to create and consume them.
Resource Dictionaries
XAML resources are definitions of objects that can be used more than once. A ResourceDictionary allows
resources to be defined in a single location, and re-used throughout a Xamarin.Forms application. This article
demonstrates how to create and consume a ResourceDictionary , and how to merge one ResourceDictionary into
another.
All of the views that are defined in Xamarin.Forms can be referenced from XAML files.
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
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
SearchBar
<SearchBar Placeholder="Xamarin.Forms Property"
Displays a search bar, for performing a search.
SearchButtonPressed="OnSearchBarButtonPressed" />
API
Views for setting values
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
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
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
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
ProgressBar
<ProgressBar Progress=".5"
Displays an animation to show that the application is VerticalOptions="CenterAndExpand" />
progressing through a lengthy activity.
API
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
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
Xamarin.Forms XAML Basics
4/2/2019 • 3 minutes to read • Edit Online
XAML topics are covered in more depth in many chapters of the book, including:
Overview
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 is also part of Xamarin.Forms, the cross-platform natively-based programming interface for iOS, Android,
and UWP mobile devices. Within the 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.
Of course, 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 obviously 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
Part 1. Getting Started with XAML
12/7/2018 • 15 minutes to read • Edit Online
Select a location for the solution, give it a name of XamlSamples (or whatever you prefer), and press OK.
On the next screen, select the Blank App template and the .NET Standard code-sharing strategy:
Press OK.
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.
<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>
</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
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();
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="“Hello, XAML!”" … />
<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" />
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();
}
}
}
}
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:
Or, the handler could obtain the Slider object that is generating this event from the sender argument and
obtain the Value property from that:
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:
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:
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
12/7/2018 • 9 minutes to read • Edit Online
Property Elements
In XAML, properties of classes are normally set as XML attributes:
However, there is an alternative way to set a property in XAML. To try this alternative with TextColor , first delete
the existing TextColor setting:
Open up the empty-element Label tag by separating it into start and end tags:
</Label>
Within these tags, add start and end tags that consist of the class name and a property name separated by a
period:
</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:
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
<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>
<BoxView Color="Silver"
HeightRequest="0"
Grid.Row="0" Grid.Column="1" />
<BoxView Color="Teal"
Grid.Row="1" Grid.Column="0" />
</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>
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" />
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.
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>
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
3/14/2019 • 11 minutes to read • Edit Online
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" />
</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>
<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:
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:
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:
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}" />
</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.
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;
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" />
<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>
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
2/18/2019 • 11 minutes to read • Edit Online
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" />
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:
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>
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.
<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">
</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:
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>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Orientation="Horizontal"
<StackLayout Orientation="Horizontal"
Spacing="0">
<Label Text="{Binding Color.R,
Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat='R={0:X2}'}" />
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.
namespace XamlSamples
{
class DoubleToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
double multiplier;
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:
Three data bindings reference this single instance. Notice that the Binding markup extension contains an
embedded StaticResource markup extension:
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
12/7/2018 • 13 minutes to read • Edit Online
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 :
BindingContext is a very 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>
</ContentPage>
Of course, the big 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, very
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 , but which updates that DateTime
property every second:
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace XamlSamples
{
class ClockViewModel : INotifyPropertyChanged
{
DateTime dateTime;
public ClockViewModel()
{
this.DateTime = DateTime.Now;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
this.DateTime = DateTime.Now;
return true;
});
}
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">
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:
Interactive MVVM
MVVM is quite 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
{
public class HslViewModel : INotifyPropertyChanged
{
double hue, saturation, luminosity;
Color color;
void SetNewColor()
{
Color = Color.FromHsla(Hue, Saturation, Luminosity);
}
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 actually 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>
The binding on each Label is the default OneWay . It only needs to display the value. But the binding on each
Slider is . This allows the Slider to be initialized from the ViewModel. Notice that the Color property
TwoWay
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.
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 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 in 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 = { '*', '#' };
// Constructor
public KeypadViewModel()
{
AddCharCommand = new Command<string>((key) =>
{
// Add the key to the input string.
InputString += key;
});
// Public properties
public string InputString
{
protected set
{
if (inputString != value)
{
{
inputString = value;
OnPropertyChanged("InputString");
DisplayText = FormatText(inputString);
// ICommand implementations
public ICommand AddCharCommand { protected set; get; }
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>
<Frame Grid.Column="0"
OutlineColor="Accent">
<Label Text="{Binding DisplayText}" />
</Frame>
<Button Text="⇦"
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" />
<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:
This indicates that the DownloadAsync method is a Task and should be awaited:
void Download ()
{
...
}
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">
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:
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
XAML Compilation in Xamarin.Forms
11/12/2018 • 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
Xamarin.Forms XAML Toolbox
8/30/2018 • 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
4/2/2019 • 2 minutes to read • Edit Online
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:
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
4/25/2019 • 2 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.
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.
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:
<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.
Refer to James Montemagno's Hanselman.Forms app for a more complex example.
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
4/2/2019 • 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.
namespace MyProject
{
[DesignTimeVisible(true)]
public class MyControl : BaseControl
{
// Your control's code here
}
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/8/2019 • 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).
CONSTRUCT DESCRIPTION
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:FieldModifier Specifies the access level for generated fields for named XAML
elements.
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.
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/6/2019 • 3 minutes to read • Edit Online
<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.
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.
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 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:
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
XAML Markup Extensions
12/7/2018 • 2 minutes to read • Edit Online
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:
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:
Related Links
Markup Extensions (sample)
XAML markup extensions chapter from Xamarin.Forms book
Resource Dictionaries
Dynamic Styles
Data Binding
Consuming XAML Markup Extensions
2/6/2019 • 14 minutes to read • Edit Online
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 Binding from a
Control Template.
The RelativeLayout layout makes use of the custom markup extension ConstraintExpression . This markup
extension is described in the article RelativeLayout.
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 :
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:
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:
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:
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 :
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>
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">
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />
</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:
<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}" />
···
</TableRoot>
</TableView>
</ContentPage>
BindingContext = this;
}
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">
BindingContext = this;
}
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>
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:
Towards the end of this article, you'll see a custom XAML markup extension that also creates a new color value:
When defining arrays of common types like strings or numbers, use the tags listed in the Passing Constructor
Arguments article to delimit the values.
<ContentPage.Content>
<StackLayout Padding="10, 0">
<Label Text="Text 1" />
<Label Text="Text 2" />
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.
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:
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 extensions 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:
Related Links
Markup Extensions (sample)
XAML markup extensions chapter from Xamarin.Forms book
Resource Dictionaries
Dynamic Styles
Data Binding
Creating XAML Markup Extensions
12/21/2018 • 5 minutes to read • Edit Online
The two IMarkupExtension interfaces define only one method each, named ProvideValue :
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.
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>
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>
</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:
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 Field Modifiers in Xamarin.Forms
6/20/2018 • 2 minutes to read • Edit Online
The x:FieldModifier namespace attribute specifies the access level for generated fields for named XAML
elements.
Overview
Valid values of the attribute are:
Public – specifies that the generated field for the XAML element is public .
NotPublic – specifies that the generated field for the XAML element is internal to the assembly.
If the value of the attribute isn't set, the generated field for the element will be private .
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:
NOTE
The x:FieldModifier attribute cannot be used to specify the access level of a XAML class.
Passing Arguments in XAML
12/7/2018 • 3 minutes to read • Edit Online
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.
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)
Bindable Properties
12/7/2018 • 8 minutes to read • Edit Online
Overview
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 .
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 Detecting 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 Creating a Default Value
with a Func.
Creating 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:
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>
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.
Detecting 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:
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:
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:
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.
Creating 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:
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.
Summary
This article provided an introduction to bindable properties, and demonstrated how to create and consume them.
A bindable property is a special type of property, where the property's value is tracked by the Xamarin.Forms
property system.
Related Links
XAML Namespaces
Event To Command Behavior (sample)
Validation Callback (sample)
Coerce Value Callback (sample)
BindableProperty
BindableObject
Attached Properties
12/7/2018 • 4 minutes to read • Edit Online
Overview
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.
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:
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 Creating and Consuming a Bindable Property.
Creating 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:
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:
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:
The namespace declaration is then used when setting the attached property on a specific control, as
demonstrated in the following XAML code example:
The Style can 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:
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.
Summary
This article provided an introduction to attached properties, and demonstrated how to create and consume them.
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.
Related Links
Bindable Properties
XAML Namespaces
Shadow Effect (sample)
BindableProperty
BindableObject
Resource Dictionaries
12/7/2018 • 8 minutes to read • Edit Online
Overview
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.
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.
Overriding 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:
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.
<ContentPage ...>
<ContentPage.Resources>
<local:MyResourceDictionary />
</ContentPage.Resources>
...
</ContentPage>
IMPORTANT
ResourceDictionary also defines a MergedWith property. Do not use this property; it has been deprecated as of
Xamarin.Forms 3.0.
That markup shows only an instance of MyResourceDictionary being added to the ResourceDictionary but you
can also reference other ResourceDictionary instances within the MergedDictionary property-element tags, and
other resources outside of those tags:
<ContentPage ...>
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyResourceDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
There can be only one MergedDictionaries section in a ResourceDictionary , but you can put as many
ResourceDictionary instances 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 dictionary that was merged via the deprecated MergedWith property.
3. 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.
<ContentPage ...>
<ContentPage.Resources>
<ResourceDictionary>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Because Xamarin.Forms 3.0 automatically instantiates the ResourceDictionary , those two outer
ResourceDictionary tags are no longer required:
<ContentPage ...>
<ContentPage.Resources>
</ContentPage.Resources>
...
</ContentPage>
This new syntax does not instantiate the MyResourceDictionary class. Instead, it references the XAML file. For that
reason the code-behind file (MyResourceDictionary.xaml.cs) is no longer required. You can also remove the
x:Class attribute from the root tag of the MyResourceDictionary.xaml file.
Summary
This article explained how to create and consume a ResourceDictionary , and how to merge resource dictionaries.
A ResourceDictionary allows resources to be defined in a single location, and re-used throughout a
Xamarin.Forms application.
Related Links
Resource Dictionaries (sample)
Styles
ResourceDictionary
XAML Standard (Preview)
11/12/2018 • 2 minutes to read • Edit Online
Related Links
Preview NuGet
Controls Reference
XAML Standard (Preview) Controls
11/12/2018 • 2 minutes to read • Edit Online
This page lists the XAML Standard controls available in the Preview, alongside their equivalent Xamarin.Forms
control.
There is also a list of controls that have new property and enumeration names in XAML Standard.
Controls
XAMARIN.FORMS XAML STANDARD
Frame Border
Picker ComboBox
ActivityIndicator ProgressRing
StackLayout StackPanel
Label TextBlock
Entry TextBox
Switch ToggleSwitch
ContentView UserControl
Button, Entry, Label, Editor, SearchBar, FontAttributesBold, Italic, None FontStyleItalic, Normal
Span, Font
IMPORTANT
Items marked with * are incomplete in the current preview
Related Links
Preview NuGet
Loading XAML at Runtime in Xamarin.Forms
12/28/2018 • 2 minutes to read • Edit Online
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:
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:
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.
WARNING
Loading XAML at runtime has a significant performance cost, and generally should be avoided.
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;
...
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:
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 Application Fundamentals
1/30/2019 • 2 minutes to read • Edit Online
Accessibility
Tips to incorporate accessible features (like supporting screen-reading tools) with Xamarin.Forms.
App Class
The Application class is the starting point for Xamarin.Forms – every app needs to implement a subclass App to
set the initial page. It also provides the Properties collection for simple data storage. It can be defined in either C#
or XAML.
App Lifecycle
The Application class OnStart , OnSleep , and OnResume methods, as well as modal navigation events, let you
handle application lifecycle events with custom code.
Behaviors
User interface controls can be easily extended without subclassing by using behaviors to add functionality.
Custom Renderers
Custom Renders let developers 'override' the default rendering of Xamarin.Forms controls to customize their
appearance and behavior on each platform (using native SDKs if desired).
Data Binding
Data binding links the properties of two objects, allowing changes in one property to be automatically reflected in
the other property. Data binding is an integral part of the Model-View -ViewModel (MVVM ) application
architecture.
Dependency Service
The DependencyService provides a simple locator so that you can code to interfaces in your shared code and
provide platform-specific implementations that are automatically resolved, making it easy to reference platform-
specific functionality in Xamarin.Forms.
Effects
Effects allow the native controls on each platform to be customized, and are typically used for small styling
changes.
Files
File handling with Xamarin.Forms can be achieved using code in a .NET Standard library, or by using embedded
resources.
Gestures
The Xamarin.Forms GestureRecognizer class supports tap, pinch, and pan gestures on user interface controls.
Localization
The built-in .NET localization framework can be used to build cross-platform multilingual applications with
Xamarin.Forms.
Local Databases
Xamarin.Forms supports database-driven applications using the SQLite database engine, which makes it possible
to load and save objects in shared code.
Messaging Center
Xamarin.Forms MessagingCenter enables view models and other components to communicate with without having
to know anything about each other besides a simple Message contract.
Navigation
Xamarin.Forms provides a number of different page navigation experiences, depending upon the Page type being
used.
Shell
Xamarin.Forms Shell is a container for applications, that provides fundamental UI features that most applications
require, leaving you to focus on the application's core workload.
Templates
Control templates provide the ability to easily theme and re-theme application pages at runtime, while data
templates provide the ability to define the presentation of data on supported controls.
Triggers
Update controls by responding to property changes and events in XAML.
Xamarin.Forms Accessibility
10/23/2018 • 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. For more information, see Keyboard
Navigation.
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
Automation Properties in Xamarin.Forms
3/8/2019 • 5 minutes to read • Edit Online
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:
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" />
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:
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:
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 Icon 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 Icon property of the Master page to the appropriate string:
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 Navigation in Xamarin.Forms
1/10/2019 • 3 minutes to read • Edit Online
<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.
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.
Supported controls
The TabIndex and IsTapStop 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/24/2019 • 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>
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:
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.
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 ();
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);
<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.
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.
Xamarin.Forms App Lifecycle
10/31/2018 • 2 minutes to read • Edit Online
Lifecycle Methods
The Application class contains three virtual methods that can be overridden to handle lifecycle methods:
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 that 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.
When updating older Xamarin.Forms applications (eg. create with Xamarin.Forms 1.3 or older), ensure that the
Android main activity includes ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation in
the [Activity()] attribute. If this is not present you will observe the OnStart method gets called on rotation as
well as when the application first starts. This attribute is automatically included in the current Xamarin.Forms app
templates.
These events can be used in scenarios where you want to track pages as they are appearing 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.
NOTE
To implement the application lifecycle methods and modal navigation events, all pre- Application methods of creating a
Xamarin.Forms app (i.e. applications written in version 1.2 or older that use a static GetMainPage method) have been
updated to create a default Application which is set as the parent of MainPage .
Xamarin.Forms applications that use this legacy behavior must be updated to an Application subclass as described on the
Application class page.
Application Indexing and Deep Linking
5/1/2019 • 9 minutes to read • Edit Online
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.
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.
Application.Current.AppLinks.RegisterLink (appLink);
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:
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.
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.
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;
}
}
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.
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
7/12/2018 • 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
7/12/2018 • 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
12/7/2018 • 3 minutes to read • Edit Online
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.
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 .
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.
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
3/15/2019 • 5 minutes to read • Edit Online
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:
// 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.
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.
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.
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);
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:
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:
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
Reusable Behaviors
11/1/2018 • 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/4/2019 • 4 minutes to read • Edit Online
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.
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:
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.
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
12/7/2018 • 6 minutes to read • Edit Online
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.
NOTE
The EventToCommandBehavior is a custom class that can be located in the EventToCommand Behavior sample, and is not
part of Xamarin.Forms.
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:
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.
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:
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:
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
5/1/2019 • 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.
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.
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 HybridWebView
This article demonstrates how to create a custom renderer for a HybridWebView custom control, which
demonstrates how to enhance the platform-specific web controls to allow C# code to be invoked from
JavaScript.
Related Links
Effects
Introduction to Custom Renderers
10/9/2018 • 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.
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.
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:
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
5/1/2019 • 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
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
Layouts
The following table lists the renderer and native control classes that implement each Xamarin.Forms Layout type:
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
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
12/7/2018 • 6 minutes to read • Edit Online
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.
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.
<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:
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.
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;
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;
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:
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
12/7/2018 • 7 minutes to read • Edit Online
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.
Similarly, the code-behind file for the ContentPage should also remain unaltered, as shown in the following code
example:
The following code example shows how the page can be created in C#:
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.
This code simply navigates to the CameraPage , on which custom renderers will customize the page's appearance on
each platform.
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:
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)
{
}
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);
try
{
...
SetupUserInterface();
SetupBasedOnStateAsync();
this.Children.Add(page);
}
...
}
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
6/8/2018 • 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.
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 .
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:
This class defines a CustomPin as inheriting the properties of the Pin class, and adding a Url property.
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer">
<ContentPage.Content>
<local:CustomMap x:Name="myMap" MapType="Street"
WidthRequest="{x:Static local:App.ScreenWidth}"
HeightRequest="{x:Static local:App.ScreenHeight}" />
</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 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:
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. For iOS and
Android, the width and height of the map is set through properties of the App class that are initialized in the
platform-specific projects.
The location of the map, and the pins it contains, are initialized as shown in the following code example:
public MapPage ()
{
...
var 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",
Id = "Xamarin",
Url = "http://xamarin.com/about/"
};
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.
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:
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:
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:
if (annotation is MKUserLocation)
return null;
annotationView = mapView.DequeueReusableAnnotation(customPin.Id.ToString());
if (annotationView == null) {
annotationView = new CustomMKAnnotationView(annotation, customPin.Id.ToString());
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).Id = customPin.Id.ToString();
((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 Id 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.Id property is set to the CustomPin.Id 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:
if (customView.Id == "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 Id
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:
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;
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
Control.GetMapAsync(this);
}
}
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
...
}
}
Provided that the custom renderer is attached to a new Xamarin.Forms element, the OnElementChanged method
calls the MapView.GetMapAsync method, which gets the underlying GoogleMap that is tied to the view. 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:
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 .
if (customPin.Id.ToString() == "Xamarin") {
view = inflater.Inflate (Resource.Layout.XamarinMapInfoWindow, null);
} else {
view = inflater.Inflate (Resource.Layout.MapInfoWindow, null);
}
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.Id 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.
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.
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;
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.
if (customPin.Id.ToString() == "Xamarin")
{
if (mapOverlay == null)
{
mapOverlay = new XamarinMapOverlay(customPin);
}
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.
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.
Summary
This article demonstrated how to create a custom renderer for the Map control, enabling developers to override
the default native rendering with their own platform-specific customization. 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.
Related Links
Maps Control
iOS Maps
Maps API
Customized Pin (sample)
Highlighting a Circular Area on a Map
12/7/2018 • 6 minutes to read • Edit Online
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 :
<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:
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 .
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;
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;
...
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
circle = formsMap.Circle;
Control.GetMapAsync(this);
}
}
NativeMap.AddCircle(circleOptions);
}
}
}
The OnElementChanged method calls the MapView.GetMapAsync method, which gets the underlying GoogleMap that is
tied to the view, 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;
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MapControl;
var circle = formsMap.Circle;
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>();
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
Highlighting a Region on a Map
12/7/2018 • 6 minutes to read • Edit Online
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 polygon 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 subclass of the Map class, that adds a ShapeCoordinates property:
public class CustomMap : Map
{
public List<Position> ShapeCoordinates { get; set; }
public CustomMap ()
{
ShapeCoordinates = new List<Position> ();
}
}
The ShapeCoordinates property will store a collection of coordinates that define the region to be highlighted.
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:
This initialization specifies a series of latitude and longitude coordinates, to define the region of the map to be
highlighted. It then 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 polygon 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 polygon overlay:
if (e.OldElement != null) {
var nativeMap = Control as MKMapView;
if (nativeMap != null) {
nativeMap.RemoveOverlays(nativeMap.Overlays);
nativeMap.OverlayRenderer = null;
polygonRenderer = null;
}
}
if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
nativeMap.OverlayRenderer = GetOverlayRenderer;
int index = 0;
foreach (var position in formsMap.ShapeCoordinates)
{
coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
index++;
}
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 collection of latitude and longitude coordinates are retrieved from the CustomMap.ShapeCoordinates
property and stored as an array of CLLocationCoordinate2D instances.
The polygon is created by calling the static MKPolygon.FromCoordinates method, which specifies the latitude and
longitude of each point.
The polygon is added to the map by calling the MKMapView.AddOverlay method. This method automatically
closes the polygon by drawing a line that connects the first and last points.
Then, implement the GetOverlayRenderer method to customize the rendering of the overlay:
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
shapeCoordinates = formsMap.ShapeCoordinates;
Control.GetMapAsync(this);
}
}
The method retrieves the collection of latitude and longitude coordinates from the
OnElementChanged
CustomMap.ShapeCoordinates property and stores them in a member variable. It then calls the MapView.GetMapAsync
method, which gets the underlying GoogleMap that is tied to the view, 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 polygon is created by instantiating a PolygonOptions object that specifies the latitude and
longitude of each point. The polygon is then added to the map by calling the NativeMap.AddPolygon method. This
method automatically closes the polygon by drawing a line that connects the first and last points.
Creating the Custom Renderer on the Universal Windows Platform
Create a subclass of the MapRenderer class and override its OnElementChanged method to add the polygon overlay:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.UWP
{
public class CustomMapRenderer : MapRenderer
{
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;
This method performs the following operations, provided that the custom renderer is attached to a new
Xamarin.Forms element:
The collection of latitude and longitude coordinates are retrieved from the CustomMap.ShapeCoordinates
property and converted into a List of BasicGeoposition coordinates.
The polygon 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. Note that the
polygon will be automatically closed by drawing a line that connects the first and last points.
Summary
This article explained how to add a polygon overlay to a map, to highlight a region of the map. Polygons are a
closed shape and have their interiors filled in.
Related Links
Polygon Map Overlay (sample)
Customizing a Map Pin
Xamarin.Forms.Maps
Highlighting a Route on a Map
12/7/2018 • 5 minutes to read • Edit Online
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 polyline 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 subclass of the Map class, that adds a RouteCoordinates property:
public class CustomMap : Map
{
public List<Position> RouteCoordinates { get; set; }
public CustomMap ()
{
RouteCoordinates = new List<Position> ();
}
}
The RouteCoordinates property will store a collection of coordinates that define the route to be highlighted.
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:
This initialization specifies a series of latitude and longitude coordinates, to define the route on the map to be
highlighted. It then 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 polyline 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 polyline overlay:
if (e.OldElement != null) {
var nativeMap = Control as MKMapView;
if (nativeMap != null) {
nativeMap.RemoveOverlays(nativeMap.Overlays);
nativeMap.OverlayRenderer = null;
polylineRenderer = null;
}
}
if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
nativeMap.OverlayRenderer = GetOverlayRenderer;
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 collection of latitude and longitude coordinates are retrieved from the CustomMap.RouteCoordinates
property and stored as an array of CLLocationCoordinate2D instances.
The polyline is created by calling the static MKPolyline.FromCoordinates method, which specifies the latitude and
longitude of each point.
The polyline 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
{
MKPolylineRenderer polylineRenderer;
...
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
routeCoordinates = formsMap.RouteCoordinates;
Control.GetMapAsync(this);
}
}
NativeMap.AddPolyline(polylineOptions);
}
}
}
The method retrieves the collection of latitude and longitude coordinates from the
OnElementChanged
CustomMap.RouteCoordinates property and stores them in a member variable. It then calls the MapView.GetMapAsync
method, which gets the underlying GoogleMap that is tied to the view, 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 polyline is created by instantiating a PolylineOptions object that specifies the latitude and
longitude of each point. The polyline is then added to the map by calling the NativeMap.AddPolyline 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 polyline overlay:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.UWP
{
public class CustomMapRenderer : MapRenderer
{
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;
This method performs the following operations, provided that the custom renderer is attached to a new
Xamarin.Forms element:
The collection of latitude and longitude coordinates are retrieved from the CustomMap.RouteCoordinates
property and converted into a List of BasicGeoposition coordinates.
The polyline is created by instantiating a MapPolyline object. The MapPolygon class is used to display a line on
the map by setting its Path property to a Geopath object that contains the line coordinates.
The polyline is rendered on the map by adding it to the MapControl.MapElements collection.
Summary
This article explained how to add a polyline overlay to a map, to show a route on a map, or form any shape that's
required.
Related Links
Polyline Map Ovlerlay (sample)
Customizing a Map Pin
Xamarin.Forms.Maps
Customizing a ListView
12/7/2018 • 16 minutes to read • Edit Online
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.
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.
<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;
}
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.
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:
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;
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;
ContentView.Add (headingLabel);
ContentView.Add (subheadingLabel);
ContentView.Add (imageView);
}
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:
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;
}
}
...
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];
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:
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.
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;
}
}
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:
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
12/7/2018 • 14 minutes to read • Edit Online
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.
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.
<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;
}
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.
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:
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
{
...
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; }
SelectionStyle = UITableViewCellSelectionStyle.Gray;
ContentView.BackgroundColor = UIColor.FromRGB(255, 255, 224);
CellImageView = new UIImageView();
ContentView.Add(HeadingLabel);
ContentView.Add(SubheadingLabel);
ContentView.Add(CellImageView);
}
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.
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
{
...
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; }
AddView(view);
}
SetImage(cell.ImageFilename);
}
The following code example shows the layout definition for the NativeAndroidCell.axml layout file:
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)
Implementing a View
4/23/2019 • 9 minutes to read • Edit Online
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.
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.
<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.
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:
if (Control == null) {
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
}
if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null) {
// Configure the control and subscribe to event handlers
}
}
A new native control should only be instantiated once, when the Control property is null . The 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 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.
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:
if (Control == null) {
uiCameraPreview = new UICameraPreview (e.NewElement.Camera);
SetNativeControl (uiCameraPreview);
}
if (e.OldElement != null) {
// Unsubscribe
uiCameraPreview.Tapped -= OnCameraPreviewTapped;
}
if (e.NewElement != null) {
// Subscribe
uiCameraPreview.Tapped += OnCameraPreviewTapped;
}
}
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;
if (Control == null)
{
cameraPreview = new CameraPreview(Context);
SetNativeControl(cameraPreview);
}
if (e.OldElement != null)
{
// Unsubscribe
cameraPreview.Click -= OnCameraPreviewClicked;
}
if (e.NewElement != null)
{
Control.Preview = Camera.Open((int)e.NewElement.Camera);
// Subscribe
cameraPreview.Click += OnCameraPreviewClicked;
}
}
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:
if (Control == null)
{
...
_captureElement = new CaptureElement();
_captureElement.Stretch = Stretch.UniformToFill;
SetupCamera();
SetNativeControl(_captureElement);
}
if (e.OldElement != null)
{
// Unsubscribe
Tapped -= OnCameraPreviewTapped;
...
}
if (e.NewElement != null)
{
// Subscribe
Tapped += OnCameraPreviewTapped;
}
}
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 HybridWebView
3/27/2019 • 16 minutes to read • Edit Online
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 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 platform-
specific web controls 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 Invoking C# from JavaScript. For
more information about the HTML page, see Creating the Web Page.
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-specific project.
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
x:Class="CustomRenderer.HybridWebViewPage"
Padding="0,20,0,0">
<ContentPage.Content>
<local:HybridWebView x:Name="hybridWebView" Uri="index.html"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</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 HybridWebView custom control can be consumed by a C# page:
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-specific 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:
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-specific web controls by
allowing C# code to be invoked from JavaScript.
The following diagram illustrates the responsibilities of each project in the sample application, along with the
relationships between them:
The HybridWebView custom control is rendered by platform-specific renderer classes, which all derive from the
ViewRenderer class for each platform. This results in each HybridWebView custom control being rendered with
platform-specific web 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 web 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 HybridWebView instance.
An overridden version of the OnElementChanged method, in each platform-specific renderer class, is the place to
perform the native web control instantiation and customization. The SetNativeControl method should be used to
instantiate the native web 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:
if (Control == null) {
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
}
if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null) {
// Configure the control and subscribe to event handlers
}
}
A new native control should only be instantiated once, when the Control property is null . The 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 only be unsubscribed from
when the element the renderer is attached to changes. Adopting this approach will help to create a performant
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 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-specific custom renderer class.
Creating 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-1.11.0.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.
Invoking 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.
Creating the Custom Renderer on iOS
The following code example shows the custom renderer for the iOS platform:
if (Control == null) {
userController = new WKUserContentController ();
var script = new WKUserScript (new NSString (JavaScriptFunction),
WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript (script);
userController.AddScriptMessageHandler (this, "invokeAction");
The HybridWebViewRendererclass 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:
Provided that the Control property is null , the following operations are carried out:
A WKUserContentController instance is created, which allows posting messages and injecting user scripts
into a web page.
A WKUserScript instance is created to inject the invokeCSharpAction JavaScript function into the web
page after the web page is loaded.
The WKUserContentController.AddUserScript method adds the WKUserScript instance to the content
controller.
The WKUserContentController.AddScriptMessageHandler method adds a script message handler named
invokeAction to the WKUserContentController instance, which will cause the JavaScript function
window.webkit.messageHandlers.invokeAction.postMessage(data) to be defined in all frames in all web
views that will use the WKUserContentController instance.
A WKWebViewConfiguration instance is created, with the WKUserContentController instance being set as the
content controller.
A WKWebView control is instantiated, and the SetNativeControl method is called to assign a reference to
the WKWebView control to the Control property.
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.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
if (Control == null)
{
var webView = new Android.Webkit.WebView(_context);
webView.Settings.JavaScriptEnabled = true;
webView.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
SetNativeControl(webView);
}
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
Control.LoadUrl($"file:///android_asset/Content/{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:
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 Control property is null , the following operations are carried out:
A native WebView instance is created, JavaScript is enabled in the control, and a JavascriptWebViewClient
instance is set as the implementation of WebViewClient .
The SetNativeControl method is called to assign a reference to the native WebView control to the
Control property.
Provided that the custom renderer is attached to a new Xamarin.Forms element:
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:
[JavascriptInterface]
[Export ("invokeAction")]
public void InvokeAction (string data)
{
HybridWebViewRenderer hybridRenderer;
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 invoked the registered action to display the pop-up.
NOTE
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 on MSDN.
Creating 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 : ViewRenderer<HybridWebView, Windows.UI.Xaml.Controls.WebView>
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.external.notify(data);}";
if (Control == null)
{
SetNativeControl(new Windows.UI.Xaml.Controls.WebView());
}
if (e.OldElement != null)
{
Control.NavigationCompleted -= OnWebViewNavigationCompleted;
Control.ScriptNotify -= OnWebViewScriptNotify;
}
if (e.NewElement != null)
{
Control.NavigationCompleted += OnWebViewNavigationCompleted;
Control.ScriptNotify += OnWebViewScriptNotify;
Control.Source = new Uri(string.Format("ms-appx-web:///Content//{0}", 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 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.
Summary
This article has demonstrated how to create a custom renderer for a HybridWebView custom control, that
demonstrates how to enhance the platform-specific web controls to allow C# code to be invoked from JavaScript.
Related Links
CustomRendererHybridWebView (sample)
Call C# from JavaScript
Implementing a video player
12/7/2018 • 2 minutes to read • Edit Online
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:
Related Links
Video Player Demos (sample)
Creating the platform video players
4/2/2019 • 8 minutes to read • Edit Online
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
if (args.NewElement != null)
{
if (Control == null)
{
// Create AVPlayerViewController
_playerViewController = new AVPlayerViewController();
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);
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;
}
···
}
···
}
base.Dispose(disposing);
}
···
}
}
The two event handlers are detached in the Dispose event for the renderer.
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
if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}
void SetAreTransportControlsEnabled()
{
((AVPlayerViewController)ViewController).ShowsPlaybackControls =
Element.AreTransportControlsEnabled;
}
···
}
}
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;
}
}
}
···
}
}
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
4/2/2019 • 8 minutes to read • Edit Online
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);
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 };
}
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));
namespace FormsVideoLibrary
{
public class ResourceVideoSource : VideoSource
{
public static readonly BindableProperty PathProperty =
BindableProperty.Create(nameof(Path), typeof(string), typeof(ResourceVideoSource));
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));
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);
}
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 .
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
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);
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;
}
}
···
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();
···
}
}
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;
}
···
}
}
<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">
</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" />
<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:
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
12/7/2018 • 2 minutes to read • Edit Online
<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();
}
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; }
<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="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
12/7/2018 • 3 minutes to read • Edit Online
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.
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);
}
}
···
}
···
}
}
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;
}
}
}
···
}
}
<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
1/29/2019 • 6 minutes to read • Edit Online
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;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
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;
[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);
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");
<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" />
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();
}
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:
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;
}
}
···
}
···
}
}
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
4/2/2019 • 10 minutes to read • Edit Online
namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
public event EventHandler PlayRequested;
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();
}
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.
if (args.OldElement != null)
{
···
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
···
void OnPlayRequested(object sender, EventArgs args)
{
videoView.Start();
}
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();
}
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);
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; }
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;
});
}
···
}
}
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.
if (args.OldElement != null)
{
args.OldElement.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;
}
···
}
···
}
}
if (args.NewElement != null)
{
if (Control == null)
{
···
mediaElement.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}">
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
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
12/7/2018 • 10 minutes to read • Edit Online
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());
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; }
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void OnUpdateStatus(object sender, EventArgs args)
{
···
if (playerItem != null)
{
((IVideoPlayerController)Element).Duration = ConvertTime(playerItem.Duration);
···
}
}
}
···
}
}
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void OnVideoViewPrepared(object sender, EventArgs args)
{
···
((IVideoPlayerController)Element).Duration = TimeSpan.FromMilliseconds(videoView.Duration);
}
···
}
}
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
void OnMediaElementMediaOpened(object sender, RoutedEventArgs args)
{
((IVideoPlayerController)Element).Duration = Control.NaturalDuration.TimeSpan;
}
···
}
}
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());
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);
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);
}
}
}
···
}
}
namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
private static readonly BindablePropertyKey TimeToEndPropertyKey =
BindableProperty.CreateReadOnly(nameof(TimeToEnd), typeof(TimeSpan), typeof(VideoPlayer), new
TimeSpan());
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 PositionSlider()
{
PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "Value")
{
TimeSpan newPosition = TimeSpan.FromSeconds(Value);
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.
<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}">
···
<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
12/7/2018 • 2 minutes to read • Edit Online
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 Fallbacks
Make data bindings more robust by defining fallback values to use if the binding process fails.
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
1/23/2019 • 9 minutes to read • Edit Online
<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.
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}" />
<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:
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 and
Universal Windows Platform (UWP ) screenshots demonstrate, 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:
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:
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.
<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 of The Xamarin Show on Channel 9 and YouTube.
Xamarin.Forms Binding Mode
5/1/2019 • 15 minutes to read • Edit Online
<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 and UWP screenshots
demonstrate. 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.
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.
Name = NamedColor.GetNearestColorName(color);
}
}
get
{
return color;
}
}
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>
<StackLayout Grid.Row="1"
Margin="10, 0">
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 and
UWP screenshots.
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.
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:
storage = value;
OnPropertyChanged(propertyName);
return true;
}
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:
// Static members
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();
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();
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 Orientation="Horizontal">
<Label Text="Name: "
VerticalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="Birth Date: "
VerticalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="Do you code in C#? "
VerticalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="Number of Copies: "
VerticalOptions="Center" />
<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" />
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 :
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
12/7/2018 • 4 minutes to read • Edit Online
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 />
<BoxView />
<BoxView />
<BoxView />
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 " 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:
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 :
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:
<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>
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
12/7/2018 • 3 minutes to read • Edit Online
<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:
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>
<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>
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.
<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 :
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:
That displays the type of the binding source, or DataBindingDemos.PathVariationsPage . You know
PathVariationsPage derives from ContentPage , so it has a Content property:
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
12/7/2018 • 10 minutes to read • Edit Online
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>
<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.
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 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.
Name = NamedColor.GetNearestColorName(color);
}
}
get
{
return color;
}
}
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 object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value / GetParameter(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:
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>
<StackLayout>
<StackLayout.BindingContext>
<local:RgbColorViewModel Color="Gray" />
</StackLayout.BindingContext>
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.
NOTE
Use of the FallbackValue and TargetNullValue properties in a binding expression is optional.
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:
NOTE
It's not possible to set the FallbackValue property with a binding expression.
IMPORTANT
A defined value converter is not executed in a binding expression when the FallbackValue property is set.
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.
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
12/7/2018 • 17 minutes to read • Edit Online
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 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:
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.
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;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
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;
···
storage = value;
OnPropertyChanged(propertyName);
return true;
}
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>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</Grid>
<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>
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 and UWP screens show 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 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 .
···
public PersonCollectionViewModel()
{
···
···
}
···
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()
{
···
···
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.
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>
<Button Text="CLEAR"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Command="{Binding ClearCommand}" />
<Button Text="⇦"
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="·"
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";
···
The button corresponding to the ClearCommand is always enabled and simply sets the entry back to "0":
···
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 DecimalKeypadViewModel()
{
···
···
···
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()
{
···
···
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.
···
</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:
BindingContext = this;
}
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
12/7/2018 • 6 minutes to read • Edit Online
NOTE
It's recommended to set the x:DataType attribute at the same level in the view hierarchy as the BindingContext is set.
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.
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.
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.
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.
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 .
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
12/7/2018 • 2 minutes to read • Edit Online
Related Links
Using DependencyService (sample)
DependencyService (sample)
Xamarin.Forms Samples
Introduction to DependencyService
12/7/2018 • 3 minutes to read • Edit Online
Overview
DependencyService allows apps to call into platform-specific functionality from shared code. This functionality
enables Xamarin.Forms apps to do anything that a native app can do.
DependencyService is a service locator. In practice, an interface is defined and DependencyService finds the correct
implementation of that interface from the various platform projects.
NOTE
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.
namespace UsingDependencyService.iOS
{
public class TextToSpeech_iOS : ITextToSpeech
{
public void Speak (string text)
{
var speechSynthesizer = new AVSpeechSynthesizer ();
speechSynthesizer.SpeakUtterance (speechUtterance);
}
}
}
Registration
Each implementation of the interface needs to be registered with DependencyService with a metadata attribute. The
following code registers the implementation for iOS:
[assembly: Dependency (typeof (TextToSpeech_iOS))]
namespace UsingDependencyService.iOS
{
...
}
speechSynthesizer.SpeakUtterance (speechUtterance);
}
}
}
Note: that the registration is performed at the namespace level, not the class level.
Universal Windows Platform .NET Native Compilation
UWP projects that use the .NET Native compilation option should follow a slightly different configuration when
initializing Xamarin.Forms. .NET Native compilation also requires slightly different registration for dependency
services.
In the App.xaml.cs file, manually register each dependency service defined in the UWP project using the
Register<T> method, as shown below:
Xamarin.Forms.Forms.Init(e, assembliesToInclude);
// register the dependencies in the same
Xamarin.Forms.DependencyService.Register<TextToSpeechImplementation>();
Note: manual registration using Register<T> is only effective in Release builds using .NET Native compilation. If
you omit this line, Debug builds will still work, but Release builds will fail to load the dependency service.
Call to DependencyService
Once the project has been set up with a common interface and implementations for each platform, use
DependencyService to get the right implementation at runtime:
Related Links
DependencyServiceSample
Xamarin.Forms Samples
Implementing Text-to-Speech
1/23/2019 • 3 minutes to read • Edit Online
Coding against this interface in the shared code will allow the Xamarin.Forms app to access the speech APIs on
each platform.
NOTE
Classes implementing the interface must have a parameterless constructor to work with the DependencyService .
iOS Implementation
The interface must be implemented in each platform-specific application project. Note that the class has a
parameterless constructor so that the DependencyService can create new instances.
[assembly: Dependency(typeof(TextToSpeechImplementation))]
namespace DependencyServiceSample.iOS
{
speechSynthesizer.SpeakUtterance(speechUtterance);
}
}
}
The [assembly] attribute registers the class as an implementation of the ITextToSpeech interface, which means
that DependencyService.Get<ITextToSpeech>() can be used in the shared code to create an instance of it.
Android Implementation
The Android code is more complex than the iOS version. It requires access to the current Android context, which is
exposed by the MainActivity.Instance property:
It also requires the implementing class to inherit from Android-specific Java.Lang.Object and to implement the
IOnInitListener interface as well.
[assembly: Dependency(typeof(TextToSpeechImplementation))]
namespace DependencyServiceSample.Droid
{
public class TextToSpeechImplementation : Java.Lang.Object, ITextToSpeech, TextToSpeech.IOnInitListener
{
TextToSpeech speaker;
string toSpeak;
The [assembly] attribute registers the class as an implementation of the ITextToSpeech interface, which means
that DependencyService.Get<ITextToSpeech>() can be used in the shared code to create an instance of it.
[assembly:Dependency(typeof(TextToSpeechImplementation))]
public class TextToSpeechImplementation : ITextToSpeech
{
public async void Speak(string text)
{
var mediaElement = new MediaElement();
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
var stream = await synth.SynthesizeTextToStreamAsync(text);
mediaElement.SetSource(stream, stream.ContentType);
mediaElement.Play();
}
}
The [assembly] attribute registers the class as an implementation of the ITextToSpeech interface, which means
that DependencyService.Get<ITextToSpeech>() can be used in the shared code to create an instance of it.
public MainPage ()
{
var speak = new Button {
Text = "Hello, Forms !",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
speak.Clicked += (sender, e) => {
DependencyService.Get<ITextToSpeech>().Speak("Hello from Xamarin Forms");
};
Content = speak;
}
Running this application on iOS, Android, or the UWP and pressing the button will result in the application
speaking to you, using the native speech SDK on each platform.
Related Links
Using DependencyService (sample)
DependencyServiceSample
Checking Device Orientation
12/7/2018 • 3 minutes to read • Edit Online
NOTE
It is possible to detect whether the device is in portrait or landscape orientation in shared code, as demonstrated in Device
Orientation. The method described in this article uses native features to get more information about orientation, including
whether the device is upside down.
Coding against this interface in the shared code will allow the Xamarin.Forms app to access the device orientation
APIs on each platform.
NOTE
Classes implementing the interface must have a parameterless constructor to work with the DependencyService .
iOS Implementation
The Interface must be implemented in each platform-specific application project. Note that the class has a
parameterless constructor so that the DependencyService can create new instances:
using UIKit;
using Foundation;
namespace DependencyServiceSample.iOS
{
public class DeviceOrientationImplementation : IDeviceOrientation
{
public DeviceOrientationImplementation(){ }
Finally, add this [assembly] attribute above the class (and outside any namespaces that have been defined),
including any required using statements:
using UIKit;
using Foundation;
using DependencyServiceSample.iOS; //enables registration outside of namespace
This attribute registers the class as an implementation of the IDeviceOrientation Interface, which means that
DependencyService.Get<IDeviceOrientation> can be used in the shared code to create an instance of it.
Android Implementation
The following code implements IDeviceOrientation on Android:
using DependencyServiceSample.Droid;
using Android.Hardware;
namespace DependencyServiceSample.Droid
{
public class DeviceOrientationImplementation : IDeviceOrientation
{
public DeviceOrientationImplementation() { }
Add this [assembly] attribute above the class (and outside any namespaces that have been defined), including any
required using statements:
This attribute registers the class as an implementation of the IDeviceOrientaiton Interface, which means that
DependencyService.Get<IDeviceOrientation> can be used in the shared code can create an instance of it.
Add the [assembly] attribute above the class (and outside any namespaces that have been defined), including any
required using statements:
[assembly: Dependency(typeof(DeviceOrientationImplementation))]
namespace DependencyServiceSample.WindowsPhone {
...
This attribute registers the class as an implementation of the DeviceOrientationImplementation Interface, which
means that DependencyService.Get<IDeviceOrientation> can be used in the shared code can create an instance of it.
Running this application on iOS, Android, or the Windows platforms and pressing the button will result in the
button's text updating with the device's orientation.
Related Links
Using DependencyService (sample)
DependencyService (sample)
Xamarin.Forms Samples
Checking Battery Status
1/29/2019 • 6 minutes to read • Edit Online
Coding against this interface in the shared code will allow the Xamarin.Forms app to access the power
management APIs on each platform.
NOTE
Classes implementing the Interface must have a parameterless constructor to work with the DependencyService .
Constructors can't be defined by interfaces.
iOS Implementation
The IBattery interface must be implemented in each platform-specific application project. The iOS
implementation will use the native UIDevice APIs to access battery information. Note that the following class has
a parameterless constructor so that the DependencyService can create new instances:
using UIKit;
using Foundation;
using DependencyServiceSample.iOS;
namespace DependencyServiceSample.iOS
{
public class BatteryImplementation : IBattery
{
public BatteryImplementation()
{
UIDevice.CurrentDevice.BatteryMonitoringEnabled = true;
}
Finally, add this [assembly] attribute above the class (and outside any namespaces that have been defined),
including any required using statements:
using UIKit;
using Foundation;
using DependencyServiceSample.iOS;//necessary for registration outside of namespace
This attribute registers the class as an implementation of the IBattery interface, which means that
DependencyService.Get<IBattery> can be used in shared code to create an instance of it:
Android Implementation
The Android implementation uses the Android.OS.BatteryManager API. This implementation is more complex than
the iOS version, requiring checks to handle lack of battery permissions:
using System;
using Android;
using Android.Content;
using Android.App;
using Android.OS;
using BatteryStatus = Android.OS.BatteryStatus;
using DependencyServiceSample.Droid;
namespace DependencyServiceSample.Droid
{
public class BatteryImplementation : IBattery
{
private BatteryBroadcastReceiver batteryReceiver;
public BatteryImplementation() { }
}
}
switch(status)
{
case (int)BatteryStatus.Charging:
return DependencyServiceSample.BatteryStatus.Charging;
case (int)BatteryStatus.Discharging:
return DependencyServiceSample.BatteryStatus.Discharging;
case (int)BatteryStatus.Full:
return DependencyServiceSample.BatteryStatus.Full;
case (int)BatteryStatus.NotCharging:
return DependencyServiceSample.BatteryStatus.NotCharging;
default:
return DependencyServiceSample.BatteryStatus.Unknown;
}
}
}
}
catch
{
System.Diagnostics.Debug.WriteLine ("Ensure you have android.permission.BATTERY_STATS");
throw;
}
}
}
if (!isCharging)
return DependencyServiceSample.PowerSource.Battery;
else if (usbCharge)
return DependencyServiceSample.PowerSource.Usb;
else if (acCharge)
return DependencyServiceSample.PowerSource.Ac;
else if (wirelessCharge)
return DependencyServiceSample.PowerSource.Wireless;
else
return DependencyServiceSample.PowerSource.Other;
}
}
}
catch
{
System.Diagnostics.Debug.WriteLine ("Ensure you have android.permission.BATTERY_STATS");
throw;
}
}
}
}
}
Add this [assembly] attribute above the class (and outside any namespaces that have been defined), including any
required using statements:
...
using BatteryStatus = Android.OS.BatteryStatus;
using DependencyServiceSample.Droid; //enables registration outside of namespace
This attribute registers the class as an implementation of the IBattery interface, which means that
DependencyService.Get<IBattery> can be used in the shared code can create an instance of it.
using DependencyServiceSample.UWP;
using Xamarin.Forms;
[assembly: Dependency(typeof(BatteryImplementation))]
namespace DependencyServiceSample.UWP
{
public class BatteryImplementation : IBattery
{
private BatteryStatus status = BatteryStatus.Unknown;
Windows.Devices.Power.Battery battery;
public BatteryImplementation()
{
}
if (finalReport.RemainingCapacityInMilliwattHours.HasValue &&
finalReport.FullChargeCapacityInMilliwattHours.HasValue)
{
finalPercent = (int)((finalReport.RemainingCapacityInMilliwattHours.Value /
(double)finalReport.FullChargeCapacityInMilliwattHours.Value) * 100);
}
return finalPercent;
}
}
The [assembly] attribute above the namespace declaration registers the class as an implementation of the
IBattery interface, which means that DependencyService.Get<IBattery> can be used in shared code to create an
instance of it.
public MainPage ()
{
var button = new Button {
Text = "Click for battery info",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
button.Clicked += (sender, e) => {
var bat = DependencyService.Get<IBattery>();
switch (bat.PowerSource){
case PowerSource.Battery:
button.Text = "Battery - ";
break;
case PowerSource.Ac:
button.Text = "AC - ";
break;
case PowerSource.Usb:
button.Text = "USB - ";
break;
case PowerSource.Wireless:
button.Text = "Wireless - ";
break;
case PowerSource.Other:
default:
button.Text = "Other - ";
break;
}
switch (bat.Status){
case BatteryStatus.Charging:
button.Text += "Charging";
break;
case BatteryStatus.Discharging:
button.Text += "Discharging";
break;
case BatteryStatus.NotCharging:
button.Text += "Not Charging";
break;
case BatteryStatus.Full:
button.Text += "Full";
break;
case BatteryStatus.Unknown:
default:
button.Text += "Unknown";
break;
}
};
Content = button;
}
Running this application on iOS, Android, or UWP and pressing the button will result in the button text updating
to reflect the current power status of the device.
Related Links
DependencyService (sample)
Using DependencyService (sample)
Xamarin.Forms Samples
Picking a Photo from the Picture Library
1/29/2019 • 6 minutes to read • Edit Online
Creating the Interface – understand how the interface is created in shared code.
iOS Implementation – learn how to implement the interface in native code for iOS.
Android Implementation – learn how to implement the interface in native code for Android.
Universal Windows Platform Implementation – learn how to implement the interface in native code for
the Universal Windows Platform (UWP ).
Implementing in Shared Code – learn how to use DependencyService to call into the native implementation
from shared code.
namespace DependencyServiceSample
{
public interface IPicturePicker
{
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 IPicturePicker 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 PicturePickerImplementation 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 IPicturePicker interface:
[assembly: Dependency (typeof (PicturePickerImplementation))]
namespace DependencyServiceSample.iOS
{
public class PicturePickerImplementation : IPicturePicker
{
TaskCompletionSource<Stream> taskCompletionSource;
UIImagePickerController imagePicker;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
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 a JPEG file in memory 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 DependencyServiceSample.iOS
{
public class PicturePickerImplementation : IPicturePicker
{
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 = image.AsJPEG(1);
Stream stream = data.AsStream();
UnregisterEventHandlers();
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
{
...
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;
if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Android.Net.Uri uri = intent.Data;
Stream stream = ContentResolver.OpenInputStream(uri);
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 PicturePickerImplementation class in the Android project. This is
the class with the GetImageStreamAsync method:
[assembly: Dependency(typeof(PicturePickerImplementation))]
namespace DependencyServiceSample.Droid
{
public class PicturePickerImplementation : IPicturePicker
{
public Task<Stream> GetImageStreamAsync()
{
// Define the Intent for getting images
Intent intent = new Intent();
intent.SetType("image/*");
intent.SetAction(Intent.ActionGetContent);
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 PicturePickerImplementation 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(PicturePickerImplementation))]
namespace DependencyServiceSample.UWP
{
public class PicturePickerImplementation : IPicturePicker
{
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");
if (storageFile == null)
{
return null;
}
The Clicked handler uses the DependencyService class to call GetImageStreamAsync . This results in a call in the
platform project. If the method returns a Stream object, then the handler creates an Image element for that
picture with a TapGestureRecognizer , and replaces the StackLayout on the page with that Image :
pickPictureButton.Clicked += async (sender, e) =>
{
pickPictureButton.IsEnabled = false;
Stream stream = await DependencyService.Get<IPicturePicker>().GetImageStreamAsync();
if (stream != null)
{
Image image = new Image
{
Source = ImageSource.FromStream(() => stream),
BackgroundColor = Color.Gray
};
Related Links
Choose a Photo from the Gallery (iOS )
Select an Image (Android)
DependencyService (sample)
Xamarin.Forms Effects
7/12/2018 • 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.
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.
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 platfom-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
4/1/2019 • 6 minutes to read • Edit Online
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(FocusEffect), nameof(FocusEffect))]
namespace EffectsDemo.iOS
{
public class FocusEffect : PlatformEffect
{
UIColor backgroundColor;
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 Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect(typeof(FocusEffect), nameof(FocusEffect))]
namespace EffectsDemo.Droid
{
public class FocusEffect : PlatformEffect
{
Android.Graphics.Color backgroundColor;
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.
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(FocusEffect), nameof(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);
}
}
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.
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.
The FocusEffect class in the .NET Standard library supports effect consumption in XAML, and is shown in the
following code example:
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.
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
4/12/2018 • 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.
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:
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.
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.
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);
}
}
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
12/7/2018 • 10 minutes to read • Edit Online
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:
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.
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:
[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);
}
}
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;
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;
UpdateColor ();
UpdateOffset ();
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
12/14/2018 • 21 minutes to read • Edit Online
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.
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:
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;
}
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.
[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;
The OnPointerPressed handler invokes the effect event by calling the onTouchAction field in the CommonHandler
method:
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:
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;
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;
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:
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.
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())
};
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;
}
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:
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));
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);
}
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()
{
}
void MakeRectangle()
{
Rectangle = new SKRect(pt1.X, pt1.Y, pt2.X, pt2.Y).Standardized;
}
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:
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();
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;
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);
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();
}
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:
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();
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)
File Handling in Xamarin.Forms
12/7/2018 • 4 minutes to read • Edit Online
Overview
Xamarin.Forms code runs on multiple platforms - each of which has its own filesystem. Previously, this meant that
reading and writing files was most easily performed using the native file APIs on each platform. Alternatively,
embedded resources are a simpler solution to distribute data files with an app. However, with .NET Standard 2.0
it's possible to share file access code in .NET Standard libraries.
For information on handling image files, refer to the Working with Images page.
File.WriteAllText(fileName, text);
In addition, the File.Exists method determines whether the specified file exists:
The path of the file on each platform can be determined from a .NET Standard library by using a value of the
Environment.SpecialFolder enumeration as the first argument to the Environment.GetFolderPath method. This can
then be combined with a filename with the Path.Combine method:
These operations are demonstrated in the sample app, which includes a page that saves and loads text:
Loading Files Embedded as Resources
To embed a file into a .NET Standard assembly, create or add a file and ensure that Build Action:
EmbeddedResource.
Visual Studio
Visual Studio for Mac
GetManifestResourceStream is used to access the embedded file using its Resource ID. By default the resource ID
is the filename prefixed with the default namespace for the project it is embedded in - in this case the assembly is
WorkingWithFiles and the filename is PCLTextResource.txt, so the resource ID is
WorkingWithFiles.PCLTextResource.txt .
The text variable can then be used to display the text or otherwise use it in code. This screenshot of the sample
app shows the text rendered in a Label control.
Loading and deserializing an XML is equally simple. The following code shows an XML file being loaded and
deserialized from a resource, then bound to a ListView for display. The XML file contains an array of Monkey
objects (the class is defined in the sample code).
#if __IOS__
var resourcePrefix = "WorkingWithFiles.iOS.";
#endif
#if __ANDROID__
var resourcePrefix = "WorkingWithFiles.Droid.";
#endif
Organizing Resources
The above examples assume that the file is embedded in the root of the .NET Standard library project, in which
case the resource ID is of the form Namespace.Filename.Extension, such as
WorkingWithFiles.PCLTextResource.txt and WorkingWithFiles.iOS.SharedTextResource.txt .
It is possible to organize embedded resources in folders. When an embedded resource is placed in a folder, the
folder name becomes part of the resource ID (separated by periods), so that the resource ID format becomes
Namespace.Folder.Filename.Extension. Placing the files used in the sample app into a folder MyFolder would
make the corresponding resource IDs WorkingWithFiles.MyFolder.PCLTextResource.txt and
WorkingWithFiles.iOS.MyFolder.SharedTextResource.txt .
using System.Reflection;
// ...
// use for debugging, not in released app code!
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(SharedPage)).Assembly;
foreach (var res in assembly.GetManifestResourceNames()) {
System.Diagnostics.Debug.WriteLine("found resource: " + res);
}
Summary
This article has shown some simple file operations for saving and loading text on the device, and for loading
embedded resources. With .NET Standard 2.0 it's possible to share file access code in .NET Standard libraries.
Related Links
FilesSample
Xamarin.Forms Samples
Working with the File System in Xamarin.iOS
Xamarin.Forms gestures
9/20/2018 • 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.
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:
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:
Related Links
TapGesture (sample)
GestureRecognizer
TapGestureRecognizer
Adding a pinch gesture recognizer
12/7/2018 • 3 minutes to read • Edit Online
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:
public PinchToZoomContainer ()
{
var pinchGesture = new PinchGestureRecognizer ();
pinchGesture.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add (pinchGesture);
}
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:
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);
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
12/7/2018 • 3 minutes to read • Edit Online
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:
NOTE
Correct panning on Android requires the Xamarin.Forms 2.1.0-pre1 NuGet package at a minimum.
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);
}
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:
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
12/7/2018 • 5 minutes to read • Edit Online
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.
Similarly, swipes that occur on the vertical axis can be recognized by setting the Direction property to Up and
Down :
Alternatively, a SwipeGestureRecognizer for each swipe direction can be created to recognize swipes in every
direction:
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.
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 :
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.
public SwipeContainer()
{
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Left));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Right));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Up));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Down));
}
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:
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
Xamarin.Forms Localization
11/8/2018 • 2 minutes to read • Edit Online
The built-in .NET localization framework can be used to build cross-platform multilingual applications with
Xamarin.Forms.
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.
Localization
3/8/2019 • 24 minutes to read • Edit Online
Overview
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.
Sample Code
There are two samples associated with this document:
UsingResxLocalization is a very simple demonstration of the concepts explained. The code snippets shown
below are all from this sample.
TodoLocalized is a basic working app that uses these localization techniques.
Shared Projects are not recommended
The TodoLocalized sample includes a Shared Project demo however due to limitations of the build system the
resource files do not get a .designer.cs file generated which breaks the ability to access translated strings strongly-
typed in code.
The remainder of this document relates to projects using the Xamarin.Forms .NET Standard library template.
NOTE
On the Universal Windows Platform, RESW files should be used for push notification localization, rather than RESX files. For
more information, see UWP Localization.
Adding Resources
The first step in globalizing a Xamarin.Forms .NET Standard library application is adding the RESX resource files
that will be used to store all the text used in the app. We need to add a RESX file that contains the default text, and
then add additional RESX files for each language we wish to support.
Base Language Resource
The base resources (RESX) file will contain the default language strings (the samples assume English is the default
language). Add the file to the Xamarin.Forms common code project by right-clicking on the project and choosing
Add > New File....
Choose a meaningful name such as AppResources and press OK.
St r i n g Vi si b i l i t y
By default when strongly-typed references to strings are generated, they will be internal to the assembly. This is
because the default build tool for RESX files generates the .designer.cs file with internal properties.
Select the AppResources.resx file and show the Properties pad to see where this build tool is configure. The
screenshot below shows the Custom Tool: ResXFileCodeGenerator.
Visual Studio
Visual Studio for Mac
To make the strongly-typed string properties public , you must manually change the configuration to Custom
Tool: PublicResXFileCodeGenerator, as shown in the screenshot below:
Visual Studio
Visual Studio for Mac
This change is optional, and is only required if you wish to reference localized strings across different assemblies
(for example, if you put the RESX files in a different assembly to your code). The sample for this topic leaves the
strings internal because they are defined in the same Xamarin.Forms .NET Standard library assembly where they
are used.
You only need to set the custom tool on the base RESX file as shown above; you do not need to set any build tool
on the language-specific RESX files discussed in the following sections.
Ed i t i n g t h e R E SX fi l e
Unfortunately there is no built-in RESX editor in Visual Studio for Mac. Adding new translatable strings requires
the addition of a new XML data element for each string. Each data element can contain the following:
name attribute (required) is the key for this translatable string. It must be a valid C# property name - so no
spaces or special characters are allowed.
value element (required), which is the actual string that is displayed in the application.
comment element (optional) can contain instructions for the translator that explains how this string is used.
xml:space attribute (optional) to control how spacing in the string is preserved.
As the application is written, every piece of text displayed to the user should be added to the base RESX resources
file in a new data element. It is recommended that you include comment s as much as possible to ensure a high-
quality translation.
NOTE
Visual Studio (including the free Community edition) contains a basic RESX editor. If you have access to a Windows computer,
that can be a convenient way to add and edit strings in RESX files.
Language-Specific Resources
Typically, the actual translation of the default text strings won't happen until large chunks of the application have
been written (in which case the default RESX file will contain lots of strings). It is still a good idea to add the
language-specific resources early in the development cycle, optionally populating with machine-translated text to
help test the localization code.
One additional RESX file is added for each language we wish to support. Language-specific resource files must
follow a specific naming convention: use the same filename as the base resources file (eg. AppResources)
followed by a period (.) and then the language code. Simple examples include:
AppResources.fr.resx - French language translations.
AppResources.es.resx - Spanish language translations.
AppResources.de.resx - German language translations.
AppResources.ja.resx - Japanese language translations.
AppResources.zh-Hans.resx - Chinese (Simplified) language translations.
AppResources.zh-Hant.resx - Chinese (Traditional) language translations.
AppResources.pt.resx - Portuguese language translations.
AppResources.pt-BR.resx - Brazilian Portuguese language translations.
The general pattern is to use two-letter language codes, but there are some examples (such as Chinese) where a
different format is used, and other examples (such as Brazilian Portuguese) where a four character locale identifier
is required.
These language-specific resources files do not require a .designer.cs partial class so they can be added as regular
XML files, with the Build Action: EmbeddedResource set. This screenshot shows a solution containing
language-specific resource files:
As an application is developed and the base RESX file has text added, you should send it out to translators who will
translate each data element and return a language-specific resource file (using the naming convention shown) to
be included in the app. Some 'machine translated' examples are shown below:
AppResources.es.resx (Spanish)
AppResources.ja.resx (Japanese)
Only the value element needs to be updated by the translator - the comment is not intended to be translated.
Remember: when editing XML files to escape reserved characters like < , > , & with < , > , and & if
they appear in the value or comment .
Using Resources in Code
Strings in the RESX resource files will be available to use in your user interface code using the AppResources class.
The name assigned to each string in the RESX file becomes a property on that class which can be referenced in
Xamarin.Forms code as shown below:
The user interface on iOS, Android, and the Universal Windows Platform (UWP ) renders as you'd expect, except
now it's possible to translate the app into multiple languages because the text is being loaded from a resource
rather than being hard-coded. Here is a screenshot showing the UI on each platform prior to translation:
Troubleshooting
Testing a Specific Language
It can be tricky to switch the simulator or a device to different languages, particularly during development when
you want to test different cultures quickly.
You can force a specific language to be loaded by setting the Culture as shown in this code snippet:
This approach – setting the culture directly on the AppResources class – can also be used to implement a language-
selector inside your app (rather than using the device's locale).
Loading Embedded Resources
The following code snippet is useful when trying to debug issues with embedded resources (such as RESX files).
Add this code to your app (early in the app lifecycle) and it will list all the resources embedded in the assembly,
showing the full resource identifier:
using System.Reflection;
// ...
// NOTE: use for debugging, not in released app code!
var assembly = typeof(EmbeddedImages).GetTypeInfo().Assembly; // "EmbeddedImages" should be a class in your
app
foreach (var res in assembly.GetManifestResourceNames())
{
System.Diagnostics.Debug.WriteLine("found resource: " + res);
}
In the AppResources.Designer.cs file (around line 33), the full resource manager name is specified (eg.
"UsingResxLocalization.Resx.AppResources" ) similar to the code below:
System.Resources.ResourceManager temp =
new System.Resources.ResourceManager(
"UsingResxLocalization.Resx.AppResources",
typeof(AppResources).GetTypeInfo().Assembly);
Check the Application Output for the results of the debug code shown above, to confirm the correct resources
are listed (ie. "UsingResxLocalization.Resx.AppResources" ).
If not, the AppResources class will be unable to load its resources. Check the following to resolve issues where the
resources cannot be found:
The default namespace for the project matches the root namespace in the AppResources.Designer.cs file.
If the AppResources.resx file is located in a subdirectory, the subdirectory name should be part of the
namespace and part of the resource identifier.
The AppResources.resx file has Build Action: EmbeddedResource.
The Project Options > Source Code > .NET Naming Policies > Use Visual Studio-style resources
names is ticked. You can untick this if you prefer, however the namespaces used when referencing your RESX
resources will need to updated throughout the app.
Doesn't work in DEBUG mode (Android only )
If the translated strings are working in your RELEASE Android builds but not while debugging, right-click on the
Android Project and select Options > Build > Android Build and ensure that the Fast assembly deployment
is NOT ticked. This option causes problems with loading resources and should not be used if you are testing
localized apps.
Displaying the Correct Language
So far we've examined how to write code so that translations can be provided, but not how to actually make them
appear. Xamarin.Forms code can take advantage of .NET's resources to load the correct language translations, but
we need to query the operating system on each platform to determine which language the user has selected.
Because some platform-specific code is required to obtain the user's language preference, use a dependency
service to expose that information in the Xamarin.Forms app and implement it for each platform.
First, define an interface to expose the user's preferred culture, similar to the code below:
Second, use the DependencyService in the Xamarin.Forms App class to call the interface and set our RESX
resources culture to the correct value. Notice that we don't need to manually set this value for the Universal
Windows Platform, since the resources framework automatically recognizes the selected language on those
platforms.
The resource Culture needs to be set when the application first loads so that the correct language strings are
used. You may optionally update this value according to platform-specific events that may be raised on iOS or
Android if the user updates their language preferences while the app is running.
The implementations for the ILocalize interface are shown in the Platform-specific Code section below. These
implementations take advantage of this PlatformCulture helper class:
Platform-Specific Code
The code to detect which language to display must be platform-specific because iOS, Android, and UWP all expose
this information in slightly different ways. The code for the ILocalize dependency service is provided below for
each platform, along with additional platform-specific requirements to ensure localized text is rendered correctly.
The platform-specific code must also handle cases where the operating system allows the user to configure a
locale identifier that is not supported by .NET's CultureInfo class. In these cases custom code must be written to
detect unsupported locales and substitute the best .NET-compatible locale.
iOS Application Project
iOS users select their preferred language separately from date and time formatting culture. To load the correct
resources to localize a Xamarin.Forms app we just need to query the NSLocale.PreferredLanguages array for the
first element.
The following implementation of the ILocalize dependency service should be placed in the iOS application
project. Because iOS uses underscores instead of dashes (which is the .NET standard representation) the code
replaces the underscore before instantiating the CultureInfo class:
[assembly:Dependency(typeof(UsingResxLocalization.iOS.Localize))]
namespace UsingResxLocalization.iOS
{
public class Localize : UsingResxLocalization.ILocalize
{
public void SetLocale (CultureInfo ci)
{
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
}
NOTE
The try/catch blocks in the GetCurrentCultureInfo method mimic the fallback behavior typically used with locale
specifiers – if the exact match is not found, look for a close match based just on the language (first block of characters in the
locale).
In the case of Xamarin.Forms, some locales are valid in iOS but do not correspond to a valid CultureInfo in .NET, and the
code above attempts to handle this.
For example, the iOS Settings > General Language & Region screen allows you to set your phone Language to English
but the Region to Spain, which results in a locale string of "en-ES" . When the CultureInfo creation fails, the code falls
back to using just the first two letters to select the display language.
Developers should modify the iOSToDotnetLanguage and ToDotnetFallbackLanguage methods to handle specific cases
required for their supported languages.
There are some system-defined user-interface elements that are automatically translated by iOS, such as the Done
button on the Picker control. To force iOS to translate these elements we need to indicate which languages we
support in the Info.plist file. You can add these values via Info.plist > Source as shown here:
Alternatively, open the Info.plist file in an XML editor and edit the values directly:
<key>CFBundleLocalizations</key>
<array>
<string>de</string>
<string>es</string>
<string>fr</string>
<string>ja</string>
<string>pt</string> <!-- Brazil -->
<string>pt-PT</string> <!-- Portugal -->
<string>ru</string>
<string>zh-Hans</string>
<string>zh-Hant</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
Once you've implemented the dependency service and updated Info.plist, the iOS app will be able to display
localized text.
NOTE
Note that Apple treats Portuguese slightly differently than you'd expect. From their docs: "use pt as the language ID for
Portuguese as it is used in Brazil and pt-PT as the language ID for Portuguese as it is used in Portugal". This means when
Portuguese language is chosen in a non-standard locale, the fallback language will be Brazilian Portuguese on iOS, unless
code is written to change this behavior (such as the ToDotnetFallbackLanguage above).
[assembly:Dependency(typeof(UsingResxLocalization.Android.Localize))]
namespace UsingResxLocalization.Android
{
public class Localize : UsingResxLocalization.ILocalize
{
public void SetLocale(CultureInfo ci)
{
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
}
public CultureInfo GetCurrentCultureInfo()
{
var netLanguage = "en";
var androidLocale = Java.Util.Locale.Default;
netLanguage = AndroidToDotnetLanguage(androidLocale.ToString().Replace("_", "-"));
// this gets called a lot - try/catch can be expensive so consider caching or something
System.Globalization.CultureInfo ci = null;
try
{
ci = new System.Globalization.CultureInfo(netLanguage);
}
catch (CultureNotFoundException e1)
{
// iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
// fallback to first characters, in this case "en"
try
{
var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
ci = new System.Globalization.CultureInfo(fallback);
}
catch (CultureNotFoundException e2)
{
// iOS language not valid .NET culture, falling back to English
ci = new System.Globalization.CultureInfo("en");
}
}
return ci;
}
string AndroidToDotnetLanguage(string androidLanguage)
{
var netLanguage = androidLanguage;
//certain languages need to be converted to CultureInfo equivalent
switch (androidLanguage)
{
case "ms-BN": // "Malaysian (Brunei)" not supported .NET culture
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
netLanguage = "ms"; // closest supported
break;
case "in-ID": // "Indonesian (Indonesia)" has different code in .NET
netLanguage = "id-ID"; // correct code for .NET
break;
case "gsw-CH": // "Schwiizertüütsch (Swiss German)" not supported .NET culture
netLanguage = "de-CH"; // closest supported
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
return netLanguage;
}
string ToDotnetFallbackLanguage(PlatformCulture platCulture)
{
var netLanguage = platCulture.LanguageCode; // use the first part of the identifier (two chars,
usually);
switch (platCulture.LanguageCode)
{
case "gsw":
netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
return netLanguage;
}
}
}
NOTE
The try/catch blocks in the GetCurrentCultureInfo method mimic the fallback behavior typically used with locale
specifiers – if the exact match is not found, look for a close match based just on the language (first block of characters in the
locale).
In the case of Xamarin.Forms, some locales are valid in Android but do not correspond to a valid CultureInfo in .NET, and
the code above attempts to handle this.
Developers should modify the iOSToDotnetLanguage and ToDotnetFallbackLanguage methods to handle specific cases
required for their supported languages.
Once this code has been added to the Android application project, it will be able to automatically display translated
strings.
NOTE
WARNING: If the translated strings are working in your RELEASE Android builds but not while debugging, right-click on
the Android Project and select Options > Build > Android Build and ensure that the Fast assembly deployment is
NOT ticked. This option causes problems with loading resources and should not be used if you are testing localized apps.
Expand the Properties node in the .NET Standard library project and double-click on the AssemblyInfo.cs file.
Add the following line to the file to set the neutral resources assembly language to English:
[assembly: NeutralResourcesLanguage("en")]
This informs the resource manager of the app's default culture, therefore ensuring that the strings defined in the
language neutral RESX file (AppResources.resx) will be displayed when the app is running in one the English
locales.
Example
After updating the platform-specific projects as shown above and recompiling the app with translated RESX files,
updated translations will be available in each app. Here is a screenshot from the sample code translated into
Simplified Chinese:
Localizing XAML
When building a Xamarin.Forms user interface in XAML the markup would look similar to this, with strings
embedded directly in the XML:
Ideally, we could translate user interface controls directly in the XAML, which we can do by creating a markup
extension. The code for a markup extension that exposes the RESX resources to XAML is shown below. This class
should be added to the Xamarin.Forms common code (along with the XAML pages):
using System;
using System.Globalization;
using System.Reflection;
using System.Resources;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace UsingResxLocalization
{
// You exclude the 'Extension' suffix when using in XAML
[ContentProperty("Text")]
public class TranslateExtension : IMarkupExtension
{
readonly CultureInfo ci = null;
const string ResourceId = "UsingResxLocalization.Resx.AppResources";
public TranslateExtension()
{
if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
{
ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
}
}
The following bullets explain the important elements in the code above:
The class is named TranslateExtension , but by convention we can refer to is as Translate in our markup.
The class implements IMarkupExtension , which is required by Xamarin.Forms for it to work.
"UsingResxLocalization.Resx.AppResources" is the resource identifier for our RESX resources. It is comprised of
our default namespace, the folder where the resource files are located and the default RESX filename.
The ResourceManager class is created using
IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly) to determine the current assembly
to load resources from, and cached in the static ResMgr field. It's created as a Lazy type so that its creation is
deferred until it's first used in the ProvideValue method.
ci uses the dependency service to get the user's chosen language from the native operating system.
GetString is the method that retrieves the actual translated string from the resources files. On the Universal
Windows Platform, ci will be null because the ILocalize interface isn't implemented on those platforms. This
is equivalent to calling the GetString method with only the first parameter. Instead, the resources framework
will automatically recognize the locale and will retrieve the translated string from the appropriate RESX file.
Error handling has been included to help debug missing resources by throwing an exception (in DEBUG mode
only).
The following XAML snippet shows how to use the markup extension. There are two steps to make it work:
1. Declare the custom xmlns:i18n namespace in the root node. The namespace and assembly must match the
project settings exactly - in this example they are identical but could be different in your project.
2. Use {Binding} syntax on attributes that would normally contain text to call the Translate markup extension.
The resource key is the only required parameter.
The following more verbose syntax is also valid for the markup extension:
All platforms will automatically resolve image references like these to localized versions of the images, as long as
the project structures explained below are implemented.
iOS Application Project
iOS uses a naming standard called Localization Projects or .lproj directories to contain image and string resources.
These directories can contain localized versions of images used in the app, and also the InfoPlist.strings file that
can be used to localize the app name. For more information about iOS Localization, see iOS Localization.
Images
This screenshot shows the iOS sample app with language-specific .lproj directories. The Spanish directory called
es.lproj, contains localized versions of the default image, as well as flag.png:
Each language directory contains a copy of flag.png, localized for that language. If no image is supplied, the
operating system will default to the image in the default language directory. For full Retina support, you should
supply @2x and @3x copies of each image.
App Name
The contents of the InfoPlist.strings is just a single key-value to configure the app name:
"CFBundleDisplayName" = "ResxEspañol";
When the application is run, the app name and the image are both localized:
Android Application Project
Android follows a different scheme for storing localized images using different drawable and strings directories
with a language code suffix. When a four-letter locale code is required (such as zh-TW or pt-BR ), note that Android
requires an additional r following the dash/preceding the locale code (eg. zh-rTW or pt-rBR ). For more information
about Android localization, see Android Localization.
Images
This screenshot shows the Android sample with a some localized drawables and strings:
Note that Android does not use zh-Hans and zh-Hant codes for Simplified and Traditional Chinese; instead, it only
supports country-specific codes zh-CN and zh-TW.
To support different resolution images for high-density screens, create additional language folders with -*dpi
suffixes, such as drawables-es-mdpi, drawables-es-xdpi, drawables-es-xxdpi, etc. See Providing Alternative
Android Resources for more information.
App Name
The contents of the strings.xml is just a single key-value to configure the app name:
Update the MainActivity.cs in the Android app project so that the Label references the strings XML.
The app now localizes the app name and image. Here's a screenshot of the result (in Spanish):
Universal Windows Platform Application Projects
The Universal Windows Platform possesses a resource infrastructure that simplifies the localization of images and
the app name. For more information about UWP localization, see UWP Localization.
Images
Images can be localized by placing them in a resource-specific folder, as demonstrated in the following screenshot:
At runtime the Windows resource infrastructure will select the appropriate image based on the user's locale.
Summary
Xamarin.Forms applications can be localized using RESX files and .NET globalization classes. Apart from a small
amount of platform-specific code to detect what language the user prefers, most of the localization effort is
centralized in the common code.
Images are generally handled in a platform-specific way to take advantage of the multi-resolution support
provided in both iOS and Android.
Related Links
RESX Localization Sample
TodoLocalized Sample App
Cross-Platform Localization
iOS Localization
Android Localization
UWP Localization
Using the CultureInfo class (MSDN )
Locating and Using Resources for a Specific Culture (MSDN )
Right-to-left localization
5/1/2019 • 4 minutes to read • Edit Online
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.
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>
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.
Related links
TodoLocalizedRTL Sample App
Xamarin.Forms Local Databases
12/7/2018 • 2 minutes to read • Edit Online
Overview
Xamarin.Forms applications can use the SQLite.NET PCL NuGet package to incorporate database operations into
shared code by referencing the SQLite classes that ship in the NuGet. Database operations can be defined in the
.NET Standard library project of the Xamarin.Forms solution.
The accompanying sample application is a simple Todo-list application. The following screenshots show how the
sample appears on each platform:
Using SQLite
To add SQLite support to a Xamarin.Forms .NET Standard library, use NuGet's search function to find sqlite-net-
pcl and install the latest package:
There are a number of NuGet packages with similar names, the correct package has these attributes:
Created by: Frank A. Krueger
Id: sqlite-net-pcl
NuGet link: sqlite-net-pcl
NOTE
Despite the package name, use the sqlite-net-pcl NuGet package even in .NET Standard projects.
Once the reference has been added, add a property to the App class that returns a local file path for storing the
database:
The TodoItemDatabase constructor, which takes the path for the database file as an argument, is shown below:
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.
The remainder of the TodoItemDatabase class contains SQLite queries that run cross-platform. Example query
code is shown below (more details on the syntax can be found in Using SQLite.NET with Xamarin.iOS.
public Task<List<TodoItem>> GetItemsAsync()
{
return database.Table<TodoItem>().ToListAsync();
}
NOTE
The advantage of using the asynchronous SQLite.Net API is that database operations are moved to background threads. In
addition, there's no need to write additional concurrency handling code because the API takes care of it.
Summary
Xamarin.Forms supports database-driven applications using the SQLite database engine, which makes it possible
to load and save objects in shared code.
This article focused on accessing a SQLite database using Xamarin.Forms. For more information on working with
SQLite.Net itself, refer to the SQLite.NET on Android or SQLite.NET on iOS documentation.
Related Links
Todo Sample
Xamarin.Forms Samples
Xamarin.Forms MessagingCenter
4/15/2019 • 3 minutes to read • Edit Online
Overview
Xamarin.Forms MessagingCenter enables view models and other components to communicate without having to
know anything about each other besides a simple Message contract.
In the MainPage class the following code sends the message. The this parameter is an instance of MainPage .
The string doesn't change - it indicates the message type and is used for determining which subscribers to notify.
This sort of message is used to indicate that some event occurred, such as "upload completed", where no further
information is required.
Passing an Argument
To pass an argument with the message, specify the argument Type in the Subscribe generic arguments and in the
Action signature.
To send the message with argument, include the Type generic parameter and the value of the argument in the
Send method call.
This simple example uses a string argument but any C# object can be passed.
Unsubscribe
An object can unsubscribe from a message signature so that no future messages are delivered. The Unsubscribe
method syntax should reflect the signature of the message (so may need to include the generic Type parameter for
the message argument).
Summary
The MessagingCenter is a simple way to reduce coupling, especially between view models. It can be used to send
and receive simple messages or pass an argument between classes. Classes should unsubscribe from messages
they no longer wish to receive.
Related Links
MessagingCenterSample
Xamarin.Forms Samples
Communicating Between Loosely Coupled Components
Xamarin.Forms Navigation
7/12/2018 • 2 minutes to read • Edit Online
Xamarin.Forms provides a number of different page navigation experiences, depending upon the Page type being
used.
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.
Displaying Pop-Ups
Xamarin.Forms provides two pop-up-like user interface elements: an alert and an action sheet. These interface
elements can be used to ask users simple questions and to guide users through tasks.
Hierarchical Navigation
5/1/2019 • 10 minutes to read • Edit Online
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:
NOTE
It's recommended that a NavigationPage should be populated with ContentPage instances only.
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.
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.
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:
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:
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.
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:
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;
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.
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:
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.
<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>
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 Tabbed Page
3/21/2019 • 5 minutes to read • Edit Online
Overview
The following screenshots show a TabbedPage on each platform:
NOTE
Note that 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 by default, and the detail area is below.
However, the tab list can be moved to the bottom of the screen with a platform-specific. For more
information, see Setting TabbedPage Toolbar Placement and Color.
NOTE
Note that when using AppCompat on Android, each tab will also display an icon. In addition, 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 Windows tablet form-factors, the tabs aren't always visible and users need to swipe-down (or right-
click, if they have a mouse attached) to view the tabs in a TabbedPage (as shown below ).
Creating 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 instances.
Assign a collection to the ItemsSource property and assign a DataTemplate to the ItemTemplate property to
return pages for objects in the collection.
With both approaches, the TabbedPage will display each page as the user selects each tab.
NOTE
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.
<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" Icon="schedule.png">
<x:Arguments>
<local:SchedulePage />
</x:Arguments>
</NavigationPage>
</TabbedPage>
The following code example shows the equivalent TabbedPage created in C#:
public class MainPageCS : TabbedPage
{
public MainPageCS ()
{
var navigationPage = new NavigationPage (new SchedulePageCS ());
navigationPage.Icon = "schedule.png";
navigationPage.Title = "Schedule";
The TabbedPage is populated with two child Page objects. The first child is a ContentPage instance, and the second
tab is a NavigationPage containing a ContentPage instance.
NOTE
The TabbedPage does not support UI virtualization. Therefore, performance may be affected if the TabbedPage contains
too many child elements.
The following screenshots show the TodayPage ContentPage instance, which is shown on the Today tab:
Selecting the Schedule tab displays the SchedulePage ContentPage instance, which is wrapped in a
NavigationPage instance, and is shown in the following screenshot:
For information about the layout of a NavigationPage , see Performing Navigation.
NOTE
While it's acceptable to place a NavigationPage into 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.
This causes the UpcomingAppointmentsPage instance to be pushed onto the navigation stack, where it becomes the
active page. This is shown in the following screenshots:
For more information about performing navigation using the NavigationPage class, see Hierarchical Navigation.
Populating a TabbedPage with a Template
The following XAML code example shows a TabbedPage constructed by assigning a DataTemplate to the
ItemTemplate property to return pages for objects in the collection:
<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">
<TabbedPage.Resources>
<ResourceDictionary>
<local:NonNullToBooleanConverter x:Key="booleanConverter" />
</ResourceDictionary>
</TabbedPage.Resources>
<TabbedPage.ItemTemplate>
<DataTemplate>
<ContentPage Title="{Binding Name}" Icon="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 TabbedPage is populated with data by setting the ItemsSource property in the constructor for the code-behind
file:
public TabbedPageDemoPage ()
{
...
ItemsSource = MonkeyDataModel.All;
}
The following code example shows the equivalent TabbedPage created in C#:
public class TabbedPageDemoPageCS : TabbedPage
{
public TabbedPageDemoPageCS ()
{
var booleanConverter = new NonNullToBooleanConverter ();
Each tab displays a ContentPage that uses a series of StackLayout and Label instances to display data for the tab.
The following screenshots show the content for the Tamarin tab:
Selecting another tab then displays content for that tab.
NOTE
The TabbedPage does not support UI virtualization. Therefore, performance may be affected if the TabbedPage contains
too many child elements.
For more information about the TabbedPage , see Chapter 25 of Charles Petzold's Xamarin.Forms book.
Summary
This article demonstrated how to use a TabbedPage to navigate through a collection of pages. The Xamarin.Forms
TabbedPage consists of a list of tabs and a larger detail area, with each tab loading content into the detail area.
Related Links
Page Varieties
TabbedPageWithNavigationPage (sample)
TabbedPage (sample)
TabbedPage
Xamarin.Forms Carousel Page
12/7/2018 • 4 minutes to read • Edit Online
Overview
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.
Creating 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.
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.
NOTE
The CarouselPage does not support UI virtualization. Therefore, performance may be affected if the CarouselPage
contains too many child elements.
<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;
}
ItemsSource = ColorsDataModel.All;
}
}
Each ContentPage simply displays a Label for a particular color and a BoxView of that color.
NOTE
The CarouselPage does not support UI virtualization. Therefore, performance may be affected if the CarouselPage
contains too many child elements.
For more information about the CarouselPage , see Chapter 25 of Charles Petzold's Xamarin.Forms book.
Summary
This article demonstrated how to use a CarouselPage to navigate through a collection of pages. The CarouselPage
is a page that users can swipe from side to side to navigate through pages of content,much like a gallery.
Related Links
Page Varieties
CarouselPage (sample)
CarouselPageTemplate (sample)
CarouselPage
Xamarin.Forms Master-Detail Page
2/22/2019 • 8 minutes to read • Edit Online
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 ());
...
}
...
}
<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"
Icon="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 Icon 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)
});
grid.Children.Add(image);
grid.Children.Add(label, 1, 0);
Icon = "hamburger.png";
Title = "Personal Organiser";
Content = new StackLayout
{
Children = { listView }
};
}
}
The following screenshots show the ContactPage detail page, which is shown after it's been selected on the master
page:
The following code example shows the equivalent MasterDetailPage created in C#:
public MainPageCS ()
{
MasterBehavior = MasterBehavior.Popover;
...
}
}
However, the value of the MasterBehavior property only affects applications running on tablets or the desktop.
Applications running on phones always have the Popover behavior.
Summary
This article demonstrated how to use a MasterDetailPage and navigate between its pages of information. 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.
Related Links
Page Varieties
MasterDetailPage (sample)
MasterDetailPage
Xamarin.Forms Modal Pages
3/21/2019 • 6 minutes to read • Edit Online
Overview
A modal page can be any of the Page types supported by Xamarin.Forms. To display a modal page the application
will push it onto the modal stack, where it will become the active page, as shown in the following diagram:
To return to the previous page the application will pop the current page from the modal stack, and the new
topmost page becomes the active page, as shown in the following diagram:
Performing Navigation
Modal navigation methods are exposed by the Navigation property on any Page derived types. These methods
provide the ability to push modal pages onto the modal stack, and pop modal pages from the modal stack.
The Navigation property also exposes a ModalStack property from which the modal pages in the modal stack can
be obtained. However, there is no concept of performing modal stack manipulation, or popping to the root page in
modal navigation. This is because these operations are not universally supported on the underlying platforms.
NOTE
A NavigationPage instance is not required for performing modal page navigation.
This causes the ModalPage instance to be pushed onto the modal stack, where it becomes the active page,
provided that an item has been selected in the ListView on the MainPage instance. The ModalPage instance is
shown in the following screenshots:
However, the precise order that 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.
This causes the ModalPage instance to be removed from the modal stack, with the new topmost page becoming
the active page. When PopModalAsync is invoked, the following events occur:
The page calling PopModalAsync has its OnDisappearing override invoked.
The page being returned to has its OnAppearing override invoked, provided that the underlying platform isn't
Android.
The PopModalAsync task returns.
However, the precise order that these events occur is platform dependent. For more information, see Chapter 24
of Charles Petzold's Xamarin.Forms book.
Disabling the Back Button
On Android, the user can always return to the previous page by pressing the standard Back button on the device. If
the modal page requires the user to complete a self-contained task before leaving the page, the application must
disable the Back button. This can be accomplished by overriding the Page.OnBackButtonPressed method on the
modal page. For more information see Chapter 24 of Charles Petzold's Xamarin.Forms book.
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:
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.
This code creates a MainPage instance, passing in the current date and time in ISO8601 format.
The MainPage instance receives the data through a constructor parameter, as shown in the following code example:
The data is then displayed on the page by setting the Label.Text property.
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:
This code sets the BindingContext of the DetailPage instance to the Contact instance, and then navigates to the
DetailPage .
The DetailPage 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="ModalNavigation.DetailPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0,40,0,0" />
</OnPlatform>
</ContentPage.Padding>
<ContentPage.Content>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Label Text="Name:" FontSize="Medium" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" />
</StackLayout>
...
<Button x:Name="dismissButton" Text="Dismiss" Clicked="OnDismissButtonClicked" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The following code example shows how the data binding can be accomplished in C#:
public class DetailPageCS : ContentPage
{
public DetailPageCS ()
{
var nameLabel = new Label {
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
FontAttributes = FontAttributes.Bold
};
nameLabel.SetBinding (Label.TextProperty, "Name");
...
var dismissButton = new Button { Text = "Dismiss" };
dismissButton.Clicked += OnDismissButtonClicked;
Thickness padding;
switch (Device.RuntimePlatform)
{
case Device.iOS:
padding = new Thickness(0, 40, 0, 0);
break;
default:
padding = new Thickness();
break;
}
Padding = padding;
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
}
},
...
dismissButton
}
};
}
Summary
This article demonstrated how to navigate to 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.
Related Links
Page Navigation
Modal (sample)
PassingData (sample)
Displaying Pop-ups
3/21/2019 • 2 minutes to read • Edit Online
Displaying an Alert
All Xamarin.Forms-supported platforms have a modal pop-up to alert the user or ask simple questions of them. To
display these alerts in Xamarin.Forms, use the DisplayAlert method on any Page . The following line of code
shows a simple message to the user:
This example does not collect information from the user. The alert displays modally and once dismissed the user
continues interacting with the application.
The DisplayAlert method can also be used to capture a user's response by presenting two buttons and returning
a boolean . To get a response from an alert, supply text for both buttons and await the method. After the user
selects one of the options the answer will be returned to your code. Note the async and await keywords in the
sample code below:
The destroy button is rendered differently than the others, and can be left null or specified as the third string
parameter. The following example uses the destroy button:
Related Links
PopupsSample
Xamarin.Forms Shell
2/11/2019 • 8 minutes to read • Edit Online
IMPORTANT
Existing iOS and Android applications can adopt Shell and benefit immediately from navigation, performance, and extensibility
improvements.
Shell provides an opinionated navigation user interface, based on flyouts and tabs. The top level of navigation in a
Shell application is a flyout:
The next level of navigation is the bottom tab bar:
When the flyout isn't open the bottom tab bar will be considered the top level of navigation
Within each bottom tab, the next navigation level is the top tab bar, where each tab is a ContentPage :
Within each ContentPage , additional ContentPage instances can be added to and removed from the navigation
stack.
namespace TailwindTraders.Mobile
{
public partial class App : Application
{
public App()
{
InitializeComponent();
The TheShell class is a XAML file that describes the visual structure of your application.
IMPORTANT
Shell is currently experimental, and can only be used by adding Forms.SetFlags("Shell_Experimental"); to your platform
project, prior to invoking the Forms.Init method.
Android
iOS
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
global::Xamarin.Forms.Forms.SetFlags("Shell_Experimental");
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
None of these elements represent any user interface, but rather the organization of the application's visual
structure. Shell will take these elements and produce the navigation user interface for the content.
The following XAML shows a simple example of a Shell file:
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TailwindTraders.Mobile.Features.Shell"
x:Class="TailwindTraders.Mobile.Features.Shell.TheShell"
Title="TailwindTraders">
<ShellItem Title="Home">
<ShellSection>
<ShellContent>
<local:HomePage />
</ShellContent>
</ShellSection>
</ShellItem>
</Shell>
NOTE
Each ShellItem can also set an FlyoutIcon property to an ImageSource , which will be displayed to the left of the title.
This XAML displays the HomePage , because it's the first item of content declared in the Shell file:
Pressing the hamburger button displays the flyout:
The number of items in the flyout can be increased by adding more ShellItem instances to the Shell file. However,
note that HomePage is created during application startup, and adding additional ShellItem instances using this
approach will result in these pages also being created during application startup. This can be avoided by setting the
ShellContent.ContentTemplate property to a DataTemplate :
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TailwindTraders.Mobile.Features.Shell"
x:Class="TailwindTraders.Mobile.Features.Shell.TheShell"
Title="TailwindTraders">
<ShellItem Title="Home">
<ShellSection>
<ShellContent>
<local:HomePage />
</ShellContent>
</ShellSection>
<ShellItem>
<ShellContent Title="Profile"
ContentTemplate="{DataTemplate local:ProfilePage}" />
</Shell>
With this approach, ProfilePage is only created when the user navigates to it, rather than at application startup. In
addition, note that for ProfilePage , the ShellItem and ShellSection objects are omitted, with the Title
property being defined on the ShellContent instance. This concise approach requires less markup, with Shell
supplying the required logical wrappers (without introducing additional views to the visual tree).
In addition, each ShellItem appearance can be customized by setting the Shell.ItemTemplate property to a
DataTemplate :
<Shell.ItemTemplate>
<DataTemplate>
<ContentView HeightRequest="32">
<ContentView.Padding>
<Thickness Left="32"
Top="16" />
</ContentView.Padding>
<Label Text="{Binding Title}" />
</ContentView>
</DataTemplate>
</Shell.ItemTemplate>
This code simply repositions the text for each ShellItem within the flyout. Note that Shell provides the Title
(and Icon ) properties to the BindingContext of the DataTemplate .
Flyout
The flyout is the root menu for the application, and consists of a flyout header, and menu items:
Flyout behavior
The flyout is accessible through the hamburger button or by swiping from the side of the screen. However, this
behavior can be changed by setting the Shell.FlyoutBehavior property to one of the FlyoutBehavior enumeration
members:
<Shell ...
FlyoutBehavior="Disabled">
...
</Shell>
Setting the FlyoutBehavior property to Disabled hides the flyout, which is useful when you only have one
ShellItem . The other valid FlyoutBehavior values are Flyout (default), and Locked .
Flyout header
The flyout header is the content that optionally appears at the top of the flyout, with its appearance being defined
by a View that can be set through the Shell.FlyoutHeader property value:
<Shell.FlyoutHeader>
<local:FlyoutHeader />
</Shell.FlyoutHeader>
Alternatively, the flyout header appearance can be defined by setting the Shell.FlyoutHeaderTemplate property to a
DataTemplate :
<Shell.FlyoutHeaderTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="Fill"
VerticalOptions="Fill"
BackgroundColor="White"
Padding="16">
<Label FontSize="Medium"
Text="Smart Shopping">
<Label.Margin>
<Thickness Left="8" />
</Label.Margin>
</Label>
<Button Image="photo"
Text="By taking a photo">
<Button.Margin>
<Thickness Top="16" />
</Button.Margin>
</Button>
<Button Image="ia"
Text="By using AR">
<Button.Margin>
<Thickness Top="8" />
</Button.Margin>
</Button>
</StackLayout>
</DataTemplate>
</Shell.FlyoutHeaderTemplate>
By default, the flyout header will be fixed in the flyout while the content below will scroll if there are enough items.
However, this behavior can be changed by setting the Shell.FlyoutHeaderBehavior property to one of the
FlyoutHeaderBehavior enumeration members:
<Shell ...
FlyoutHeaderBehavior="CollapseOnScroll">
...
</Shell>
Setting the FlyoutHeaderBehavior to collapses the flyout as scrolling occurs. The other valid
CollapseOnScroll
FlyoutHeaderBehavior values are Default , Fixed , and Scroll (scroll with the menu items).
Menu items
The number of items in the flyout can be increased by adding more ShellItem instances. However, it's also
possible to add MenuItem instances to the flyout. This permits scenarios such as navigating to an identical page
while passing data through the MenuItem.CommandParameter property.
MenuItem instances should be added to the Shell.MenuItems collection:
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TailwindTraders.Views"
x:Class="TailwindTraders.Shell"
FlyoutHeaderBehavior="Fixed"
Title="Tailwind Traders"
...>
<Shell.MenuItems>
<MenuItem Command="{Binding ProductTypeCommand}"
CommandParameter="1"
Text="Holiday decorations" />
<MenuItem Command="{Binding ProductTypeCommand}"
CommandParameter="2"
Text="Appliances" />
<MenuItem Command="{Binding ProductTypeCommand}"
CommandParameter="3"
Text="Bathrooms" />
...
</Shell.MenuItems>
<ShellItem Title="Home">
<ShellSection>
<ShellContent>
<local:HomePage />
</ShellContent>
</ShellSection>
</ShellItem>
</Shell>
NOTE
Each MenuItem can also set an Icon property to a FileImageSource , which will be displayed to the left of the text.
<Shell.MenuItemTemplate>
<DataTemplate>
<ContentView HeightRequest="32">
<ContentView.Padding>
<Thickness Left="32"
Top="16" />
</ContentView.Padding>
<Label Text="{Binding Text}"
FontAttributes="Bold" />
</ContentView>
</DataTemplate>
</Shell.MenuItemTemplate>
Tabs
ShellSection instances will be rendered as bottom tabs, provided that there are multiple ShellSection instances
in a single ShellItem :
ShellContent items will be rendered as top tabs, provided that there are multiple ShellContent instances within a
single ShellSection :
Tabs can be styled using XAML styles, or by supplying a custom renderer. For example, the following example
shows a XAML style that sets tab color:
<Style x:Key="BaseStyle"
TargetType="Element">
<Setter Property="Shell.ShellTabBarBackgroundColor"
Value="#3498DB" />
<Setter Property="Shell.ShellTabBarTitleColor"
Value="White" />
<Setter Property="Shell.ShellTabBarUnselectedColor"
Value="#B4FFFFFF" />
</Style>
Navigation
Shell includes a URI-based navigation experience. URIs provide an improved navigation experience that permits
navigation to any page in the application, without having to follow a set navigation hierarchy. In addition, it also
provides the ability to navigate backwards without having to visit all of the pages on the navigation stack.
This URI-based navigation is accomplished with routes, which are URI segments used to navigate within the
application. The Shell file must declare a route scheme, a route host, and a route:
<Shell ...
Route="tailwindtraders"
RouteHost="www.microsoft.com"
RouteScheme="app">
...
</Shell>
Combined, the RouteScheme , RouteHost , and Route property values form the
app://www.microsoft.com/tailwindtraders root URI.
Each element in the Shell file can also define a route property that can be used in programmatic navigation.
In the Shell file constructor, or any other location that runs before a route is invoked, additional routes can be
explicitly registered for any pages that aren't represented by a Shell element (such as MenuItem instances):
Routing.RegisterRoute("productcategory", typeof(ProductCategoryPage));
Implementing navigation
Menu items expose a Command property that can be used to implement navigation:
To invoke navigation, a reference to the application Shell , through the MainPage property of the Application
class, must be obtained. Then, navigation can be invoked by calling the GoToAsync method, passing a valid URI as
an argument. The GoToAsync method navigates using a ShellNavigationState object, which will be constructed
from a string or a Uri .
Passing data
Data can be passed between pages through query string parameters. Shell will set the query string parameter
values on the ContentPage or ViewModel when you add query property attributes to the class:
[QueryProperty("TypeID", "id")]
public partial class ProductCategoryPage : ContentPage
{
private string _typeId;
public ProductCategoryPage()
{
InitializeComponent();
The QueryProperty attribute specifies that the TypeID will receive the data passed in the id query string
parameter from the URI in the GoToAsync method call.
Intercepting navigation
Shell provides the ability to hook into the navigation routing before it has completed, and after it has completed.
This can be accomplished by registering events handlers for the Navigating and Navigated events, respectively:
<Shell ...
Navigating="OnShellNavigating">
...
</Shell>
In addition, Shell provides an overridable OnBackButtonPressed method that can be used to intercept a back button
press.
Related links
Tailwind Traders (sample)
Xamarin.Forms Templates
12/7/2018 • 2 minutes to read • Edit Online
Control Templates
Xamarin.Forms control templates provide the ability to easily theme and re-theme application pages at runtime.
Data Templates
Xamarin.Forms data templates provide the ability to define the presentation of data on supported controls.
Xamarin.Forms Control Templates
6/8/2018 • 2 minutes to read • Edit Online
Control templates provide a clean separation between the appearance of a page and its content, enabling the
creation of pages that can easily be themed.
Introduction
Xamarin.Forms control templates provide the ability to easily theme and re-theme application pages at runtime.
This article provides an introduction to control templates.
Creating a ControlTemplate
Control templates can be defined at the application level or at the page level. This article demonstrates how to
create and consume control templates.
Xamarin.Forms control templates provide the ability to easily theme and re-theme application pages at runtime.
This article provides an introduction to control templates.
Controls have different properties, such as BackgroundColor and TextColor , that can define aspects of the control's
appearance. These properties can be set using styles, which can be changed at runtime to implement basic
theming. However, styles don't maintain a clean separation between the appearance of a page and its content, and
the changes that can be made by setting such properties are limited.
Control templates provide a clean separation between the appearance of a page and its content, therefore enabling
the creation of pages that can easily be themed. For example, an application may contain application-level control
templates that provide a dark theme and a light theme. Each ContentPage in the application can be themed by
applying one of the control templates without changing the content being displayed by each page. In addition, the
themes provided by control templates aren't limited to changing the properties of controls. They can also change
the controls used to implement the theme.
Creating a ControlTemplate
A ControlTemplate specifies the appearance of a page or view, and contains a root layout, and within the layout,
the controls that implement the template. Typically, a ControlTemplate will utilize a ContentPresenter to mark
where the content to be displayed by the page or view will appear. The page or view that consumes the
ControlTemplate will then define content to be displayed by the ContentPresenter . The following diagram
illustrates a ControlTemplate for a page that contains a number of controls, including a ContentPresenter marked
by a blue rectangle:
A ControlTemplate can be applied to the following types by setting their ControlTemplate properties:
ContentPage
ContentView
TemplatedPage
TemplatedView
When a ControlTemplate is created and assigned to these types, any existing appearance is replaced with the
appearance defined in the ControlTemplate . In addition, as well as setting appearance by using the
ControlTemplate property, control templates can also be applied by using styles to further expand theme ability.
NOTE
What are the TemplatedPage and TemplatedView types? TemplatedPage is the base class for ContentPage , and is the
most basic page type provided by Xamarin.Forms. Unlike ContentPage , TemplatedPage does not have a Content
property. Therefore, content can't be directly added to a TemplatedPage instance. Instead, content is added by setting the
control template for the TemplatedPage instance. Similarly, TemplatedView is the base class for ContentView . Unlike
ContentView , TemplatedView does not have a Content property. Therefore, content can't be directly added to a
TemplatedView instance. Instead, content is added by setting the control template for the TemplatedView instance.
Control templates lower in the view hierarchy take precedence over those defined higher up. For example, a
ControlTemplate named DarkTheme that's defined at the page-level will take precedence over an identically named
template defined at the application-level. Therefore, a control template that defines a theme to be applied to each
page in an application should be defined at the application-level.
Related Links
Styles
ControlTemplate
ContentPresenter
Creating a ControlTemplate
12/7/2018 • 4 minutes to read • Edit Online
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<BoxView ... />
<Label Text="Control Template Demo App"
TextColor="White"
VerticalOptions="Center" ... />
<ContentPresenter ... />
<BoxView Color="Teal" ... />
<Label Text="(c) Xamarin 2016"
TextColor="White"
VerticalOptions="Center" ... />
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="AquaTemplate">
...
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
Each ControlTemplate instance is created as a reusable object in a ResourceDictionary . This is achieved by giving
each declaration a unique x:Key attribute, which provides it with a descriptive key in the ResourceDictionary .
The following code example shows the associated App code-behind:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.HomePage">
<ContentView x:Name="contentView" Padding="0,20,0,0"
ControlTemplate="{StaticResource TealTemplate}">
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="Welcome to the app!" HorizontalOptions="Center" />
<Button Text="Change Theme" Clicked="OnButtonClicked" />
</StackLayout>
</ContentView>
</ContentPage>
The TealTemplate is assigned to the ContentView.ControlTemplate property by using the StaticResource markup
extension. The ContentView.Content property is set to a StackLayout that defines the content to be displayed on
the ContentPage . This content will be displayed by the ContentPresenter contained in the TealTemplate . This
results in the appearance shown in the following screenshots:
This method replaces the active ControlTemplate instance with the alternative ControlTemplate instance, resulting
in the following screenshot:
NOTE
On a ContentPage , the Content property can be assigned and the ControlTemplate property can also be set. When
this occurs, if the ControlTemplate contains a ContentPresenter instance, the content assigned to the Content
property will be presented by the ContentPresenter within the ControlTemplate .
<Style TargetType="ContentView">
<Setter Property="ControlTemplate" Value="{StaticResource TealTemplate}" />
</Style>
Because the Style instance is implicit, it will be applied to all ContentView instances in the application. Therefore,
it's no longer necessary to set the ContentView.ControlTemplate property, as demonstrated in the following code
example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.HomePage">
<ContentView x:Name="contentView" Padding="0,20,0,0">
...
</ContentView>
</ContentPage>
When adding a ControlTemplate at the page level, a ResourceDictionary is added to the ContentPage , and then the
ControlTemplate instances are included in the ResourceDictionary .
Creating a ControlTemplate in C#
To define a ControlTemplate at the application level, a class must be created that represents the ControlTemplate .
The class should derive from the layout being used for the template, as shown in the following code example:
The AquaTemplate class is identical to the TealTemplate class, except that different colors are used for the
BoxView.Color and Label.TextColor properties.
The following code example shows a ContentPage applying the TealTemplate to the ContentView :
public class HomePageCS : ContentPage
{
...
ControlTemplate tealTemplate = new ControlTemplate (typeof(TealTemplate));
ControlTemplate aquaTemplate = new ControlTemplate (typeof(AquaTemplate));
public HomePageCS ()
{
var button = new Button { Text = "Change Theme" };
var contentView = new ContentView {
Padding = new Thickness (0, 20, 0, 0),
Content = new StackLayout {
VerticalOptions = LayoutOptions.CenterAndExpand,
Children = {
new Label { Text = "Welcome to the app!", HorizontalOptions = LayoutOptions.Center },
button
}
},
ControlTemplate = tealTemplate
};
...
Content = contentView;
}
}
The ControlTemplate instances are created by specifying the type of the classes that define the control templates,
in the ControlTemplate constructor.
The ContentView.Contentproperty is set to a StackLayout that defines the content to be displayed on the
ContentPage . This content will be displayed by the ContentPresenter contained in the TealTemplate . The same
mechanism outlined previously is used to change the theme at runtime to the AquaTheme .
Summary
This article demonstrated how to create and consume control templates. Control templates can be defined at the
application level or page level.
Related Links
Styles
Simple Theme (sample)
ControlTemplate
ContentPresenter
ContentView
ResourceDictionary
Binding from a Xamarin.Forms ControlTemplate
12/7/2018 • 4 minutes to read • Edit Online
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label Text="{TemplateBinding Parent.HeaderText}" ... />
...
<Label Text="{TemplateBinding Parent.FooterText}" ... />
</Grid>
</ControlTemplate>
Rather than set the Label.Text properties to static text, the properties can use template bindings to bind to
bindable properties on the parent of the target view that owns the ControlTemplate . However, note that the
template bindings bind to Parent.HeaderText and Parent.FooterText , rather than HeaderText and FooterText .
This is because in this example, the bindable properties are defined on the grandparent of the target view, rather
than the parent, as demonstrated in the following code example:
<ContentPage ...>
<ContentView ... ControlTemplate="{StaticResource TealTemplate}">
...
</ContentView>
</ContentPage>
The source of the template binding is always automatically set to the parent of the target view that owns the
control template, which here is the ContentView instance. The template binding uses the Parent property to
return the parent element of the ContentView instance, which is the ContentPage instance. Therefore, using a
TemplateBinding in the ControlTemplate to bind to Parent.HeaderText and Parent.FooterText locates the
bindable properties that are defined on the ContentPage , as demonstrated in the following code example:
public static readonly BindableProperty HeaderTextProperty =
BindableProperty.Create ("HeaderText", typeof(string), typeof(HomePage), "Control Template Demo App");
public static readonly BindableProperty FooterTextProperty =
BindableProperty.Create ("FooterText", typeof(string), typeof(HomePage), "(c) Xamarin 2016");
Creating a TemplateBinding in C#
In C#, a TemplateBinding is created by using the TemplateBinding constructor, as demonstrated in the following
code example:
Rather than set the Label.Text properties to static text, the properties can use template bindings to bind to
bindable properties on the parent of the target view that owns the ControlTemplate . The template binding is
created by using the SetBinding method, specifying a TemplateBinding instance as the second parameter. Note
that the template bindings bind to Parent.HeaderText and Parent.FooterText , because the bindable properties are
defined on the grandparent of the target view, rather than the parent, as demonstrated in the following code
example:
public class HomePageCS : ContentPage
{
...
public HomePageCS ()
{
Content = new ContentView {
ControlTemplate = tealTemplate,
Content = new StackLayout {
...
},
...
};
...
}
}
The HeaderText and FooterText ViewModel properties can be bound to, as shown in the following XAML code
example:
<ContentPage xmlns:local="clr-namespace:SimpleTheme;assembly=SimpleTheme"
HeaderText="{Binding HeaderText}" FooterText="{Binding FooterText}" ...>
<ContentPage.BindingContext>
<local:HomePageViewModel />
</ContentPage.BindingContext>
<ContentView ControlTemplate="{StaticResource TealTemplate}" ...>
...
</ContentView>
</ContentPage>
The HeaderText and bindable properties are bound to the HomePageViewModel.HeaderText and
FooterText
HomePageViewModel.FooterText properties, due to setting the BindingContext to an instance of the
HomePageViewModel class. Overall, this results in control properties in the ControlTemplate being bound to
BindableProperty instances on the ContentPage , which in turn bind to ViewModel properties.
You can also bind to the view model properties directly, so that you don't need to declare BindableProperty s for
HeaderText and FooterText on the ContentPage , by binding the control template to
Parent.BindingContext.PropertyName e.g.:
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label Text="{TemplateBinding Parent.BindingContext.HeaderText}" ... />
...
<Label Text="{TemplateBinding Parent.BindingContext.FooterText}" ... />
</Grid>
</ControlTemplate>
For more information about data binding to ViewModels, see From Data Bindings to MVVM.
Summary
This article demonstrated using template bindings to perform data binding from a control template. Template
bindings allow controls in a control template to data bind to public properties, enabling property values on
controls in the control template to be easily changed.
Related Links
Data Binding Basics
From Data Bindings to MVVM
Simple Theme with Template Binding (sample)
Simple Theme with Template Binding and ViewModel (sample)
TemplateBinding
ControlTemplate
ContentView
Xamarin.Forms Data Templates
12/7/2018 • 2 minutes to read • Edit Online
Introduction
Xamarin.Forms data templates provide the ability to define the presentation of data on supported controls. This
article provides an introduction to data templates, examining why they are necessary.
Creating a DataTemplate
Data templates can be created inline, in a ResourceDictionary , or from a custom type or appropriate
Xamarin.Forms cell type. An inline template should be used if there's no need to reuse the data template
elsewhere. Alternatively, a data template can be reused by defining it as a custom type, or as a control-level, page-
level, or application-level resource.
Creating a DataTemplateSelector
A DataTemplateSelector can be used to choose a DataTemplate at runtime based on the value of a data-bound
property. This enables multiple DataTemplate instances to be applied to the same type of object, to customize the
appearance of particular objects. This article demonstrates how to create and consume a DataTemplateSelector .
Related Links
Data Templates (sample)
Introduction to Xamarin.Forms Data Templates
12/7/2018 • 3 minutes to read • Edit Online
The Person class defines Name , Age , and Location properties, which can be set when a Person object is created.
The ListView is used to display the collection of Person objects, 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"
xmlns:local="clr-namespace:DataTemplates"
...>
<StackLayout Margin="20">
...
<ListView Margin="0,20,0,0">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:Person}">
<local:Person Name="Steve" Age="21" Location="USA" />
<local:Person Name="John" Age="37" Location="USA" />
<local:Person Name="Tom" Age="42" Location="UK" />
<local:Person Name="Lucas" Age="29" Location="Germany" />
<local:Person Name="Tariq" Age="39" Location="UK" />
<local:Person Name="Jane" Age="30" Location="USA" />
</x:Array>
</ListView.ItemsSource>
</ListView>
</StackLayout>
</ContentPage>
Items are added to the ListView in XAML by initializing the ItemsSource property from an array of Person
instances.
NOTE
Note that the x:Array element requires a Type attribute indicating the type of the items in the array.
The equivalent C# page is shown in the following code example, which initializes the ItemsSource property to a
List of Person instances:
public WithoutDataTemplatePageCS()
{
...
var people = new List<Person>
{
new Person { Name = "Steve", Age = 21, Location = "USA" },
new Person { Name = "John", Age = 37, Location = "USA" },
new Person { Name = "Tom", Age = 42, Location = "UK" },
new Person { Name = "Lucas", Age = 29, Location = "Germany" },
new Person { Name = "Tariq", Age = 39, Location = "UK" },
new Person { Name = "Jane", Age = 30, Location = "USA" }
};
The ListView calls ToString when displaying the objects in the collection. Because there is no Person.ToString
override, ToString returns the type name of each object, as shown in the following screenshots:
The Person object can override the ToString method to display meaningful data, as shown in the following code
example:
This results in the ListView displaying the Person.Name property value for each object in the collection, as shown
in the following screenshots:
The Person.ToString override could return a formatted string consisting of the Name , Age , and Location
properties. However, this approach offers only a limited control over the appearance of each item of data. For
more flexibility, a DataTemplate can be created that defines the appearance of the data.
Creating a DataTemplate
A DataTemplate is used to specify the appearance of data, and typically uses data binding to display data. Its
common usage scenario is when displaying data from a collection of objects in a ListView . For example, when a
ListView is bound to a collection of Person objects, the ListView.ItemTemplate property will be set to a
DataTemplate that defines the appearance of each Person object in the ListView . The DataTemplate will contain
elements that bind to property values of each Person object. For more information about data binding, see Data
Binding Basics.
A DataTemplate can be used as a value for the following properties:
ListView.HeaderTemplate
ListView.FooterTemplate
ListView.GroupHeaderTemplate
ItemsView.ItemTemplate , which is inherited by ListView .
MultiPage.ItemTemplate , which is inherited by CarouselPage , MasterDetailPage , and TabbedPage .
NOTE
Note that although the TableView makes uses of Cell objects, it does not use a DataTemplate . This is because data
bindings are always set directly on Cell objects.
A DataTemplate that's placed as a direct child of the properties listed above is known as an inline template.
Alternatively, a DataTemplate can be defined as a control-level, page-level, or application-level resource. Choosing
where to define a DataTemplate impacts where it can be used:
A DataTemplate defined at the control level can only be applied to the control.
A DataTemplate defined at the page level can be applied to multiple valid controls on the page.
A DataTemplate defined at the application level can be applied to valid controls throughout the application.
Data templates lower in the view hierarchy take precedence over those defined higher up when they share x:Key
attributes. For example, an application-level data template will be overridden by a page-level data template, and a
page-level data template will be overridden by a control-level data template, or an inline data template.
Related Links
Cell Appearance
Data Templates (sample)
DataTemplate
Creating a Xamarin.Forms DataTemplate
1/29/2019 • 5 minutes to read • Edit Online
The child of an inline DataTemplate must be of, or derive from, type Cell . This example uses a ViewCell , which
derives from Cell . Layout inside the ViewCell is managed here by a Grid . The Grid contains three Label
instances that bind their Text properties to the appropriate properties of each Person object in the collection.
The equivalent C# code is shown in the following code example:
public class WithDataTemplatePageCS : ContentPage
{
public WithDataTemplatePageCS()
{
...
var people = new List<Person>
{
new Person { Name = "Steve", Age = 21, Location = "USA" },
...
};
nameLabel.SetBinding(Label.TextProperty, "Name");
ageLabel.SetBinding(Label.TextProperty, "Age");
locationLabel.SetBinding(Label.TextProperty, "Location");
grid.Children.Add(nameLabel);
grid.Children.Add(ageLabel, 1, 0);
grid.Children.Add(locationLabel, 2, 0);
In C#, the inline DataTemplate is created using a constructor overload that specifies a Func argument.
Here, the ListView.ItemTemplate property is set to a DataTemplate that's created from a custom type that defines
the cell appearance. The custom type must derive from type ViewCell , as shown in the following code example:
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataTemplates.PersonCell">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Name}" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Age}" />
<Label Grid.Column="2" Text="{Binding Location}" HorizontalTextAlignment="End" />
</Grid>
</ViewCell>
Within the ViewCell , layout is managed here by a Grid . The Grid contains three Label instances that bind their
Text properties to the appropriate properties of each Person object in the collection.
In C#, the DataTemplate is created using a constructor overload that specifies the cell type as an argument. The cell
type must derive from type ViewCell , as shown in the following code example:
nameLabel.SetBinding(Label.TextProperty, "Name");
ageLabel.SetBinding(Label.TextProperty, "Age");
locationLabel.SetBinding(Label.TextProperty, "Location");
grid.Children.Add(nameLabel);
grid.Children.Add(ageLabel, 1, 0);
grid.Children.Add(locationLabel, 2, 0);
View = grid;
}
}
NOTE
Note that Xamarin.Forms also includes cell types that can be used to display simple data in ListView cells. For more
information, see Cell Appearance.
The DataTemplate is assigned to the ListView.ItemTemplate property by using the StaticResource markup
extension. Note that while the DataTemplate is defined in the page's ResourceDictionary , it could also be defined at
the control level or application level.
The following code example shows the equivalent page in C#:
The DataTemplate is added to the ResourceDictionary using the Add method, which specifies a Key string that is
used to reference the DataTemplate when retrieving it.
Summary
This article has explained how to create data templates, inline, from a custom type, or in a ResourceDictionary . An
inline template should be used if there's no need to reuse the data template elsewhere. Alternatively, a data
template can be reused by defining it as a custom type, or as a control-level, page-level, or application-level
resource.
Related Links
Cell Appearance
Data Templates (sample)
DataTemplate
Creating a Xamarin.Forms DataTemplateSelector
12/7/2018 • 3 minutes to read • Edit Online
Creating a DataTemplateSelector
A data template selector is implemented by creating a class that inherits from DataTemplateSelector . The
OnSelectTemplate method is then overridden to return a particular DataTemplate , as shown in the following code
example:
The OnSelectTemplate method returns the appropriate template based on the value of the DateOfBirth property.
The template to return is the value of the ValidTemplate property or the InvalidTemplate property, which are set
when consuming the PersonDataTemplateSelector .
An instance of the data template selector class can then be assigned to Xamarin.Forms control properties such as
ListView.ItemTemplate . For a list of valid properties, see Creating a DataTemplate.
Limitations
DataTemplateSelector instances have the following limitations:
The DataTemplateSelector subclass must always return the same template for the same data if queried multiple
times.
The DataTemplateSelector subclass must not return another DataTemplateSelector subclass.
The DataTemplateSelector subclass must not return new instances of a DataTemplate on each call. Instead, the
same instance must be returned. Failure to do so will create a memory leak and will disable virtualization.
On Android, there can be no more than 20 different data templates per ListView .
This page level ResourceDictionary defines two DataTemplate instances and a PersonDataTemplateSelector
instance. The PersonDataTemplateSelector instance sets its ValidTemplate and InvalidTemplate properties to the
appropriate DataTemplate instances by using the StaticResource markup extension. Note that while the resources
are defined in the page's ResourceDictionary , they could also be defined at the control level or application level.
The PersonDataTemplateSelector instance is consumed by assigning it to the ListView.ItemTemplate property, as
shown in the following code example:
At runtime, the ListView calls the PersonDataTemplateSelector.OnSelectTemplate method for each of the items in
the underlying collection, with the call passing the data object as the item parameter. The DataTemplate that is
returned by the method is then applied to that object.
The following screenshots show the result of the ListView applying the PersonDataTemplateSelector to each
object in the underlying collection:
Any Person object that has a DateOfBirth property value greater than or equal to 1980 is displayed in green, with
the remaining objects being displayed in red.
Consuming a DataTemplateSelector in C#
In C#, the PersonDataTemplateSelector can be instantiated and assigned to the ListView.ItemTemplate property, as
shown in the following code example:
public HomePageCS ()
{
...
SetupDataTemplates ();
var listView = new ListView {
ItemsSource = people,
ItemTemplate = new PersonDataTemplateSelector {
ValidTemplate = validTemplate,
InvalidTemplate = invalidTemplate }
};
The PersonDataTemplateSelector instance sets its ValidTemplate and InvalidTemplate properties to the
appropriate DataTemplate instances created by the SetupDataTemplates method. At runtime, the ListView calls
the PersonDataTemplateSelector.OnSelectTemplate method for each of the items in the underlying collection, with
the call passing the data object as the item parameter. The DataTemplate that is returned by the method is then
applied to that object.
Summary
This article has demonstrated how to create and consume a DataTemplateSelector . A DataTemplateSelector can be
used to choose a DataTemplate at runtime based on the value of a data-bound property. This enables multiple
DataTemplate instances to be applied to the same type of object, to customize the appearance of particular objects.
Related Links
Data Template Selector (sample)
DataTemplateSelector
Xamarin.Forms Triggers
12/7/2018 • 6 minutes to read • Edit Online
Property Triggers
A simple trigger can be expressed purely in XAML, adding a Trigger element to a control's triggers collection.
This example shows a trigger that changes an Entry background color when it receives focus:
Data Triggers
Data triggers use data binding to monitor another control to cause the Setter s to get called. Instead of the
Property attribute in a property trigger, set the Binding attribute to monitor for the specified value.
The example below uses the data binding syntax {Binding Source={x:Reference entry}, Path=Text.Length} which is
how we refer to another control's properties. When the length of the entry is zero, the trigger is activated. In this
sample the trigger disables the button when the input is empty.
Tip: when evaluating Path=Text.Length always provide a default value for the target property (eg. Text="" )
because otherwise it will be null and the trigger won't work like you expect.
In addition to specifying Setter s you can also provide EnterActions and ExitActions .
Event Triggers
The EventTrigger element requires only an Event property, such as "Clicked" in the example below.
<EventTrigger Event="Clicked">
<local:NumericValidationTriggerAction />
</EventTrigger>
Notice that there are no Setter elements but rather a reference to a class defined by
local:NumericValidationTriggerAction which requires the xmlns:local to be declared in the page's XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"
The class itself implements TriggerAction which means it should provide an override for the Invoke method that
is called whenever the trigger event occurs.
A trigger action implementation should:
Implement the generic TriggerAction<T> class, with the generic parameter corresponding with the type of
control the trigger will be applied to. You can use superclasses such as VisualElement to write trigger
actions that work with a variety of controls, or specify a control type like Entry .
Override the Invoke method - this is called whenever the trigger criteria are met.
Optionally expose properties that can be set in the XAML when the trigger is declared (such as Anchor ,
Scale , and Length in this example).
The properties exposed by the trigger action can be set in the XAML declaration as follows:
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
Be careful when sharing triggers in a ResourceDictionary , one instance will be shared among controls so any state
that is configured once will apply to them all.
Note that event triggers do not support EnterActions and ExitActions described below.
Multi Triggers
A MultiTrigger looks similar to a Trigger or DataTrigger except there can be more than one condition. All the
conditions must be true before the Setter s are triggered.
Here's an example of a trigger for a button that binds to two different inputs ( email and phone ):
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference email},
Path=Text.Length}"
Value="0" />
<BindingCondition Binding="{Binding Source={x:Reference phone},
Path=Text.Length}"
Value="0" />
</MultiTrigger.Conditions>
The Conditions collection could also contain PropertyCondition elements like this:
To use this converter in a multi trigger, first add it to the page's resource dictionary (along with a custom
xmlns:local namespace definition):
<ResourceDictionary>
<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>
The XAML is shown below. Note the following differences from the first multi trigger example:
The button has IsEnabled="false" set by default.
The multi trigger conditions use the converter to turn the Text.Length value into a boolean .
When all the conditions are true , the setter makes the button's IsEnabled property true .
<Entry x:Name="user" Text="" Placeholder="user name" />
These screenshots show the difference between the two multi trigger examples above. In the top part of the
screens, text input in just one Entry is enough to enable the Save button. In the bottom part of the screens, the
Login button remains inactive until both fields contain data.
<Trigger.ExitActions>
<local:FadeTriggerAction StartsFrom="1" />
</Trigger.ExitActions>
<!-- You can use both Enter/Exit and Setter together if required -->
</Trigger>
</Entry.Triggers>
</Entry>
As always, when a class is referenced in XAML you should declare a namespace such as xmlns:local as shown
here:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"
}),
length:1000, // milliseconds
easing: Easing.Linear);
}
}
Related Links
Triggers Sample
Xamarin.Forms API Documentation
Xamarin.Forms User Interface Views
3/21/2019 • 3 minutes to read • Edit Online
Animation
Xamarin.Forms includes its own animation infrastructure that's straightforward for creating simple animations,
while also being versatile enough to create complex animations.
BoxView
The BoxView is just a simple colored rectangle, but it can be used for decorative items, rudimentary graphics, and
for obtaining interative touch input.
Button
The Button responds to a tap or click that directs an application to carry out a particular task.
CollectionView
The CollectionView is a flexible and performant view for presenting lists of data using different layout
specifications.
Colors
Defining and using colors across platforms can be tricky when each platform has its own standards and defaults.
Controls Reference
This document is a quick reference to the UI views that make up the Xamarin.Forms framework, such as Pages,
Layouts, Views and Cells.
DataPages
DataPages provide an API to quickly and easily bind a data source to pre-built views. List items and detail pages
will automatically render the data, and be customized using themes.
DatePicker
The DatePicker allows a user to select a date within a specified range. It is implemented using the date picker
supported by the particular platform that the application is run on.
Images
Images can be shared across platforms with Xamarin.Forms, they can be loaded specifically for each platform, or
they can be downloaded for display.
ImageButton
The ImageButton displays an image and responds to a tap or click that directs an application to carry out a
particular task.
Layouts
Xamarin.Forms has several layouts for organizing on-screen content. StackLayout , Grid , FlexLayout ,
AbsoluteLayout , ScrollView , and RelativeLayout can each be used to create beautiful, responsive user interfaces.
ListView
Xamarin.Forms provides a list view control to display scrolling rows of data. The control includes contextual
actions, HasUnevenRows automatic sizing, separator customization, pull-to-refresh, and headers and footers.
Maps
Adding maps requires an additional NuGet package download and some platform-specific configuration. Maps
and pin markers can be added in just a few lines of code once the configuration is done.
Picker
The Picker view is a control for selecting a text item from a list of data.
Slider
The Slider allows a user to select a numeric value from a continuous range.
Stepper
The Stepper allows a user to select a numeric value from a range of values. It consists of two buttons labeled with
minus and plus signs. Manipulating the two buttons changes the selected value incrementally.
Styles
Font, color, and other attributes can be grouped into styles which can be shared across controls, layouts, or the
entire application using ResourceDictionaries.
TableView
The table view is similar to a list view, but rather than being designed for long lists of data it is intended for data-
entry-style screens of scrolling controls or simple scrolling menus.
Text
Xamarin.Forms has several views for presenting and receiving text. Text views can be formatted and customized for
platforms. Specific font settings can enable compatibility with accessibility features.
Themes
Xamarin.Forms Themes define a specific visual appearance for the standard controls. Once you add a theme to the
application's resource dictionary, the appearance of the standard controls will change.
TimePicker
The TimePicker allows a user to select a time. It is implemented using the time picker supported by the particular
platform that the application is run on.
Visual
Xamarin.Forms Material Visual can be used to create Xamarin.Forms applications that look identical, or largely
identical, on iOS and Android.
WebView
Xamarin.Forms uses the native web browser control on each platform, and can display websites, local resources,
and generated Html strings.
Related Links
Xamarin.Forms Gallery (sample)
Animation in Xamarin.Forms
7/12/2018 • 2 minutes to read • Edit Online
Xamarin.Forms includes its own animation infrastructure that's straightforward for creating simple animations,
while also being versatile enough to create complex animations.
The Xamarin.Forms animation classes target different properties of visual elements, with a typical animation
progressively changing a property from one value to another over a period of time. Note that there is no XAML
interface for the Xamarin.Forms animation classes. However, animations can be encapsulated in behaviors and
then referenced from XAML.
Simple Animations
The ViewExtensions class provides extension methods that can be used to construct simple animations that rotate,
scale, translate, and fade VisualElement instances. This article demonstrates creating and canceling animations
using the ViewExtensions class.
Easing Functions
Xamarin.Forms includes an Easing class that allows you to specify a transfer function that controls how
animations speed up or slow down as they're running. This article demonstrates how to consume the pre-defined
easing functions, and how to create custom easing functions.
Custom Animations
The Animation class is the building block of all Xamarin.Forms animations, with the extension methods in the
ViewExtensions class creating one or more Animation objects. This article demonstrates how to use the
Animation class to create and cancel animations, synchronize multiple animations, and create custom animations
that animate properties that aren't animated by the existing animation methods.
Simple Animations in Xamarin.Forms
12/7/2018 • 9 minutes to read • Edit Online
By default, each animation will take 250 milliseconds. However, a duration for each animation can be specified
when creating the animation.
The ViewExtensions class also includes a CancelAnimations method that can be used to cancel any animations.
NOTE
The ViewExtensions class provides a LayoutTo extension method. However, this method is intended to be used by
layouts to animate transitions between layout states that contain size and position changes. Therefore, it should only be
used by Layout subclasses.
The animation extension methods in the ViewExtensions class are all asynchronous and return a Task<bool>
object. The return value is false if the animation completes, and true if the animation is cancelled. Therefore, the
animation methods should typically be used with the await operator, which makes it possible to easily determine
when an animation has completed. In addition, it then becomes possible to create sequential animations with
subsequent animation methods executing after the previous method has completed. For more information, see
Compound Animations.
If there's a requirement to let an animation complete in the background, then the await operator can be omitted.
In this scenario, the animation extension methods will quickly return after initiating the animation, with the
animation occurring in the background. This operation can be taken advantage of when creating composite
animations. For more information, see Composite Animations.
For more information about the await operator, see Async Support Overview.
Single Animations
Each extension method in the ViewExtensions implements a single animation operation that progressively
changes a property from one value to another value over a period of time. This section explores each animation
operation.
Rotation
The following code example demonstrates using the RotateTo method to animate the Rotation property of an
Image :
This code animates the Image instance by rotating up to 360 degrees over 2 seconds (2000 milliseconds). The
RotateTo method obtains the current Rotation property value for the start of the animation, and then rotates
from that value to its first argument (360). Once the animation is complete, the image's Rotation property is reset
to 0. This ensures that the Rotation property doesn't remain at 360 after the animation concludes, which would
prevent additional rotations.
The following screenshots show the rotation in progress on each platform:
Relative Rotation
The following code example demonstrates using the RelRotateTo method to incrementally increase or decrease
the Rotation property of an Image :
This code animates the Image instance by rotating 360 degrees from its starting position over 2 seconds (2000
milliseconds). The RelRotateTo method obtains the current Rotation property value for the start of the
animation, and then rotates from that value to the value plus its first argument (360). This ensures that each
animation will always be a 360 degrees rotation from the starting position. Therefore, if a new animation is
invoked while an animation is already in progress, it will start from the current position and may end at a position
that is not an increment of 360 degrees.
The following screenshots show the relative rotation in progress on each platform:
Scaling
The following code example demonstrates using the ScaleTo method to animate the Scale property of an Image
:
This code animates the Image instance by scaling up to twice its size over 2 seconds (2000 milliseconds). The
ScaleTo method obtains the current Scale property value (default value of 1 ) for the start of the animation, and
then scales from that value to its first argument (2). This has the effect of expanding the size of the image to twice
its size.
The following screenshots show the scaling in progress on each platform:
NOTE
The VisualElement class also defines ScaleX and ScaleY properties, which can scale the VisualElement differently in
the horizontal and vertical directions. These properties can be animated with the Animation class. For more information,
see Custom Animations in Xamarin.Forms.
Relative Scaling
The following code example demonstrates using the RelScaleTo method to animate the Scale property of an
Image :
This code animates the Image instance by scaling up to twice its size over 2 seconds (2000 milliseconds). The
RelScaleTo method obtains the current Scale property value for the start of the animation, and then scales from
that value to the value plus its first argument (2). This ensures that each animation will always be a scaling of 2
from the starting position.
Scaling and Rotation with Anchors
The AnchorX and AnchorY properties set the center of scaling or rotation for the Rotation and Scale properties.
Therefore, their values also affect the RotateTo and ScaleTo methods.
Given an Image that has been placed at the center of a layout, the following code example demonstrates rotating
the image around the center of the layout by setting its AnchorY property:
Translation
The following code example demonstrates using the TranslateTo method to animate the TranslationX and
TranslationY properties of an Image :
This code animates the Image instance by translating it horizontally and vertically over 1 second (1000
milliseconds). The TranslateTo method simultaneously translates the image 100 pixels to the left, and 100 pixels
upwards. This is because the first and second arguments are both negative numbers. Providing positive numbers
would translate the image to the right, and down.
The following screenshots show the translation in progress on each platform:
NOTE
If an element is initially laid out off screen and then translated onto the screen, after translation the element's input layout
remains off screen and the user can't interact with it. Therefore, it's recommended that a view should be laid out in its final
position, and then any required translations performed.
Fading
The following code example demonstrates using the FadeTo method to animate the Opacity property of an
Image :
image.Opacity = 0;
await image.FadeTo (1, 4000);
This code animates the Image instance by fading it in over 4 seconds (4000 milliseconds). The FadeTo method
obtains the current Opacity property value for the start of the animation, and then fades in from that value to its
first argument (1).
The following screenshots show the fade in progress on each platform:
Compound Animations
A compound animation is a sequential combination of animations, and can be created with the await operator, as
demonstrated in the following code example:
In this example, the Image is translated over 6 seconds (6000 milliseconds). The translation of the Image uses five
animations, with the await operator indicating that each animation executes sequentially. Therefore, subsequent
animation methods execute after the previous method has completed.
Composite Animations
A composite animation is a combination of animations where two or more animations run simultaneously.
Composite animations can be created by mixing awaited and non-awaited animations, as demonstrated in the
following code example:
In this example, the Image is scaled and simultaneously rotated over 4 seconds (4000 milliseconds). The scaling of
the Image uses two sequential animations that occur at the same time as the rotation. The RotateTo method
executes without an await operator and returns immediately, with the first ScaleTo animation then beginning.
The await operator on the first ScaleTo method call delays the second ScaleTo method call until the first
ScaleTo method call has completed. At this point the RotateTo animation is half way completed and the Image
will be rotated 180 degrees. During the final 2 seconds (2000 milliseconds), the second ScaleTo animation and
the RotateTo animation both complete.
Running Multiple Asynchronous Methods Concurrently
The static Task.WhenAny and Task.WhenAll methods are used to run multiple asynchronous methods
concurrently, and therefore can be used to create composite animations. Both methods return a Task object and
accept a collection of methods that each return a Task object. The Task.WhenAny method completes when any
method in its collection completes execution, as demonstrated in the following code example:
await Task.WhenAny<bool>
(
image.RotateTo (360, 4000),
image.ScaleTo (2, 2000)
);
await image.ScaleTo (1, 2000);
In this example, the Task.WhenAny method call contains two tasks. The first task rotates the image over 4 seconds
(4000 milliseconds), and the second task scales the image over 2 seconds (2000 milliseconds). When the second
task completes, the Task.WhenAny method call completes. However, even though the RotateTo method is still
running, the second ScaleTo method can begin.
The Task.WhenAll method completes when all the methods in its collection have completed, as demonstrated in
the following code example:
// 10 minute animation
uint duration = 10 * 60 * 1000;
await Task.WhenAll (
image.RotateTo (307 * 360, duration),
image.RotateXTo (251 * 360, duration),
image.RotateYTo (199 * 360, duration)
);
In this example, the Task.WhenAll method call contains three tasks, each of which executes over 10 minutes. Each
Task makes a different number of 360 degree rotations – 307 rotations for RotateTo , 251 rotations for
RotateXTo , and 199 rotations for RotateYTo . These values are prime numbers, therefore ensuring that the
rotations aren't synchronized and hence won't result in repetitive patterns.
The following screenshots show the multiple rotations in progress on each platform:
Canceling Animations
An application can cancel one or more animations with a call to the static ViewExtensions.CancelAnimations
method, as demonstrated in the following code example:
ViewExtensions.CancelAnimations (image);
This will immediately cancel all animations that are currently running on the Image instance.
Summary
This article demonstrated creating and canceling animations using the ViewExtensions class. This class provides
extension methods that can be used to construct simple animations that rotate, scale, translate, and fade
VisualElement instances.
Related Links
Async Support Overview
Basic Animation (sample)
ViewExtensions
Easing Functions in Xamarin.Forms
12/7/2018 • 3 minutes to read • Edit Online
By specifying an easing function for an animation, the animation velocity becomes non-linear and produces the
effect provided by the easing function. Omitting an easing function when creating an animation causes the
animation to use the default Linear easing function, which produces a linear velocity.
For more information about using the animation extension methods in the ViewExtensions class, see Simple
Animations. Easing functions can also be consumed by the Animation class. For more information, see Custom
Animations.
Custom Easing Functions
There are three main approaches to creating a custom easing function:
1. Create a method that takes a double argument, and returns a double result.
2. Create a Func<double, double> .
3. Specify the easing function as the argument to the Easing constructor.
In all three cases, the custom easing function should return 0 for an argument of 0, and 1 for an argument of 1.
However, any value can be returned between the argument values of 0 and 1. Each approach will now be
discussed in turn.
Custom Easing Method
A custom easing function can be defined as a method that takes a double argument, and returns a double result,
as demonstrated in the following code example:
The CustomEase method truncates the incoming value to the values 0, 0.2, 0.4, 0.6, 0.8, and 1. Therefore, the Image
instance is translated in discrete jumps, rather than smoothly.
Custom Easing Func
A custom easing function can also be defined as a Func<double, double> , as demonstrated in the following code
example:
The CustomEase Func represents an easing function that starts off fast, slows down and reverses course, and then
reverses course again to accelerate quickly towards the end. Therefore, while the overall movement of the Image
instance is downwards, it also temporarily reverses course halfway through the animation.
Custom Easing Constructor
A custom easing function can also be defined as the argument to the Easing constructor, as demonstrated in the
following code example:
await image.TranslateTo (0, 200, 2000, new Easing (t => 1 - Math.Cos (10 * Math.PI * t) * Math.Exp (-5 * t)));
The custom easing function is specified as a lambda function argument to the Easing constructor, and uses the
Math.Cos method to create a slow drop effect that's dampened by the Math.Exp method. Therefore, the Image
instance is translated so that it appears to drop to its final resting place.
Summary
This article demonstrated how to consume the pre-defined easing functions, and how to create custom easing
functions. Xamarin.Forms includes an Easing class that allows you to specify a transfer function that controls how
animations speed up or slow down as they're running.
Related Links
Async Support Overview
Easing Functions (sample)
Easing
ViewExtensions
Custom Animations in Xamarin.Forms
12/7/2018 • 10 minutes to read • Edit Online
Creating an Animation
When creating an Animation object, typically, a minimum of three parameters are required, as demonstrated in
the following code example:
This code defines an animation of the Scale property of an Image instance from a value of 1 to a value of 2. The
animated value, which is derived by Xamarin.Forms, is passed to the callback specified as the first argument,
where it's used to change the value of the Scale property.
The animation is started with a call to the Commit method, as demonstrated in the following code example:
animation.Commit (this, "SimpleAnimation", 16, 2000, Easing.Linear, (v, c) => image.Scale = 1, () => true);
Note that the Commit method does not return a Task object. Instead, notifications are provided through callback
methods.
The following arguments are specified in the Commit method:
The first argument (owner) identifies the owner of the animation. This can be the visual element on which the
animation is applied, or another visual element, such as the page.
The second argument (name) identifies the animation with a name. The name is combined with the owner to
uniquely identify the animation. This unique identification can then be used to determine whether the
animation is running ( AnimationIsRunning ), or to cancel it ( AbortAnimation ).
The third argument (rate) indicates the number of milliseconds between each call to the callback method
defined in the Animation constructor
The fourth argument ( length) indicates the duration of the animation, in milliseconds.
The fifth argument (easing) defines the easing function to be used in the animation. Alternatively, the easing
function can be specified as an argument to the Animation constructor. For more information about easing
functions, see Easing Functions.
The sixth argument (finished) is a callback that will be executed when the animation has completed. This
callback takes two arguments, with the first argument indicating a final value, and the second argument being a
bool that's set to true if the animation was canceled. Alternatively, the finished callback can be specified as
an argument to the Animation constructor. However, with a single animation, if finished callbacks are specified
in both the Animation constructor and the Commit method, only the callback specified in the Commit method
will be executed.
The seventh argument (repeat) is a callback that allows the animation to be repeated. It's called at the end of
the animation, and returning true indicates that the animation should be repeated.
The overall effect is to create an animation that increases the Scale property of an Image from 1 to 2, over 2
seconds (2000 milliseconds), using the Linear easing function. Each time the animation completes, its Scale
property is reset to 1 and the animation repeats.
NOTE
Concurrent animations, that run independently of each other can be constructed by creating an Animation object for each
animation, and then calling the Commit method on each animation.
Child Animations
The Animation class also supports child animations, which involves creating an Animation object to which other
Animation objects are added. This enables a series of animations to be run and synchronized. The following code
example demonstrates creating and running child animations:
parentAnimation.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true,
false));
Alternatively, the code example can be written more concisely, as demonstrated in the following code example:
new Animation {
{ 0, 0.5, new Animation (v => image.Scale = v, 1, 2) },
{ 0, 1, new Animation (v => image.Rotation = v, 0, 360) },
{ 0.5, 1, new Animation (v => image.Scale = v, 2, 1) }
}.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));
In both code examples, a parent Animation object is created, to which additional Animation objects are then
added. The first two arguments to the Add method specify when to begin and finish the child animation. The
argument values must be between 0 and 1, and represent the relative period within the parent animation that the
specified child animation will be active. Therefore, in this example the scaleUpAnimation will be active for the first
half of the animation, the scaleDownAnimation will be active for the second half of the animation, and the
rotateAnimation will be active for the entire duration.
The overall effect is that the animation occurs over 4 seconds (4000 milliseconds). The scaleUpAnimation animates
the Scale property from 1 to 2, over 2 seconds. The scaleDownAnimation then animates the Scale property from
2 to 1, over 2 seconds. While both scale animations are occurring, the rotateAnimation animates the Rotation
property from 0 to 360, over 4 seconds. Note that the scaling animations also use easing functions. The SpringIn
easing function causes the Image to initially shrink before getting larger, and the SpringOut easing function
causes the Image to become smaller than its actual size towards the end of the complete animation.
There are a number of differences between an Animation object that uses child animations, and one that doesn't:
When using child animations, the finished callback on a child animation indicates when the child has
completed, and the finished callback passed to the Commit method indicates when the entire animation has
completed.
When using child animations, returning true from the repeat callback on the Commit method will not cause
the animation to repeat, but the animation will continue to run without new values.
When including an easing function in the Commit method, and the easing function returns a value greater than
1, the animation will be terminated. If the easing function returns a value less than 0, the value is clamped to 0.
To use an easing function that returns a value less than 0 or greater than 1, it must specified in one of the child
animations, rather than in the Commit method.
The Animation class also includes WithConcurrent methods that can be used to add child animations to a parent
Animation object. However, their begin and finish argument values aren't restricted to 0 to 1, but only that part of
the child animation that corresponds to a range of 0 to 1 will be active. For example, if a WithConcurrent method
call defines a child animation that targets a Scale property from 1 to 6, but with begin and finish values of -2 and
3, the begin value of -2 corresponds to a Scale value of 1, and the finish value of 3 corresponds to a Scale value
of 6. Because values outside the range of 0 and 1 play no part in an animation, the Scale property will only be
animated from 3 to 6.
Canceling an Animation
An application can cancel an animation with a call to the AbortAnimation extension method, as demonstrated in
the following code example:
this.AbortAnimation ("SimpleAnimation");
Note that animations are uniquely identified by a combination of the animation owner, and the animation name.
Therefore, the owner and name specified when running the animation must be specified to cancel the animation.
Therefore, the code example will immediately cancel the animation named SimpleAnimation that's owned by the
page.
The resulting animation provides the appearance of advancing the page background through the colors of the
rainbow.
For more examples of creating complex animations, including a Bezier curve animation, see Chapter 22 of
Creating Mobile Apps with Xamarin.Forms.
Creating a Custom Animation Extension Method
The extension methods in the ViewExtensions class animate a property from its current value to a specified value.
This makes it difficult to create, for example, a ColorTo animation method that can be used to animate a color
from one value to another, because:
The only Color property defined by the VisualElement class is BackgroundColor , which isn't always the
desired Color property to animate.
Often the current value of a Color property is Color.Default , which isn't a real color, and which can't be used
in interpolation calculations.
The solution to this problem is to not have the ColorTo method target a particular Color property. Instead, it can
be written with a callback method that passes the interpolated Color value back to the caller. In addition, the
method will take start and end Color arguments.
The ColorTo method can be implemented as an extension method that uses the Animate method in the
AnimationExtensions class to provide its functionality. This is because the Animate method can be used to target
properties that aren't of type double , as demonstrated in the following code example:
The Animate method requires a transform argument, which is a callback method. The input to this callback is
always a double ranging from 0 to 1. Therefore, the ColorTo method defines its own transform Func that
accepts a double ranging from 0 to 1, and that returns a Color value corresponding to that value. The Color
value is calculated by interpolating the R , G , B , and A values of the two supplied Color arguments. The
Color value is then passed to the callback method for application to a particular property.
This approach allows the ColorTo method to animate any Color property, as demonstrated in the following code
example:
await Task.WhenAll(
label.ColorTo(Color.Red, Color.Blue, c => label.TextColor = c, 5000),
label.ColorTo(Color.Blue, Color.Red, c => label.BackgroundColor = c, 5000));
await this.ColorTo(Color.FromRgb(0, 0, 0), Color.FromRgb(255, 255, 255), c => BackgroundColor = c, 5000);
await boxView.ColorTo(Color.Blue, Color.Red, c => boxView.Color = c, 4000);
In this code example, the ColorTo method animates the TextColor and BackgroundColor properties of a Label ,
the BackgroundColor property of a page, and the Color property of a BoxView .
Summary
This article demonstrated how to use the Animation class to create and cancel animations, synchronize multiple
animations, and create custom animations that animate properties that aren't animated by the existing animation
methods. The Animation class is the building block of all Xamarin.Forms animations.
Related Links
Custom Animations (sample)
Animation
AnimationExtensions
Xamarin.Forms BoxView
12/7/2018 • 18 minutes to read • Edit Online
The Color property is of type Color ; the property can be set to any Color value, including the 141 static read-
only fields of named colors ranging alphabetically from AliceBlue to YellowGreen .
The CornerRadius property is of type CornerRadius ; the property can be set to a single double uniform corner
radius value, or a CornerRadius structure defined by four double values that are applied to the top left, top right,
bottom left, and bottom right of the BoxView .
The WidthRequest and HeightRequest properties only play a role if the BoxView is unconstrained in layout. This is
the case when the layout container needs to know the child's size, for example, when the BoxView is a child of an
auto-sized cell in the Grid layout. A BoxView is also unconstrained when its HorizontalOptions and
VerticalOptions properties are set to values other than LayoutOptions.Fill . If the BoxView is unconstrained, but
the WidthRequest and HeightRequest properties are not set, then the width or height are set to default values of 40
units, or about 1/4 inch on mobile devices.
The WidthRequest and HeightRequest properties are ignored if the BoxView is constrained in layout, in which case
the layout container imposes its own size on the BoxView .
A BoxView can be constrained in one dimension and unconstrained in the other. For example, if the BoxView is a
child of a vertical StackLayout , the vertical dimension of the BoxView is unconstrained and its horizontal
dimension is generally constrained. But there are exceptions for that horizontal dimension: If the BoxView has its
HorizontalOptions property set to something other than LayoutOptions.Fill , then the horizontal dimension is
also unconstrained. It's also possible for the StackLayout itself to have an unconstrained horizontal dimension, in
which case the BoxView will also be horizontally unconstrained.
The BasicBoxView sample displays a one-inch-square unconstrained BoxView in the center of its page:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BasicBoxView"
x:Class="BasicBoxView.MainPage">
<BoxView Color="CornflowerBlue"
CornerRadius="10"
WidthRequest="160"
HeightRequest="160"
VerticalOptions="Center"
HorizontalOptions="Center" />
</ContentPage>
If the VerticalOptions and HorizontalOptions properties are removed from the BoxView tag or are set to Fill ,
then the BoxView becomes constrained by the size of the page, and expands to fill the page.
A BoxView can also be a child of an AbsoluteLayout . In that case, both the location and size of the BoxView are set
using the LayoutBounds attached bindable property. The AbsoluteLayout is discussed in the article
AbsoluteLayout.
You'll see examples of all these cases in the sample programs that follow.
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="BoxView">
<Setter Property="Color" Value="Black" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView Margin="15">
<StackLayout>
···
</StackLayout>
</ScrollView>
</ContentPage>
All of the markup that follows are children of the StackLayout . This markup consists of several types of decorative
BoxView elements used with the Label element:
The stylish header at the top of the page is achieved with an AbsoluteLayout whose children are four BoxView
elements and a Label , all of which are assigned specific locations and sizes:
<AbsoluteLayout>
<BoxView AbsoluteLayout.LayoutBounds="0, 10, 200, 5" />
<BoxView AbsoluteLayout.LayoutBounds="0, 20, 200, 5" />
<BoxView AbsoluteLayout.LayoutBounds="10, 0, 5, 65" />
<BoxView AbsoluteLayout.LayoutBounds="20, 0, 5, 65" />
<Label Text="Stylish Header"
FontSize="24"
AbsoluteLayout.LayoutBounds="30, 25, AutoSize, AutoSize"/>
</AbsoluteLayout>
In the XAML file, the AbsoluteLayout is followed by a Label with formatted text that describes the
AbsoluteLayout .
You can underline a text string by enclosing both the Label and BoxView in a StackLayout that has its
HorizontalOptions value set to something other than Fill . The width of the StackLayout is then governed by the
width of the Label , which then imposes that width on the BoxView . The BoxView is assigned only an explicit
height:
<StackLayout HorizontalOptions="Center">
<Label Text="Underlined Text"
FontSize="24" />
<BoxView HeightRequest="2" />
</StackLayout>
You can't use this technique to underline individual words within longer text strings or a paragraph.
It's also possible to use a BoxView to resemble an HTML hr (horizontal rule) element. Simply let the width of the
BoxView be determined by its parent container, which in this case is the StackLayout :
Finally, you can draw a vertical line on one side of a paragraph of text by enclosing both the BoxView and the
Label in a horizontal StackLayout . In this case, the height of the BoxView is the same as the height of
StackLayout , which is governed by the height of the Label :
<StackLayout Orientation="Horizontal">
<BoxView WidthRequest="4"
Margin="0, 0, 10, 0" />
<Label>
···
</Label>
</StackLayout>
// Static members.
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();
The program visuals are described in the XAML file. The ItemsSource property of the ListView is set to the static
NamedColor.All property, which means that the ListView displays all the individual NamedColor objects:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ListViewColors"
x:Class="ListViewColors.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="10, 20, 10, 0" />
<On Platform="Android, UWP" Value="10, 0" />
</OnPlatform>
</ContentPage.Padding>
<ListView SeparatorVisibility="None"
ItemsSource="{x:Static local:NamedColor.All}">
<ListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32">
<On Platform="iOS, Android" Value="80" />
<On Platform="UWP" Value="90" />
</OnPlatform>
</ListView.RowHeight>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="5">
<Frame OutlineColor="Accent"
Padding="10">
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
WidthRequest="50"
HeightRequest="50" />
<StackLayout>
<Label Text="{Binding FriendlyName}"
FontSize="22"
VerticalOptions="StartAndExpand" />
<Label Text="{Binding RgbDisplay, StringFormat='RGB = {0}'}"
FontSize="16"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</StackLayout>
</Frame>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
The NamedColor objects are formatted by the ViewCell object that is set as the data template of the ListView .
This template includes a BoxView whose Color property is bound to the Color property of the NamedColor
object.
public LifeCell()
{
BackgroundColor = Color.White;
LifeCell adds three more properties to BoxView : the Col and Row properties store the position of the cell
within the grid, and the IsAlive property indicates its state. The IsAlive property also sets the Color property
of the BoxView to black if the cell is alive, and white if the cell is not alive.
LifeCell also installs a TapGestureRecognizer to allow the user to toggle the state of cells by tapping them. The
class translates the Tapped event from the gesture recognizer into its own Tapped event.
The GameOfLife program also includes a LifeGrid class that encapsulates much of the logic of the game, and a
MainPage class that handles the program's visuals. These include an overlay that describes the rules of the game.
Here is the program in action showing a couple hundred LifeCell objects on the page:
Creating a Digital Clock
The DotMatrixClock program creates 210 BoxView elements to simulate the dots of an old-fashioned 5-by-7
dot-matrix display. You can read the time in either portrait or landscape mode, but it's larger in landscape:
The XAML file does little more than instantiate the AbsoluteLayout used for the clock:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DotMatrixClock"
x:Class="DotMatrixClock.MainPage"
Padding="10"
SizeChanged="OnPageSizeChanged">
<AbsoluteLayout x:Name="absoluteLayout"
VerticalOptions="Center" />
</ContentPage>
Everything else occurs in the code-behind file. The dot-matrix display logic is greatly simplified by the definition of
several arrays that describe the dots corresponding to each of the 10 digits and a colon:
public partial class MainPage : ContentPage
{
// Total dots horizontally and vertically.
const int horzDots = 41;
const int vertDots = 7;
···
}
These fields conclude with a three-dimensional array of BoxView elements for storing the dot patterns for the six
digits.
The constructor creates all the BoxView elements for the digits and colon, and also initializes the Color property
of the BoxView elements for the colon:
···
public MainPage()
{
InitializeComponent();
···
This program uses the relative positioning and sizing feature of AbsoluteLayout . The width and height of each
BoxView are set to fractional values, specifically 85% of 1 divided by the number of horizontal and vertical dots.
The positions are also set to fractional values.
Because all the positions and sizes are relative to the total size of the AbsoluteLayout , the SizeChanged handler for
the page need only set a HeightRequest of the AbsoluteLayout :
···
···
The width of the AbsoluteLayout is automatically set because it stretches to the full width of the page.
The final code in the MainPage class processes the timer callback and colors the dots of each digit. The definition of
the multi-dimensional arrays at the beginning of the code-behind file helps make this logic the simplest part of the
program:
public partial class MainPage : ContentPage
{
···
bool OnTimer()
{
DateTime dateTime = DateTime.Now;
All the visuals in the BoxViewClock program are children of an AbsoluteLayout . These elements are sized using
the LayoutBounds attached property, and rotated using the Rotation property.
The three BoxView elements for the hands of the clock are instantiated in the XAML file, but not positioned or
sized:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BoxViewClock"
x:Class="BoxViewClock.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
<AbsoluteLayout x:Name="absoluteLayout"
SizeChanged="OnAbsoluteLayoutSizeChanged">
<BoxView x:Name="hourHand"
Color="Black" />
<BoxView x:Name="minuteHand"
Color="Black" />
<BoxView x:Name="secondHand"
Color="Black" />
</AbsoluteLayout>
</ContentPage>
The constructor of the code-behind file instantiates the 60 BoxView elements for the tick marks around the
circumference of the clock:
···
public MainPage()
{
InitializeComponent();
···
The sizing and positioning of all the BoxView elements occurs in the SizeChanged handler for the AbsoluteLayout .
A little structure internal to the class called HandParams describes the size of each of the three hands relative to the
total size of the clock:
public partial class MainPage : ContentPage
{
// Structure for storing information about the three hands.
struct HandParams
{
public HandParams(double width, double height, double offset) : this()
{
Width = width;
Height = height;
Offset = offset;
}
···
The SizeChanged handler determines the center and radius of the AbsoluteLayout , and then sizes and positions the
60 BoxView elements used as tick marks. The for loop concludes by setting the Rotation property of each of
these BoxView elements. At the end of the SizeChanged handler, the LayoutHand method is called to size and
position the three hands of the clock:
public partial class MainPage : ContentPage
{
···
AbsoluteLayout.SetLayoutBounds(boxView,
new Rectangle(center.X - 0.5 * width,
center.Y - offset * height,
width, height));
···
The LayoutHand method sizes and positions each hand to point straight up to the 12:00 position. At the end of the
method, the AnchorY property is set to a position corresponding to the center of the clock. This indicates the
center of rotation.
The hands are rotated in the timer callback function:
public partial class MainPage : ContentPage
{
···
bool OnTimerTick()
{
// Set rotation angles for hour and minute hands.
DateTime dateTime = DateTime.Now;
hourHand.Rotation = 30 * (dateTime.Hour % 12) + 0.5 * dateTime.Minute;
minuteHand.Rotation = 6 * dateTime.Minute + 0.1 * dateTime.Second;
if (t < 0.5)
{
t = 0.5 * Easing.SpringIn.Ease(t / 0.5);
}
else
{
t = 0.5 * (1 + Easing.SpringOut.Ease((t - 0.5) / 0.5));
}
The second hand is treated a little differently: An animation easing function is applied to make the movement seem
mechanical rather than smooth. On each tick, the second hand pulls back a little and then overshoots its
destination. This little bit of code adds a lot to the realism of the movement.
Conclusion
The BoxView might seem simple at first, but as you've seen, it can be quite versatile, and can almost reproduce
visuals that are normally possible only with vector graphics. For more sophisticated graphics, consult Using
SkiaSharp in Xamarin.Forms.
Related Links
Basic BoxView (sample)
Text Decoration (sample)
Color ListBox (sample)
Game of Life (sample)
Dot-Matrix Clock (sample)
BoxView Clock (sample)
BoxView
Xamarin.Forms Button
3/8/2019 • 19 minutes to read • Edit Online
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.BasicButtonClickPage"
Title="Basic Button Click">
<StackLayout>
<Label x:Name="label"
Text="Click the Button below"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
The Button tends to occupy all the space that's allowed for it. For example, if you don't set the HorizontalOptions
property of Button to something other than Fill , the Button will occupy the full width of its parent.
By default, the Button is rectangular, but you can give it rounded corners by using the CornerRadius property, as
described below in the section Button appearance.
The Text property specifies the text that appears in the Button . The Clicked event is set to an event handler
named OnButtonClicked . This handler is located in the code-behind file, BasicButtonClickPage.xaml.cs:
public partial class BasicButtonClickPage : ContentPage
{
public BasicButtonClickPage ()
{
InitializeComponent ();
}
When the Button is tapped, the OnButtonClicked method executes. The sender argument is the Button object
responsible for this event. You can use this to access the Button object, or to distinguish between multiple Button
objects sharing the same Clicked event.
This particular Clicked handler calls an animation function that rotates the Label 360 degrees in 1000
milliseconds. Here's the program running on iOS and Android devices, and as a Universal Windows Platform
(UWP ) application on the Windows 10 desktop:
Notice that the OnButtonClicked method includes the async modifier because await is used within the event
handler. A Clicked event handler requires the async modifier only if the body of the handler uses await .
Each platform renders the Button in its own specific manner. In the Button appearance section, you'll see how
to set colors and make the Button border visible for more customized appearances. Button implements the
IFontElement interface, so it includes FontFamily , FontSize , and FontAttributes properties.
Everything is done in the class's constructor. Because the Clicked handler is only one statement long, it can be
attached to the event very simply:
Of course, you can also define the event handler as a separate method (just like the OnButtonClick method in
Basic Button Click) and attach that method to the event:
button.Clicked += OnButtonClicked;
This approach is particularly suitable in connection with data-binding, and particularly when implementing the
Model-View -ViewModel (MVVM ) architecture. These topics are discussed in the articles Data Binding, From Data
Bindings to MVVM, and MVVM.
In an MVVM application, the ViewModel defines properties of type ICommand that are then connected to the
XAML Button elements with data bindings. Xamarin.Forms also defines Command and Command<T> classes that
implement the ICommand interface and assist the ViewModel in defining properties of type ICommand .
Commanding is described in greater detail in the article The Command Interface but the Basic Button
Command page in the ButtonDemos sample shows the basic approach.
The CommandDemoViewModel class is a very simple ViewModel that defines a property of type double named
Number , and two properties of type ICommand named MultiplyBy2Command and DivideBy2Command :
public CommandDemoViewModel()
{
MultiplyBy2Command = new Command(() => Number *= 2);
The two properties are initialized in the class's constructor with two objects of type Command . The
ICommand
Command constructors include a little function (called the execute constructor argument) that either doubles or
halves the Number property.
The BasicButtonCommand.xaml file sets its BindingContext to an instance of CommandDemoViewModel . The
Label element and two Button elements contain bindings to the three properties in CommandDemoViewModel :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonDemos"
x:Class="ButtonDemos.BasicButtonCommandPage"
Title="Basic Button Command">
<ContentPage.BindingContext>
<local:CommandDemoViewModel />
</ContentPage.BindingContext>
<StackLayout>
<Label Text="{Binding Number, StringFormat='Value is now {0}'}"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
As the two Button elements are tapped, the commands are executed, and the number changes value:
The advantage of this approach over Clicked handlers is that all the logic involving the functionality of this page
is located in the ViewModel rather than the code-behind file, achieving a better separation of the user interface
from the business logic.
It is also possible for the Command objects to control the enabling and disabling of the Button elements. For
example, suppose you want to limit the range of number values between 210 and 2–10. You can add another
function to the constructor (called the canExecute argument) that returns true if the Button should be enabled.
Here's the modification to the CommandDemoViewModel constructor:
class CommandDemoViewModel : INotifyPropertyChanged
{
···
public CommandDemoViewModel()
{
MultiplyBy2Command = new Command(
execute: () =>
{
Number *= 2;
((Command)MultiplyBy2Command).ChangeCanExecute();
((Command)DivideBy2Command).ChangeCanExecute();
},
canExecute: () => Number < Math.Pow(2, 10));
The calls to the ChangeCanExecute method of Command are necessary so that the Command method can call the
canExecute method and determine whether the Button should be disabled or not. With this code change, as the
number reaches the limit, the Button is disabled:
It is possible for two or more Button elements to be bound to the same ICommand property. The Button
elements can be distinguished using the CommandParameter property of Button . In this case, you'll want to use the
generic Command<T> class. The CommandParameter object is then passed as an argument to the execute and
canExecute methods. This technique is shown in detail in the Basic Commanding section of the Command
Interface article.
The ButtonDemos sample also uses this technique in its MainPage class. The MainPage.xaml file contains a
Button for each page of the sample:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonDemos"
x:Class="ButtonDemos.MainPage"
Title="Button Demos">
<ScrollView>
<FlexLayout Direction="Column"
JustifyContent="SpaceEvenly"
AlignItems="Center">
</FlexLayout>
</ScrollView>
</ContentPage>
Each Button has its Command property bound to a property named NavigateCommand , and the CommandParameter is
set to a Type object corresponding to one of the page classes in the project.
That NavigateCommand property is of type ICommand and is defined in the code-behind file:
BindingContext = this;
}
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.PressAndReleaseButtonPage"
Title="Press and Release Button">
<StackLayout>
<Label x:Name="label"
Text="Press and hold the Button below"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
The code-behind file animates the Label when a Pressed event occurs, but suspends the rotation when a
Released event occurs:
public partial class PressAndReleaseButtonPage : ContentPage
{
bool animationInProgress = false;
Stopwatch stopwatch = new Stopwatch();
public PressAndReleaseButtonPage ()
{
InitializeComponent ();
}
Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>
{
label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);
return animationInProgress;
});
}
The result is that the Label only rotates while a finger is in contact with the Button , and stops when the finger is
released:
This kind of behavior has applications for games: A finger held on a Button might make an on screen object
move in a particular direction.
Button appearance
The Button inherits or defines several properties that affect its appearance:
TextColor is the color of the Button text
BackgroundColor is the color of the background to that text
BorderColor is the color of an area surrounding the Button
FontFamily is the font family used for the text
FontSize is the size of the text
FontAttributes indicates if the text is italic or bold
BorderWidth is the width of the border
CornerRadius is the corner radius of the Button
NOTE
The Button class also has Margin and Padding properties that control the layout behavior of the Button . For more
information, see Margin and Padding.
The effects of six of these properties (excluding FontFamily and FontAttributes ) are demonstrated in the Button
Appearance page. Another property, Image , is discussed in the section Using bitmaps with button.
All of the views and data bindings in the Button Appearance page are defined in the XAML file:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonDemos"
x:Class="ButtonDemos.ButtonAppearancePage"
Title="Button Appearance">
<StackLayout>
<Button x:Name="button"
Text="Button"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
TextColor="{Binding Source={x:Reference textColorPicker},
Path=SelectedItem.Color}"
BackgroundColor="{Binding Source={x:Reference backgroundColorPicker},
Path=SelectedItem.Color}"
BorderColor="{Binding Source={x:Reference borderColorPicker},
Path=SelectedItem.Color}" />
<Slider x:Name="fontSizeSlider"
Maximum="48"
Minimum="1"
Value="{Binding FontSize}" />
<Slider x:Name="borderWidthSlider"
Minimum="-1"
Maximum="12"
Value="{Binding BorderWidth}" />
<Slider x:Name="cornerRadiusSlider"
Minimum="-1"
Maximum="24"
Value="{Binding CornerRadius}" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="Label">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</Grid.Resources>
<Picker x:Name="textColorPicker"
ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
ItemDisplayBinding="{Binding FriendlyName}"
SelectedIndex="0"
Grid.Row="0" Grid.Column="1" />
<Picker x:Name="backgroundColorPicker"
ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
ItemDisplayBinding="{Binding FriendlyName}"
SelectedIndex="0"
Grid.Row="1" Grid.Column="1" />
<Picker x:Name="borderColorPicker"
ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
ItemDisplayBinding="{Binding FriendlyName}"
SelectedIndex="0"
Grid.Row="2" Grid.Column="1" />
</Grid>
</StackLayout>
</StackLayout>
</ContentPage>
The Button at the top of the page has its three Color properties bound to Picker elements at the bottom of the
page. The items in the Picker elements are colors from the NamedColor class included in the project. Three
Slider elements contain two-way bindings to the FontSize , BorderWidth , and CornerRadius properties of the
Button .
This program allows you to experiment with combinations of all these properties:
To see the Button border, you'll need to set a BorderColor to something other than Default , and the
BorderWidth to a positive value.
On iOS, you'll notice that large border widths intrude into the interior of the Button and interfere with the display
of text. If you choose to use a border with an iOS Button , you'll probably want to begin and end the Text
property with spaces to retain its visibility.
On UWP, selecting a CornerRadius that exceeds half the height of the Button raises an exception.
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
The Pressed VisualState specifies that when the Button is pressed, its Scale property will be changed from its
default value of 1 to 0.8. The Normal VisualState specifies that when the Button is in a normal state, its Scale
property will be set to 1. Therefore, the overall effect is that when the Button is pressed, it's rescaled to be slightly
smaller, and when the Button is released, it's rescaled to its default size.
For more information about visual states, see The Xamarin.Forms Visual State Manager.
public ToggleButton()
{
Clicked += (sender, args) => IsToggled ^= true;
}
// Fire event
toggleButton.Toggled?.Invoke(toggleButton, new ToggledEventArgs(isToggled));
The ToggleButton constructor attaches a handler to the Clicked event so that it can change the value of the
IsToggled property. The OnIsToggledChanged method fires the Toggled event.
The last line of the OnIsToggledChanged method calls the static VisualStateManager.GoToState method with the two
text strings "ToggledOn" and "ToggledOff". You can read about this method and how your application can respond
to visual states in the article The Xamarin.Forms Visual State Manager.
Because ToggleButton makes the call to VisualStateManager.GoToState , the class itself doesn't need to include any
additional facilities to change the button's appearance based on its IsToggled state. That is the responsibility of
the XAML that hosts the ToggleButton .
The Toggle Button Demo page contains two instances of ToggleButton , including Visual State Manager markup
that sets the Text , BackgroundColor , and TextColor of the button based on the visual state:
<?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:ButtonDemos"
x:Class="ButtonDemos.ToggleButtonDemoPage"
Title="Toggle Button Demo">
<ContentPage.Resources>
<Style TargetType="local:ToggleButton">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="HorizontalOptions" Value="Center" />
</Style>
</ContentPage.Resources>
<VisualState Name="ToggledOn">
<VisualState.Setters>
<Setter Property="Text" Value=" Italic On " />
<Setter Property="BackgroundColor" Value="#404040" />
<Setter Property="TextColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:ToggleButton>
<local:ToggleButton Toggled="OnBoldButtonToggled">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ToggleStates">
<VisualState Name="ToggledOff">
<VisualState.Setters>
<Setter Property="Text" Value="Bold Off" />
<Setter Property="BackgroundColor" Value="#C0C0C0" />
<Setter Property="TextColor" Value="Black" />
</VisualState.Setters>
</VisualState>
<VisualState Name="ToggledOn">
<VisualState.Setters>
<Setter Property="Text" Value=" Bold On " />
<Setter Property="BackgroundColor" Value="#404040" />
<Setter Property="TextColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:ToggleButton>
<Label x:Name="label"
Text="Just a little passage of some sample text that can be formatted in italic or boldface by
toggling the two buttons."
FontSize="Large"
HorizontalTextAlignment="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
The Toggled event handlers are in the code-behind file. They are responsible for setting the FontAttributes
property of the Label based on the state of the buttons:
In code, you can create a Button and set the ContentLayout property like this:
The Image Button Demo page uses OnPlatform to specify different filenames for the iOS, Android, and UWP
bitmap files. If you want to use the same filename for each platform and avoid the use of OnPlatform , you'll need
to store the UWP bitmaps in the root directory of the project.
The first Button on the Image Button Demo page sets the Image property but not the Text property:
<Button>
<Button.Image>
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Button.Image>
</Button>
If the UWP bitmaps are stored in the root directory of the project, this markup can be considerably simplified:
To avoid a lot of repetitious markup in the ImageButtonDemo.xaml file, an implicit Style is also defined to set
the Image property. This Style is automatically applied to five other Button elements. Here's the complete
XAML file:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.ImageButtonDemoPage">
<FlexLayout Direction="Column"
JustifyContent="SpaceEvenly"
AlignItems="Center">
<FlexLayout.Resources>
<Style TargetType="Button">
<Setter Property="Image">
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Setter>
</Style>
</FlexLayout.Resources>
<Button>
<Button.Image>
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Button.Image>
</Button>
The final four Button elements make use of the ContentLayout property to specify a position and spacing of the
text and bitmap:
You've now seen the various ways that you can handle Button events and change the Button appearance.
Related links
ButtonDemos sample
Button API
Xamarin.Forms CollectionView
3/21/2019 • 2 minutes to read • Edit Online
IMPORTANT
The CollectionView is currently a preview, and lacks some of its planned functionality. In addition, the API may change as
the implementation is completed.
CollectionView is a view for presenting lists of data using different layout specifications. It aims to provide a more
flexible, and performant alternative to ListView . While the CollectionView and ListView APIs are similar, there
are some notable differences:
CollectionView has a flexible layout model, which allows data to be presented vertically or horizontally, in a list
or a grid.
CollectionView has no concept of cells. Instead, a data template is used to define the appearance of each item
of data in the list.
CollectionView automatically utilizes the virtualization provided by the underlying native controls.
CollectionView reduces the API surface of ListView . Many properties and events from ListView are not
present in CollectionView .
CollectionView does not include built-in separators.
CollectionView is available in the Xamarin.Forms 4.0 pre-releases. However, it is currently experimental and can
only be used by adding the following line of code to your AppDelegate class on iOS, or to your MainActivity class
on Android, before calling Forms.Init :
Forms.SetFlags("CollectionView_Experimental");
NOTE
CollectionView is only available on iOS and Android.
IMPORTANT
The CollectionView is currently a preview, and lacks some of its planned functionality. In addition, the API may change as
the implementation is completed.
CollectionView defines the following properties that define the data to be displayed, and its appearance:
ItemsSource , of type IEnumerable , specifies the collection of items to be displayed, and has a default value of
null .
ItemTemplate , of type DataTemplate , specifies the template to apply to each item in the collection of items to be
displayed.
These properties are backed by BindableProperty objects, which means that the properties can be targets of data
bindings.
<CollectionView>
<CollectionView.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>
</CollectionView.ItemsSource>
</CollectionView>
NOTE
Note that the x:Array element requires a Type attribute indicating the type of the items in the array.
IMPORTANT
If the CollectionView is required to refresh as items are added, removed, or changed in the underlying collection, the
underlying collection should be an IEnumerable collection that sends property change notifications, such as
ObservableCollection .
By default, CollectionView displays items in a vertical list, as shown in the following screenshots:
For information on how to change the CollectionView layout, see Specify a Layout. For information on how to
define the appearance of each item in the CollectionView , see Define item appearance.
Data binding
CollectionView can be populated with data by using data binding to bind its ItemsSource property to an
IEnumerable collection. In XAML, this is achieved with the Binding markup extension:
In this example, the ItemsSource property data binds to the Monkeys property of the connected view model.
NOTE
Compiled bindings can be enabled to improve data binding performance in Xamarin.Forms applications. For more
information, see Compiled Bindings.
For more information about data binding, see Xamarin.Forms Data Binding.
Define item appearance
The appearance of each item in the CollectionView can be defined by setting the CollectionView.ItemTemplate
property to a DataTemplate :
Grid.SetRowSpan(image, 2);
grid.Children.Add(image);
grid.Children.Add(nameLabel, 1, 0);
grid.Children.Add(locationLabel, 1, 1);
return grid;
});
The elements specified in the DataTemplate define the appearance of each item in the list. In the example, layout
within the DataTemplate is managed by a Grid . The Grid contains an Image object, and two Label objects, that
all bind to properties of the Monkey class:
The following screenshots show the result of templating each item in the list:
For more information about data templates, see Xamarin.Forms Data Templates.
Related links
CollectionView (sample)
Xamarin.Forms Data Binding
Xamarin.Forms Data Templates
Specify Xamarin.Forms CollectionView Layout
3/21/2019 • 6 minutes to read • Edit Online
IMPORTANT
The CollectionView is currently a preview, and lacks some of its planned functionality. In addition, the API may change as
the implementation is completed.
These properties are backed by BindableProperty objects, which means that the properties can be targets of data
bindings.
By default, a CollectionView will display its items in a vertical list. However, any of the following layouts can be
used:
Vertical list – a single column list that grows vertically as new items are added.
Horizontal list – a single row list that grows horizontally as new items are added.
Vertical grid – a multi-column grid that grows vertically as new items are added.
Horizontal grid – a multi-row grid that grows horizontally as new items are added.
These layouts can be specified by setting the ItemsLayout property to class that derives from the ItemsLayout
class. This class defines the following properties:
, of type
Orientation ItemsLayoutOrientation , specifies the direction in which the CollectionView expands as
items are added.
SnapPointsAlignment , of type SnapPointsAlignment , specifies how snap points are aligned with items.
SnapPointsType , of type SnapPointsType , specifies the behavior of snap points when scrolling.
These properties are backed by BindableProperty objects, which means that the properties can be targets of data
bindings. For more information about snap points, see Snap points in the Scroll an Item into View guide.
The ItemsLayoutOrientation enumeration defines the following members:
Vertical indicates that the CollectionView will expand vertically as items are added.
Horizontal indicates that the CollectionView will expand horizontally as items are added.
The ListItemsLayoutclass inherits from the ItemsLayout class, and defines static VerticalList and
HorizontalList members. These members can be used to create vertical or horizontal lists, respectively.
Alternatively, a ListItemsLayout object can be created, specifying an ItemsLayoutOrientation enumeration
member as an argument.
The GridItemsLayout class inherits from the ItemsLayout class, and defines a Span property, of type int , that
represents the number of columns or rows to display in the grid. The default value of the Span property is 1, and
its value must always be greater than or equal to 1.
NOTE
CollectionView uses the native layout engines to perform layout.
Vertical list
By default, CollectionView will display its items in a vertical list layout. Therefore, it's not necessary to set the
ItemsLayout property to use this layout:
However, for completeness, a CollectionView can be set to display its items in a vertical list by setting its
ItemsLayout to the static ListItemsLayout.VerticalList member:
Alternatively, this can also be accomplished by setting the ItemsLayout property to an object of the
ListItemsLayout class, specifying the Vertical ItemsLayoutOrientation enumeration member as an argument:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<ListItemsLayout>
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
...
</CollectionView>
This results in a single column list, which grows vertically as new items are added:
Horizontal list
CollectionView can display its items in a horizontal list by setting its ItemsLayout property to the static
ListItemsLayout.HorizontalList member:
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="{x:Static ListItemsLayout.HorizontalList}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Alternatively, this can also be accomplished by setting the ItemsLayout property to a ListItemsLayout object,
specifying the Horizontal ItemsLayoutOrientation enumeration member as an argument:
This results in a single row list, which grows horizontally as new items are added:
Vertical grid
CollectionView can display its items in a vertical grid by setting its ItemsLayout property to a GridItemsLayout
object whose Orientation property is set to Vertical :
By default, a vertical GridItemsLayout will display items in a single column. However, this example sets the
GridItemsLayout.Span property to 2. This results in a two-column grid, which grows vertically as new items are
added:
Horizontal grid
CollectionView can display its items in a horizontal grid by setting its ItemsLayout property to a GridItemsLayout
object whose Orientation property is set to Horizontal :
By default, a horizontal GridItemsLayout will display items in a single row. However, this example sets the
GridItemsLayout.Span property to 4. This results in a four -row grid, which grows horizontally as new items are
added:
Right-to-left layout
CollectionView can layout its content in a right-to-left flow direction by setting its FlowDirection property to
RightToLeft . However, the FlowDirection property should ideally be set on a page or root layout, which causes
all the elements within the page, or root layout, to respond to the flow direction:
The default FlowDirectionfor an element with a parent is MatchParent . Therefore, the CollectionView inherits the
FlowDirection property value from the StackLayout , which in turn inherits the FlowDirection property value
from the ContentPage . This results in the right-to-left layout shown in the following screenshots:
For more information about flow direction, see Right-to-left localization.
Item sizing
By default, each item in a CollectionView is individually measured and sized, provided that the UI elements in the
DataTemplate don't specify fixed sizes. This behavior, which can be changed, is specified by the
CollectionView.ItemSizingStrategy property value. This property value can be set to one of the
ItemSizingStrategy enumeration members:
IMPORTANT
The MeasureFirstItem sizing strategy should be used in situations where the item size is intended to be uniform across all
items, and will result in increased performance.
<CollectionView ...
ItemSizingStrategy="MeasureFirstItem">
...
</CollectionView>
Related links
CollectionView (sample)
Right-to-left localization
Scroll an Item into View
Set CollectionView Selection Mode
3/21/2019 • 4 minutes to read • Edit Online
IMPORTANT
The CollectionView is currently a preview, and lacks some of its planned functionality. In addition, the API may change as
the implementation is completed.
All of these properties are backed by BindableProperty objects, which means that the properties can be targets of
data bindings.
By default, CollectionView selection is disabled. However, this behavior can be changed by setting the
SelectionMode property value to one of the SelectionMode enumeration members:
None – indicates that items cannot be selected. This is the default value.
Single – indicates that a single item can be selected, with the selected item being highlighted.
Multiple – indicates that multiple items can be selected, with the selected items being highlighted.
CollectionView defines a SelectionChanged event that is fired when the SelectedItem property changes, either
due to the user selecting an item from the list, or when an application sets the property. The
SelectionChangedEventArgs object that accompanies the SelectionChanged event has two properties, both of type
IReadOnlyList<object> :
PreviousSelection – the list of items that were selected, before the selection changed.
CurrentSelection – the list of items that are selected, after the selection change.
Single selection
When the SelectionMode property is set to Single , a single item in the CollectionView can be selected. When an
item is selected, the SelectedItem property will be set to the value of the selected item. When this property
changes, the SelectionChangedCommand is executed (with the value of the SelectionChangedCommandParameter being
passed to the ICommand ), and the SelectionChanged event fires.
The following XAML example shows a CollectionView that can respond to single item selection:
<CollectionView ItemsSource="{Binding Monkeys}"
SelectionMode="Single"
SelectionChanged="OnCollectionViewSelectionChanged">
...
</CollectionView>
In this code example, the OnCollectionViewSelectionChanged event handler is executed when the SelectionChanged
event fires, with the event handler retrieving the previously selected item, and the current selected item:
IMPORTANT
The SelectionChanged event can be fired by changes that occur as a result of changing the SelectionMode property.
Pre-selection
When the SelectionMode property is set to Single , a single item in the CollectionView can be pre-selected by
setting the SelectedItem property to the item. The following XAML example shows a CollectionView that pre-
selects a single item:
The SelectedItem property data binds to the SelectedMonkey property of the connected view model, which is of
type Monkey . A TwoWay binding is used so that if the user changes the selected item, the value of the
SelectedMonkey property will be set to the selected Monkey object. The SelectedMonkey property is defined in the
MonkeysViewModel class, and is set to the fourth item of the Monkeys collection:
Monkey selectedMonkey;
public Monkey SelectedMonkey
{
get
{
return selectedMonkey;
}
set
{
if (selectedMonkey != value)
{
selectedMonkey = value;
}
}
}
public MonkeysViewModel()
{
...
selectedMonkey = Monkeys.Skip(3).FirstOrDefault();
}
...
}
Therefore, when the CollectionView appears, the fourth item in the list is pre-selected:
IMPORTANT
The Style that contains the Selected VisualState must have a TargetType property value that's the type of the
root element of the DataTemplate , which is set as the ItemTemplate property value.
In this example, the Style.TargetType property value is set to Grid because the root element of the ItemTemplate
is a Grid . The Selected VisualState specifies that when an item in the CollectionView is selected, the
BackgroundColor of the item will be set to LightSkyBlue :
For more information about visual states, see Xamarin.Forms Visual State Manager.
Disable selection
CollectionView selection is disabled by default. However, if a CollectionView has selection enabled, it can be
disabled by setting the SelectionMode property to None :
<CollectionView ...
SelectionMode="None" />
The equivalent C# code is:
When the SelectionMode property is set to None , items in the CollectionView cannot be selected, the
SelectedItem property will remain null , and the SelectionChanged event will not be fired.
NOTE
When an item has been selected and the SelectionMode property is changed from Single to None , the SelectedItem
property will be set to null and the SelectionChanged event will be fired with an empty CurrentSelection property.
Related links
CollectionView (sample)
Xamarin.Forms Visual State Manager
Display an EmptyView when Data is Unavailable
3/21/2019 • 5 minutes to read • Edit Online
IMPORTANT
The CollectionView is currently a preview, and lacks some of its planned functionality. In addition, the API may change as
the implementation is completed.
CollectionView defines the following properties that can be used to provide user feedback when there's no data to
display:
EmptyView , of type object , the string, binding, or view that will be displayed when the ItemsSource property is
null , or when the collection specified by the ItemsSource property is null or empty. The default value is
null .
EmptyViewTemplate , of type DataTemplate , the template to use to format the specified EmptyView . The default
value is null .
These properties are backed by BindableProperty objects, which means that the properties can be targets of data
bindings.
The main usage scenarios for setting the EmptyView property are displaying user feedback when a filtering
operation on a CollectionView yields no data, and displaying user feedback while data is being retrieved from a
web service.
NOTE
The EmptyView property can be set to a view that includes interactive content if required.
For more information about data templates, see Xamarin.Forms Data Templates.
The result is that, because the data bound collection is null , the string set as the EmptyView property value is
displayed:
<StackLayout Margin="20">
<SearchBar x:Name="searchBar"
SearchCommand="{Binding FilterCommand}"
SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
Placeholder="Filter" />
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.EmptyView>
<StackLayout>
<Label Text="No results matched your filter."
Margin="10,25,10,10"
FontAttributes="Bold"
FontSize="18"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
<Label Text="Try a broader filter?"
FontAttributes="Italic"
FontSize="12"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
</StackLayout>
</CollectionView.EmptyView>
</CollectionView>
</StackLayout>
When the SearchBar executes the FilterCommand , the collection displayed by the CollectionView is filtered for the
search term stored in the SearchBar.Text property. If the filtering operation yields no data, the StackLayout set as
the EmptyView property value is displayed:
<StackLayout Margin="20">
<SearchBar x:Name="searchBar"
SearchCommand="{Binding FilterCommand}"
SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
Placeholder="Filter" />
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.EmptyView>
<views:FilterData Filter="{Binding Source={x:Reference searchBar}, Path=Text}" />
</CollectionView.EmptyView>
<CollectionView.EmptyViewTemplate>
<DataTemplate>
<Label Text="{Binding Filter, StringFormat='Your filter term of {0} did not match any
records.'}"
Margin="10,25,10,10"
FontAttributes="Bold"
FontSize="18"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
</DataTemplate>
</CollectionView.EmptyViewTemplate>
</CollectionView>
</StackLayout>
The equivalent C# code is:
The EmptyView property is set to a FilterData object, and the Filter property data binds to the SearchBar.Text
property. When the SearchBar executes the FilterCommand , the collection displayed by the CollectionView is
filtered for the search term stored in the Filter property. If the filtering operation yields no data, the Label
defined in the DataTemplate , that's set as the EmptyViewTemplate property value, is displayed:
NOTE
When displaying a templated custom type when data is unavailable, the EmptyViewTemplate property can be set to a view
that contains multiple child views.
<StackLayout Margin="20">
<SearchBar x:Name="searchBar"
SearchCommand="{Binding FilterCommand}"
SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
Placeholder="Filter" />
<StackLayout Orientation="Horizontal">
<Label Text="Toggle EmptyViews" />
<Switch Toggled="OnEmptyViewSwitchToggled" />
</StackLayout>
<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>
This XAML defines two ContentView objects in the page-level ResourceDictionary , with the Switch object
controlling which ContentView object will be set as the EmptyView property value. When the Switch is toggled,
the OnEmptyViewSwitchToggled event handler executes the ToggleEmptyView method:
The ToggleEmptyView method sets the EmptyView property of the collectionView object to one of the two
ContentView objects stored in the ResourceDictionary , based on the value of the Switch.IsToggled property.
When the SearchBar executes the FilterCommand , the collection displayed by the CollectionView is filtered for the
search term stored in the SearchBar.Text property. If the filtering operation yields no data, the ContentView object
set as the EmptyView property is displayed:
For more information about resource dictionaries, see Xamarin.Forms Resource Dictionaries.
Related links
CollectionView (sample)
Xamarin.Forms Data Templates
Xamarin.Forms Resource Dictionaries
Scroll an Item into View
3/21/2019 • 5 minutes to read • Edit Online
IMPORTANT
The CollectionView is currently a preview, and lacks some of its planned functionality. In addition, the API may change as
the implementation is completed.
CollectionView defines two ScrollTo methods, that scroll items into view. One of the overloads scrolls the item
at the specified index into view, while the other scrolls the specified item into view. Both overloads have additional
arguments that can be specified to indicate the exact position of the item after the scroll has completed, and
whether to animate the scroll.
CollectionView defines a event that is fired when one of the ScrollTo methods is invoked.
ScrollToRequested
The ScrollToRequestedEventArgs object that accompanies the ScrollToRequested event has many properties,
including IsAnimated , Index , Item , and ScrollToPosition . These properties are set from the arguments
specified in the ScrollTo method calls.
When a user swipes to initiate a scroll, the end position of the scroll can be controlled so that items are fully
displayed. This feature is known as snapping, because items snap to position when scrolling stops. For more
information, see Snap points.
collectionView.ScrollTo(12);
This example code results in the minimal scrolling required to scroll the item into view:
NOTE
The ScrollToPosition.MakeVisible member is used by default, if the position argument is not specified when calling
the ScrollTo method.
Start
The ScrollToPosition.Start member indicates that the item should be scrolled to the start of the view:
This example code results in the item being scrolled to the start of the view:
Center
The ScrollToPosition.Center member indicates that the item should be scrolled to the center of the view:
This example code results in the item being scrolled to the center of the view:
End
The ScrollToPosition.End member indicates that the item should be scrolled to the end of the view:
This example code results in the item being scrolled to the end of the view:
Disable scroll animation
A scrolling animation is displayed when scrolling an item into view. However, this animation can be disabled by
setting the animate argument of the ScrollTo method to false :
Snap points
When a user swipes to initiate a scroll, the end position of the scroll can be controlled so that items are fully
displayed. This feature is known as snapping, because items snap to position when scrolling stops, and is
controlled by the following properties from the ItemsLayout class:
SnapPointsType , of type SnapPointsType , specifies the behavior of snap points when scrolling.
SnapPointsAlignment , of type SnapPointsAlignment , specifies how snap points are aligned with items.
These properties are backed by BindableProperty objects, which means that the properties can be targets of data
bindings.
NOTE
When snapping occurs, it will occur in the direction that produces the least amount of motion.
By default, the SnapPointsType property is set to SnapPointsType.None , which ensures that scrolling does not snap
items, as shown in the following screenshots:
Snap points alignment
The SnapPointsAlignment enumeration defines Start , Center , and End members.
IMPORTANT
The value of the SnapPointsAlignment property is only respected when the SnapPointsType property is set to
Mandatory , or MandatorySingle .
Start
The SnapPointsAlignment.Start member indicates that snap points are aligned with the leading edge of items.
By default, the SnapPointsAlignment property is set to SnapPointsAlignment.Start . However, for completeness, the
following XAML example shows how to set this enumeration member:
<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<ListItemsLayout SnapPointsType="MandatorySingle"
SnapPointsAlignment="Start">
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
When a user swipes to initiate a scroll, the top item will be aligned with the top of the view:
Center
The SnapPointsAlignment.Center member indicates that snap points are aligned with the center of items. The
following XAML example shows how to set this enumeration member:
<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<ListItemsLayout SnapPointsType="MandatorySingle"
SnapPointsAlignment="Center">
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
When a user swipes to initiate a scroll, the top item will be center aligned at the top of the view:
End
The SnapPointsAlignment.End member indicates that snap points are aligned with the trailing edge of items. The
following XAML example shows how to set this enumeration member:
<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<ListItemsLayout SnapPointsType="MandatorySingle"
SnapPointsAlignment="End">
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
When a user swipes to initiate a scroll, the bottom item will be aligned with the bottom of the view:
Related links
CollectionView (sample)
Colors in Xamarin.Forms
12/7/2018 • 3 minutes to read • Edit Online
These colors are shown on each platform below. Notice the final color - Accent - is a blue-ish color for iOS and
Android; this value is defined by Xamarin.Forms.
Color.Default
Use the Default to set (or re-set) a color value back to the platform default (understanding that this represents a
different underlying color on each platform for each property).
Developers can use this value to set a Color property but should not query this instance for its component RGB
values (they're all set to -1).
Color.Transparent
Set the color to clear.
Color.Accent
On iOS and Android this instance is set to a contrasting color that is visible on the default background but is not
the same as the default text color.
Additional Methods
Color instances include additional methods that can be used to create new colors:
AddLuminosity - returns a new color by modifying the luminosity by the supplied delta.
WithHue - returns a new color, replacing the hue with the value supplied.
WithLuminosity - returns a new color, replacing the luminosity with the value supplied.
WithSaturation - returns a new color, replacing the saturation with the value supplied.
MultiplyAlpha - returns a new color by modifying the alpha, multiplying it by the supplied alpha value.
Implicit Conversions
Implicit conversion between the Xamarin.Forms.Color and System.Drawing.Color types can be performed:
Device.RuntimePlatform
This code snippet uses the Device.RuntimePlatform property to selectively set the color of an ActivityIndicator :
NOTE
When using XAML compilation, color names are case insensitive and therefore can be written in lowercase. For more
information about XAML compilation, see XAML Compilation.
Summary
The Xamarin.Forms Color class is used to create platform-aware color references. It can be used in shared code
and XAML.
Related Links
ColorsSample
Bindable Picker (sample)
Controls Reference
1/30/2019 • 2 minutes to read • Edit Online
In the four articles on Pages, Layouts, Views, and Cells, each type of control is described with links to its API
documentation, an article describing its use (if one exists), and one or more sample programs (if they exist). Each
type of control is also accompanied by a screenshot showing a page from the FormsGallery sample running on
iOS, Android, and UWP devices. Below each screenshot are links to the source code for the C# page, the
equivalent XAML page, and (when appropriate) the C# code-behind file for the XAML page.
Related Links
Xamarin.Forms FormsGallery sample
API Documentation
Xamarin.Forms Pages
1/30/2019 • 2 minutes to read • Edit Online
Pages
Xamarin.Forms supports the following page types:
ContentPage
API Documentation
MasterDetailPage
A MasterDetailPage manages two panes of information.
Set the Master property to a page generally showing a list
or menu. Set the Detail property to a page showing a
selected item from the master page. The IsPresented
property governs whether the master or detail page is visible.
NavigationPage
TabbedPage
CarouselPage
CarouselPage derives from the abstract MultiPage class
and allows navigation among child pages through finger
swiping. Set the Children property to a collection of
ContentPage objects, or set the ItemsSource property to
a collection of data objects and the ItemTemplate property
to a DataTemplate describing how each object is to be
visually represented.
TemplatedPage
Related Links
Xamarin.Forms FormsGallery sample
Xamarin.Forms Samples
Xamarin.Forms API Documentation
Xamarin.Forms Layouts
1/30/2019 • 2 minutes to read • Edit Online
The classes that derive from Layout can be divided into two categories:
API Documentation
Frame
The Frame class derives from ContentView and displays a
rectangular frame around its child. Frame has a default
Padding value of 20, and also defines OutlineColor ,
CornerRadius , and HasShadow properties.
API Documentation
ScrollView
TemplatedView
ContentPresenter
ContentPresenter is a layout manager for templated views,
used within a ControlTemplate to mark where the content
that is to be presented appears.
Grid
AbsoluteLayout
AbsoluteLayout positions child elements at specific
locations relative to its parent. A child's position is indicated
using the attached properties LayoutBounds and
LayoutFlags . An AbsoluteLayout is useful for animating
the positions of views.
RelativeLayout
FlexLayout
Related Links
Xamarin.Forms FormsGallery sample
Xamarin.Forms Samples
Xamarin.Forms API Documentation
Xamarin.Forms Views
4/11/2019 • 6 minutes to read • Edit Online
Image
BoxView
BoxView displays a solid rectangle colored by the Color
property. BoxView has a default size request of 40x40. For
other sizes, assign the WidthRequest and HeightRequest
properties.
WebView
OpenGLView
Map
Map displays a map. The Xamarin.Forms.Maps Nuget
package must be installed. Android and Universal Windows
Platform require a map authorization key.
ImageButton
Guide / Sample
SearchBar
SearchBar displays an area for the user to type a text
string, and a button (or a keyboard key) that signals the
application to perform a search. The Text property provides
access to the text, and the SearchButtonPressed event
indicates that the button has been pressed.
API Documentation
Stepper
Switch
Switch takes the form of an on/off switch to allow the user
to select a Boolean value. The IsToggled property is the
state of the switch, and the Toggled event is fired when the
state changes.
API Documentation
DatePicker
TimePicker
Editor
API Documentation
ProgressBar
ProgressBar uses an animation to show that the
application is progressing through a lengthy activity. Set the
Progress property to values between 0 and 1 to indicate
the progress.
API Documentation
Guide / Sample
ListView
Picker
Picker displays a selected item from a list of text strings,
and allows selecting that item when the view is tapped. Set
the Items property to a list of strings, or the ItemsSource
property to a collection of objects. The
SelectedIndexChanged event is fired when an item is
selected.
The Picker displays the list of items only when it's selected.
Use a ListView or TableView for a scrollable list that
remains on the page.
TableView
Related Links
Xamarin.Forms FormsGallery sample
Xamarin.Forms Samples
Xamarin.Forms API Documentation
Xamarin.Forms Cells
1/30/2019 • 2 minutes to read • Edit Online
Cells
Xamarin.Forms supports the following cell types:
TextCell
ImageCell
The SwitchCell contains text set with the Text ' property
and on/off switch initially set with the Boolean On property.
Handle the OnChanged event to be notified when the On
property changes.
EntryCell
Related Links
Xamarin.Forms FormsGallery sample
Xamarin.Forms Samples
Xamarin.Forms API Documentation
Xamarin.Forms DataPages
6/8/2018 • 2 minutes to read • Edit Online
IMPORTANT
DataPages requires a Xamarin.Forms Theme reference to render.
Xamarin.Forms DataPages were announced at Evolve 2016 and are available as a preview for customers to try and
provide feedback.
DataPages provide an API to quickly and easily bind a data source to pre-built views. List items and detail pages
will automatically render the data, and can be customized using themes.
To see how the Evolve keynote demo works, check out the getting started guide.
Introduction
Data sources and the associated data pages allow developers to quickly and easily consume a supported data
source and render it using built-in UI scaffolding that can be customized with themes.
DataPages are added to a Xamarin.Forms application by including the Xamarin.Forms.Pages Nuget package.
Data Sources
The Preview has some prebuilt data sources available for use:
JsonDataSource
AzureDataSource (separate Nuget)
AzureEasyTableDataSource (separate Nuget)
See the getting started guide for an example using a JsonDataSource .
Pages & Controls
The following pages and controls are included to allow easy binding to the supplied data sources:
ListDataPage – see the getting started example.
DirectoryPage – a list with grouping enabled.
PersonDetailPage – a single data item view customized for a specific object type (a contact entry).
DataView – a view to expose data from the source in a generic fashion.
CardView – a styled view that contains an image, title text, and description text.
HeroImage – an image-rendering view.
ListItem – a pre-built view with a layout similar to native iOS and Android list items.
See the DataPages controls reference for examples.
Under the Hood
A Xamarin.Forms data source adheres to the IDataSource interface.
The Xamarin.Forms infrastructure interacts with a data source through the following properties:
Data – a read-only list of data items that can be displayed.
IsLoading – a boolean indicating whether the data is loaded and available for rendering.
[key] – an indexer to retrieve elements.
There are two methods MaskKey and UnmaskKey that can be used to hide (or show ) data item properties (ie.
prevent them from being rendered). The key corresponds to the a named property on the data item object.
Getting Started with DataPages
4/16/2019 • 4 minutes to read • Edit Online
IMPORTANT
DataPages requires a Xamarin.Forms Theme reference to render.
To get started building a simple data-driven page using the DataPages Preview, follow the steps below. This demo
uses a hardcoded style ("Events") in the Preview builds that only works with the specific JSON format in the code.
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mytheme="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Light"
x:Class="DataPagesDemo.App">
<Application.Resources>
<ResourceDictionary MergedWith="mytheme:LightThemeResources" />
</Application.Resources>
</Application>
IMPORTANT: You should also follow the steps to load theme assemblies (below ) by adding some boilerplate
code to the iOS AppDelegate and Android MainActivity . This will be improved in a future preview release.
C# file
XAML file
In addition to changing the root element to <p:ListDataPage> the custom namespace for xmlns:p must also be
added:
<ContentPage.Content></ContentPage.Content>
</p:ListDataPage>
Application subclass
Change the class constructor so that the MainPage is set to a
App NavigationPage containing the new
SessionDataPage . A navigation page must be used.
<p:ListDataPage.DataSource>
<p:JsonDataSource Source="http://demo3143189.mockable.io/sessions" />
</p:ListDataPage.DataSource>
</p:ListDataPage>
JSON data
An example of the JSON data from the demo source is shown below:
[{
"end": "2016-04-27T18:00:00Z",
"start": "2016-04-27T17:15:00Z",
"abstract": "The new Apple TV has been released, and YOU can be one of the first developers to write apps
for it. To make things even better, you can build these apps in C#! This session will introduce the basics of
how to create a tvOS app with Xamarin, including: differences between tvOS and iOS APIs, TV user interface
best practices, responding to user input, as well as the capabilities and limitations of building apps for a
television. Grab some popcorn—this is going to be good!",
"title": "As Seen On TV … Bringing C# to the Living Room",
"presenter": "Matthew Soucoup",
"biography": "Matthew is a Xamarin MVP and Certified Xamarin Developer from Madison, WI. He founded his
company Code Mill Technologies and started the Madison Mobile .Net Developers Group. Matt regularly speaks on
.Net and Xamarin development at user groups, code camps and conferences throughout the Midwest. Matt gardens
hot peppers, rides bikes, and loves Wisconsin micro-brews and cheese.",
"image": "http://i.imgur.com/ASj60DP.jpg",
"avatar": "http://i.imgur.com/ASj60DP.jpg",
"room": "Crick"
}]
4. Run!
The above steps should result in a working data page:
This works because the pre-built style "Events" exists in the Light Theme Nuget package and has styles defined
that match the data source (eg. "title", "image", "presenter").
The "Events" StyleClass is built to display the ListDataPage control with a custom CardView control that is
defined in Xamarin.Forms.Pages. The CardView control has three properties: ImageSource , Text , and Detail .
The theme is hardcoded to bind the datasource's three fields (from the JSON file) to these properties for display.
5. Customize
The inherited style can be overridden by specifying a template and using data source bindings. The XAML below
declares a custom template for each row using the new ListItemControl and {p:DataSourceBinding} syntax which
is included in the Xamarin.Forms.Pages Nuget:
<p:ListDataPage.DefaultItemTemplate>
<DataTemplate>
<ViewCell>
<p:ListItemControl
Title="{p:DataSourceBinding title}"
Detail="{p:DataSourceBinding room}"
ImageSource="{p:DataSourceBinding image}"
DataSource="{Binding Value}"
HeightRequest="90"
>
</p:ListItemControl>
</ViewCell>
</DataTemplate>
</p:ListDataPage.DefaultItemTemplate>
By providing a DataTemplate this code overrides the StyleClass and instead uses the default layout for a
ListItemControl .
Developers that prefer C# to XAML can create data source bindings too (remember to include a
using Xamarin.Forms.Pages; statement):
It's a little more work to create themes from scratch (see the Themes guide) but future preview releases will make
this easier to do.
Troubleshooting
Could not load file or assembly 'Xamarin.Forms.Theme.Light' or one of
its dependencies
In the preview release, themes may not be able to load at runtime. Add the code shown below into the relevant
projects to fix this error.
iOS
In the AppDelegate.cs add the following lines after LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.iOS.UnderlineEffect);
Android
In the MainActivity.cs add the following lines after LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.Android.UnderlineEffect);
Related Links
DataPagesDemo sample
DataPages Controls Reference
6/8/2018 • 4 minutes to read • Edit Online
IMPORTANT
DataPages requires a Xamarin.Forms Theme reference to render.
The Xamarin.Forms DataPages Nuget includes a number of controls that can take advantage of data source
binding.
To use these controls in XAML, ensure the namespace has been included, for example see the xmlns:pages
declaration below:
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"
x:Class="DataPagesDemo.Detail">
The examples below include DynamicResource references which would need to exist in the project's resources
dictionary to work. There is also an example of how to build a custom control
Built-in Controls
HeroImage
ListItem
HeroImage
The HeroImage control has four properties:
Text
Detail
ImageSource
Aspect
<pages:HeroImage
ImageSource="{ DynamicResource HeroImageImage }"
Text="Keith Ballinger"
Detail="Xamarin"
/>
Android
iOS
ListItem
The ListItem control's layout is similar to native iOS and Android list or table rows, however it can also be used
as a regular view. In the example code below it is shown hosted inside a StackLayout , but it can also be used in
data-bound scolling list controls.
There are five properties:
Title
Detail
ImageSource
PlaceholdImageSource
Aspect
<StackLayout Spacing="0">
<pages:ListItemControl
Detail="Xamarin"
ImageSource="{ DynamicResource UserImage }"
Title="Miguel de Icaza"
PlaceholdImageSource="{ DynamicResource IconImage }"
/>
These screenshots show the ListItem on iOS and Android platforms using both the Light and Dark themes:
Android
iOS
<local:CardView
ImageSource="{ DynamicResource CardViewImage }"
Text="CardView Text"
Detail="CardView Detail"
/>
It should look like the screenshots below using colors corresponding to the built-in Light and Dark themes:
Android
iOS
public CardView()
{
}
}
</StackLayout>
</ControlTemplate>
5. Add the Theme-specific Resources
Because this is a custom control, add the resources that match the theme you are using the resource dictionary:
Li gh t T h em e Co l o r s
<Color x:Key="iOSCardViewBackgroundColor">#FFFFFF</Color>
<Color x:Key="AndroidCardViewBackgroundColor">#FFFFFF</Color>
<Color x:Key="AndroidCardViewTextTextColor">#030303</Color>
<Color x:Key="iOSCardViewTextTextColor">#030303</Color>
<Color x:Key="AndroidCardViewDetailTextColor">#8F8E94</Color>
<Color x:Key="iOSCardViewDetailTextColor">#8F8E94</Color>
Dar k T h em e Co l o r s
<Color x:Key="AndroidCardViewTextTextColor">#FFFFFF</Color>
<Color x:Key="iOSCardViewTextTextColor">#FFFFFF</Color>
<Color x:Key="AndroidCardViewDetailTextColor">#B5B4B9</Color>
<Color x:Key="iOSCardViewDetailTextColor">#B5B4B9</Color>
<Style TargetType="local:CardView">
<Setter Property="ControlTemplate" Value="{ StaticResource CardViewControlControlTemplate }" />
... some custom styling omitted
<Setter Property="BackgroundColor" Value="{ StaticResource CardViewBackgroundColor }" />
</Style>
<StackLayout Spacing="0">
<local:CardView
Margin="12,6"
ImageSource="{ DynamicResource CardViewImage }"
Text="CardView Text"
Detail="CardView Detail"
/>
</StackLayout>
Xamarin.Forms DatePicker
12/7/2018 • 5 minutes to read • Edit Online
MinimumDate of type , which defaults to the first day of the year 1900.
DateTime
MaximumDate of type
DateTime , which defaults to the last day of the year 2100.
Date of type DateTime , the selected date, which defaults to the value DateTime.Today .
Format of type string , a standard or custom .NET formatting string, which defaults to "D", the long date
pattern.
TextColor of type Color , the color used to display the selected date, which defaults to Color.Default .
FontAttributes of type FontAttributes , which defaults to FontAtributes.None .
FontFamily of type string , which defaults to null .
FontSize of type double , which defaults to -1.0.
The DatePicker fires a DateSelected event when the user selects a date.
WARNING
When setting MinimumDate and MaximumDate , make sure that MinimumDate is always less than or equal to
MaximumDate . Otherwise, DatePicker will raise an exception.
Internally, the DatePicker ensures that Date is between MinimumDate and MaximumDate , inclusive. If MinimumDate
or MaximumDate is set so that Date is not between them, DatePicker will adjust the value of Date .
All eight properties are backed by BindableProperty objects, which means that they can be styled, and the
properties can be targets of data bindings. The Date property has a default binding mode of BindingMode.TwoWay ,
which means that it can be a target of a data binding in an application that uses the Model-View -ViewModel
(MVVM ) architecture.
When a DateTime value is specified in XAML, the XAML parser uses the DateTime.Parse method with a
CultureInfo.InvariantCulture argument to convert the string to a DateTime value. The dates must be specified in
a precise format: two-digit months, two-digit days, and four-digit years separated by slashes:
<DatePicker MinimumDate="01/01/2018"
MaximumDate="12/31/2018"
Date="06/21/2018" />
In this example, all three properties are initialized to the corresponding properties in the ViewModel. Because the
Date property has a binding mode of TwoWay , any new date that the user selects is automatically reflected in the
ViewModel.
If the DatePickerdoes not contain a binding on its Date property, an application should attach a handler to the
DateSelected event to be informed when the user selects a new date.
For information about setting font properties, see Fonts.
<DatePicker ···
HorizontalOptions="Center"
··· />
However, this is not recommended. Depending on the setting of the Format property, selected dates might
require different display widths. For example, the "D" format string causes DateTime to display dates in a long
format, and "Wednesday, September 12, 2018" requires a greater display width than "Friday, May 4, 2018".
Depending on the platform, this difference might cause the DateTime view to change width in layout, or for the
display to be truncated.
TIP
It's best to use the default HorizontalOptions setting of Fill with DatePicker , and not to use a width of Auto when
putting DatePicker in a Grid cell.
DatePicker in an application
The DaysBetweenDates sample includes two DatePicker views on its page. These can be used to select two
dates, and the program calculates the number of days between those dates. The program doesn't change the
settings of the MinimumDate and MaximumDate properties, so the two dates must be between 1900 and 2100.
Here's the XAML file:
<?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:DaysBetweenDates"
x:Class="DaysBetweenDates.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout Margin="10">
<Label Text="Days Between Dates"
Style="{DynamicResource TitleStyle}"
Margin="0, 20"
HorizontalTextAlignment="Center" />
<DatePicker x:Name="startDatePicker"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />
<DatePicker x:Name="endDatePicker"
MinimumDate="{Binding Source={x:Reference startDatePicker},
Path=Date}"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />
<StackLayout Orientation="Horizontal"
Margin="0, 0, 0, 30">
<Label Text="Include both days in total: "
VerticalOptions="Center" />
<Switch x:Name="includeSwitch"
Toggled="OnSwitchToggled" />
</StackLayout>
<Label x:Name="resultLabel"
FontAttributes="Bold"
HorizontalTextAlignment="Center" />
</StackLayout>
</ContentPage>
Each DatePicker is assigned a Format property of "D" for a long date format. Notice also that the endDatePicker
object has a binding that targets its MinimumDate property. The binding source is the selected Date property of
the startDatePicker object. This ensures that the end date is always later than or equal to the start date. In
addition to the two DatePicker objects, a Switch is labeled "Include both days in total".
The two DatePicker views have handlers attached to the DateSelected event, and the Switch has a handler
attached to its Toggled event. These event handlers are in the code-behind file and trigger a new calculation of the
days between the two dates:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
void Recalculate()
{
TimeSpan timeSpan = endDatePicker.Date - startDatePicker.Date +
(includeSwitch.IsToggled ? TimeSpan.FromDays(1) : TimeSpan.Zero);
When the sample is first run, both DatePicker views are initialized to today's date. The following screenshot
shows the program running on iOS, Android, and the Universal Windows Platform:
Tapping either of the DatePicker displays invokes the platform date picker. The platforms implement this date
picker in very different ways, but each approach is familiar to users of that platform:
TIP
On Android, the DatePicker dialog can be customized by overriding the CreateDatePickerDialog method in a custom
renderer. This allows, for example, additional buttons to be added to the dialog.
After two dates are selected, the application displays the number of days between those dates:
Related links
DaysBetweenDates sample
DatePicker API
SkiaSharp Graphics in Xamarin.Forms
12/7/2018 • 2 minutes to read • Edit Online
SkiaSharp Preliminaries
SkiaSharp for Xamarin.Forms is packaged as a NuGet package. After you've created a Xamarin.Forms solution in
Visual Studio or Visual Studio for Mac, you can use the NuGet package manager to search for the
SkiaSharp.Views.Forms package and add it to your solution. If you check the References section of each project
after adding SkiaSharp, you can see that various SkiaSharp libraries have been added to each of the projects in the
solution.
If your Xamarin.Forms application targets iOS, use the project properties page to change the minimum
deployment target to iOS 8.0.
In any C# page that uses SkiaSharp you'll want to include a using directive for the SkiaSharp namespace, which
encompasses all the SkiaSharp classes, structures, and enumerations that you'll use in your graphics programming.
You'll also want a using directive for the SkiaSharp.Views.Forms namespace for the classes specific to
Xamarin.Forms. This is a much smaller namespace, with the most important class being SKCanvasView . This class
derives from the Xamarin.Forms View class and hosts your SkiaSharp graphics output.
IMPORTANT
The SkiaSharp.Views.Forms namespace also contains an SKGLView class that derives from View but uses OpenGL for
rendering graphics. For purposes of simplicity, this guide restricts itself to SKCanvasView , but using SKGLView instead is
quite similar.
SkiaSharp Transforms
Transforms allow graphics objects to be uniformly translated, scaled, rotated, or skewed. This article also shows
how you can use a standard 3-by-3 transform matrix for creating non-affine transforms and applying transforms to
paths.
SkiaSharp Bitmaps
Bitmaps are rectangular arrays of bits corresponding to the pixels of a display device. This series of articles shows
how to load, save, display, create, draw on, animate, and access the bits of SkiaSharp bitmaps.
SkiaSharp Effects
Effects are properties that alter the normal display of graphics, including linear and circular gradients, bitmap tiling,
blend modes, blur, and others.
Related Links
SkiaSharp APIs
SkiaSharpFormsDemos (sample)
SkiaSharp with Xamarin.Forms Webinar (video)
Images in Xamarin.Forms
3/8/2019 • 11 minutes to read • Edit Online
Displaying Images
Xamarin.Forms uses the Image view to display images on a page. It has two important properties:
Source- An ImageSource instance, either File, Uri or Resource, which sets the image to display.
Aspect - How to size the image within the bounds it is being displayed within (whether to stretch, crop or
letterbox).
ImageSource instances can be obtained using static methods for each type of image source:
FromFile- Requires a filename or filepath that can be resolved on each platform.
FromUri - Requires a Uri object, eg. new Uri("http://server.com/image.jpg") .
FromResource - Requires a resource identifier to an image file embedded in the application or .NET Standard
library project, with a Build Action:EmbeddedResource.
FromStream - Requires a stream that supplies image data.
The Aspect property determines how the image will be scaled to fit the display area:
Fill- Stretches the image to completely and exactly fill the display area. This may result in the image being
distorted.
AspectFill - Clips the image so that it fills the display area while preserving the aspect (ie. no distortion).
AspectFit - Letterboxes the image (if required) so that the entire image fits into the display area, with blank
space added to the top/bottom or sides depending on whether the image is wide or tall.
Images can be loaded from a local file, an embedded resource, or downloaded. In addition, font icons can be
displayed by the Image view by specifying the font icon data in a FontImageSource object. For more information,
see Display font icons in the Fonts guide.
Local Images
Image files can be added to each application project and referenced from Xamarin.Forms shared code. This
method of distributing images is required when images are platform-specific, such as when using different
resolutions on different platforms, or slightly different designs.
To use a single image across all apps, the same filename must be used on every platform, and it should be a valid
Android resource name (ie. only lowercase letters, numerals, the underscore, and the period are allowed).
iOS - The preferred way to manage and support images since iOS 9 is to use Asset Catalog Image Sets,
which should contain all of the versions of an image that are necessary to support various devices and scale
factors for an application. For more information, see Adding Images to an Asset Catalog Image Set.
Android - Place images in the Resources/drawable directory with Build Action: AndroidResource. High-
and low -DPI versions of an image can also be supplied (in appropriately named Resources subdirectories
such as drawable-ldpi, drawable-hdpi, and drawable-xhdpi).
Universal Windows Platform (UWP ) - Place images in the application's root directory with Build Action:
Content.
IMPORTANT
Prior to iOS 9, images were typically placed in the Resources folder with Build Action: BundleResource. However, this
method of working with images in an iOS app has been deprecated by Apple. For more information, see Image Sizes and
Filenames.
Adhering to these rules for file naming and placement allows the following XAML to load and display the image
on all platforms:
The following screenshots show the result of displaying a local image on each platform:
For more flexibility the Device.RuntimePlatform property can be used to select a different image file or path for
some or all platforms, as shown in this code example:
IMPORTANT
To use the same image filename across all platforms the name must be valid on all platforms. Android drawables have
naming restrictions – only lowercase letters, numbers, underscore, and period are allowed – and for cross-platform
compatibility this must be followed on all the other platforms too. The example filename waterfront.png follows the rules,
but examples of invalid filenames include "water front.png", "WaterFront.png", "water-front.png", and "wåterfront.png".
Native Resolutions (Retina and High-DPI )
iOS, Android, and UWP include support for different image resolutions, where the operating system chooses the
appropriate image at runtime based on the device's capabilities. Xamarin.Forms uses the native platforms' APIs
for loading local images, so it automatically supports alternate resolutions if the files are correctly named and
located in the project.
The preferred way to manage images since iOS 9 is to drag images for each resolution required to the
appropriate asset catalog image set. For more information, see Adding Images to an Asset Catalog Image Set.
Prior to iOS 9, retina versions of the image could be placed in the Resources folder - two and three times the
resolution with a @2x or @3x suffixes on the filename before the file extension (eg. [email protected]).
However, this method of working with images in an iOS app has been deprecated by Apple. For more
information, see Image Sizes and Filenames.
Android alternate resolution images should be placed in specially-named directories in the Android project, as
shown in the following screenshot:
UWP image file names can be suffixed with .scale-xxx before the file extension, where xxx is the percentage of
scaling applied to the asset, e.g. myimage.scale-200.png. Images can then be referred to in code or XAML
without the scale modifier, e.g. just myimage.png. The platform will select the nearest appropriate asset scale
based on the display's current DPI.
Additional Controls that Display Images
Some controls have properties that display an image, such as:
Page - Any page type that derives from Page has Icon and BackgroundImage properties, which can be
assigned a local file reference. Under certain circumstances, such as when a NavigationPage is displaying a
ContentPage , the icon will be displayed if supported by the platform.
IMPORTANT
On iOS, the Page.Icon property can't be populated from an image in an asset catalog image set. Instead, load
icon images for the Page.Icon property from the Resources folder in the iOS project.
ToolbarItem - Has an Icon property that can be set to a local file reference.
ImageCell - Has an ImageSource property that can be set to an image retrieved from a local file, an
embedded resource, or a URI.
Embedded Images
Embedded images are also shipped with an application (like local images) but instead of having a copy of the
image in each application's file structure the image file is embedded in the assembly as a resource. This method of
distributing images is recommended when identical images are used on each platform, and is particularly suited
to creating components, as the image is bundled with the code.
To embed an image in a project, right-click to add new items and select the image/s you wish to add. By default
the image will have Build Action: None; this needs to be set to Build Action: EmbeddedResource.
Visual Studio
Visual Studio for Mac
The Build Action can be viewed and changed in the Properties window for a file.
In this example the resource ID is WorkingWithImages.beach.jpg. The IDE has generated this default by
concatenating the Default Namespace for this project with the filename, using a period (.) between each value.
If you place embedded images into folders within your project, the folder names are also separated by periods (.)
in the resource ID. Moving the beach.jpg image into a folder called MyImages would result in a resource ID of
WorkingWithImages.MyImages.beach.jpg
The code to load an embedded image simply passes the Resource ID to the ImageSource.FromResource method
as shown below:
NOTE
To support displaying embedded images in release mode on the Universal Windows Platform, it's necessary to use the
overload of ImageSource.FromResource that specifies the source assembly in which to search for the image.
Currently there is no implicit conversion for resource identifiers. Instead, you must use ImageSource.FromResource
or new ResourceImageSource() to load embedded images.
The following screenshots show the result of displaying an embedded image on each platform:
Using XAML
Because there is no built-in type converter from string to ResourceImageSource , these types of images cannot be
natively loaded by XAML. Instead, a simple custom XAML markup extension can be written to load images using
a Resource ID specified in XAML:
[ContentProperty (nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }
return imageSource;
}
}
NOTE
To support displaying embedded images in release mode on the Universal Windows Platform, it's necessary to use the
overload of ImageSource.FromResource that specifies the source assembly in which to search for the image.
To use this extension add a custom xmlns to the XAML, using the correct namespace and assembly values for the
project. The image source can then be set using this syntax: {local:ImageResource WorkingWithImages.beach.jpg} . A
complete XAML example is shown below:
using System.Reflection;
// ...
// NOTE: use for debugging, not in released app code!
var assembly = typeof(EmbeddedImages).GetTypeInfo().Assembly;
foreach (var res in assembly.GetManifestResourceNames())
{
System.Diagnostics.Debug.WriteLine("found resource: " + res);
}
Downloading Images
Images can be automatically downloaded for display, as shown in the following XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WorkingWithImages.DownloadImagesXaml">
<StackLayout VerticalOptions="Center" HorizontalOptions="Center">
<Label Text="Image UriSource Xaml" />
<Image Source="https://xamarin.com/content/images/pages/forms/example-app.png" />
<Label Text="example-app.png gets downloaded from xamarin.com" />
</StackLayout>
</ContentPage>
The ImageSource.FromUri method requires a Uri object, and returns a new UriImageSource that reads from the
Uri .
There is also an implicit conversion for URI strings, so the following example will also work:
webImage.Source = "https://xamarin.com/content/images/pages/forms/example-app.png";
The following screenshots show the result of displaying a remote image on each platform:
Caching is enabled by default and will store the image locally for 24 hours. To disable caching for a particular
image, instantiate the image source as follows:
To set a specific cache period (for example, 5 days) instantiate the image source as follows:
webImage.Source = new UriImageSource
{
Uri = new Uri("https://xamarin.com/content/images/pages/forms/example-app.png"),
CachingEnabled = true,
CacheValidity = new TimeSpan(5,0,0,0)
};
Built-in caching makes it very easy to support scenarios like scrolling lists of images, where you can set (or bind)
an image in each cell and let the built-in cache take care of re-loading the image when the cell is scrolled back into
view.
Icons
See the iOS Working with Images, Google Iconography, and Guidelines for tile and icon assets for more
information on creating these application resources.
In addition, font icons can be displayed by the Image view by specifying the font icon data in a FontImageSource
object. For more information, see Display font icons in the Fonts guide.
Splash screens
Only iOS and UWP applications require a splash screen (also called a startup screen or default image).
Refer to the documentation for iOS Working with Images and Splash screens on the Windows Dev Center.
Summary
Xamarin.Forms offers a number of different ways to include images in a cross-platform application, allowing for
the same image to be used across platforms or for platform-specific images to be specified. Downloaded images
are also automatically cached, automating a common coding scenario.
Application icon and splash screen images are set-up and configured as for non-Xamarin.Forms applications -
follow the same guidance used for platform-specific apps.
Related Links
WorkingWithImages (sample)
iOS Working with Images
Android Iconography
Guidelines for tile and icon assets
Xamarin.Forms ImageButton
12/7/2018 • 6 minutes to read • Edit Online
NOTE
While the Button view defines an Image property, that allows you to display a image on the Button , this property is
intended to be used when displaying a small icon next to the Button text.
The code examples in this guide are taken from the FormsGallery sample.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FormsGallery.XamlExamples.ImageButtonDemoPage"
Title="ImageButton Demo">
<StackLayout>
<Label Text="ImageButton"
FontSize="50"
FontAttributes="Bold"
HorizontalOptions="Center" />
<ImageButton Source="XamarinLogo.png"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
The Source property specifies the image that appears in the ImageButton . In this example it's set to a local file
that will be loaded from each platform project, resulting in the following screenshots:
By default, the ImageButton is rectangular, but you can give it rounded corners by using the CornerRadius
property. For more information about ImageButton appearance, see ImageButton appearance.
The following example shows how to create a page that is functionally equivalent to the previous XAML example,
but entirely in C#:
The following example shows how to instantiate a ImageButton in XAML and handle its Clicked event:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FormsGallery.XamlExamples.ImageButtonDemoPage"
Title="ImageButton Demo">
<StackLayout>
<Label Text="ImageButton"
FontSize="50"
FontAttributes="Bold"
HorizontalOptions="Center" />
<ImageButton Source="XamarinLogo.png"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnImageButtonClicked" />
<Label x:Name="label"
Text="0 ImageButton clicks"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
The Clicked event is set to an event handler named OnImageButtonClicked that is located in the code-behind file:
public ImageButtonDemoPage()
{
InitializeComponent();
}
When the is tapped, the OnImageButtonClicked method executes. The sender argument is the
ImageButton
ImageButton responsible for this event. You can use this to access the ImageButton object, or to distinguish
between multiple ImageButton objects sharing the same Clicked event.
This particular Clicked handler increments a counter and displays the counter value in a Label :
The following example shows how to create a page that is functionally equivalent to the previous XAML example,
but entirely in C#:
public class ImageButtonDemoPage : ContentPage
{
Label label;
int clickTotal = 0;
public ImageButtonDemoPage()
{
Label header = new Label
{
Text = "ImageButton",
FontSize = 50,
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Center
};
ImageButton appearance
In addition to the properties that ImageButton inherits from the View class, ImageButton also defines several
properties that affect its appearance:
Aspect is how the image will be scaled to fit the display area.
BorderColor is the color of an area surrounding the ImageButton .
BorderWidth is the width of the border.
CornerRadius is the corner radius of the ImageButton .
The Aspect property can be set to one of the members of the Aspect enumeration:
Fill- stretches the image to completely and exactly fill the ImageButton . This may result in the image being
distorted.
AspectFill - clips the image so that it fills the ImageButton while preserving the aspect ratio.
AspectFit - letterboxes the image (if necessary) so that the entire image fits into the ImageButton , with blank
space added to the top/bottom or sides depending on whether the image is wide or tall. This is the default
value of the Aspect enumeration.
NOTE
The ImageButton class also has Margin and Padding properties that control the layout behavior of the ImageButton .
For more information, see Margin and Padding.
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ImageButton>
The Pressed VisualState specifies that when the ImageButton is pressed, its Scale property will be changed
from its default value of 1 to 0.8. The Normal VisualState specifies that when the ImageButton is in a normal
state, its Scale property will be set to 1. Therefore, the overall effect is that when the ImageButton is pressed, it's
rescaled to be slightly smaller, and when the ImageButton is released, it's rescaled to its default size.
For more information about visual states, see The Xamarin.Forms Visual State Manager.
Related links
FormsGallery sample
Layouts in Xamarin.Forms
5/1/2019 • 8 minutes to read • Edit Online
For an example of when StackLayout would be a good choice, consider an app that needs to display a button and
a label, with the label left-aligned and the button right-aligned.
<StackLayout Orientation="Horizontal">
<Label HorizontalOptions="StartAndExpand" Text="Label" />
<Button HorizontalOptions="End" Text="Button" />
</StackLayout>
FlexLayout
The FlexLayout is similar to StackLayout in that it displays child views either horizontally or vertically:
<FlexLayout Direction="Column"
AlignItems="Center"
JustifyContent="SpaceEvenly">
However, if there are too many children to fit in a single row or columm, FlexLayout is also capable of wrapping
those views. FlexLayout is based on the CSS Flexible Box Layout Module, and has many of the same built-in
options for positioning and aligning its children.
AbsoluteLayout
The AbsoluteLayout is used for displaying views, with size and position being specified either as explicit values or
values relative to the size of the layout. Unlike StackLayout and Grid , AbsoluteLayout allows child views to
overlap. Unlike RelativeLayout , AbsoluteLayout doesn't let you place elements off screen.
For an example of when AbsoluteLayout would be a good choice, consider an app that needs to present collections
of objects as stacks. This is often seen when presenting albums of photos or songs. The following code gives the
appearance of a pile, with elements rotated to hint at the contents of the pile:
In XAML:
<AbsoluteLayout Padding="15">
<Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100"
Rotation="30"
Source="bottom.png" />
<Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100"
Rotation="60"
Source="middle.png" />
<Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100"
Source="cover.png" />
</AbsoluteLayout>
RelativeLayout
The RelativeLayout is used for displaying views, with size and position specified as values relative to the values of
the layout or another view. Relative values do not need to match he corresponding value on the related view. As an
example, it is possible to set a view's Width property to be proportional to another view's X property.
RelativeLayout can be used to create UIs that scale proportionally across device sizes. The following XAML
implements a design with boxes at the topmost corners, with a flagpole with flag in the center:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="1" Grid.Row="0" Grid.Column="0" />
<Button Text="2" Grid.Row="0" Grid.Column="1" />
<Button Text="3" Grid.Row="0" Grid.Column="2" />
<Button Text="4" Grid.Row="1" Grid.Column="0" />
<Button Text="5" Grid.Row="1" Grid.Column="1" />
<Button Text="6" Grid.Row="1" Grid.Column="2" />
<Button Text="7" Grid.Row="2" Grid.Column="0" />
<Button Text="8" Grid.Row="2" Grid.Column="1" />
<Button Text="9" Grid.Row="2" Grid.Column="2" />
<Button Text="0" Grid.Row="3" Grid.Column="1" />
<Button Text="<-" Grid.Row="3" Grid.Column="2" />
</Grid>
Related Links
Apple's Human Interface Guidelines
Android Design Website
Layout (sample)
BusinessTumble Example (sample)
Xamarin.Forms StackLayout
12/7/2018 • 4 minutes to read • Edit Online
Purpose
StackLayout is less complex than other views. Simple linear interfaces can be created by just adding views to a
StackLayout , and more complex interfaces created by nesting them.
In C#:
public class StackLayoutCode : ContentPage
{
public StackLayoutCode ()
{
var layout = new StackLayout ();
var button = new Button { Text = "StackLayout", VerticalOptions = LayoutOptions.Start,
HorizontalOptions = LayoutOptions.FillAndExpand };
var yellowBox = new BoxView { Color = Color.Yellow, VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand };
var greenBox = new BoxView { Color = Color.Green, VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand };
var blueBox = new BoxView { Color = Color.Blue, VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand, HeightRequest = 75 };
layout.Children.Add(button);
layout.Children.Add(yellowBox);
layout.Children.Add(greenBox);
layout.Children.Add(blueBox);
layout.Spacing = 10;
Content = layout;
}
}
Spacing = 0:
Spacing of ten:
Sizing
The size of a view in a StackLayout depends on both the height and width requests and the layout options.
StackLayout will enforce padding. The following LayoutOption s will cause views to take up as much space as is
available from the layout:
CenterAndExpand – centers the view within the layout and expands to take up as much space as the layout
will give it.
EndAndExpand – places the view at the end of the layout (bottom or right-most boundary) and expands to
take up as much space as the layout will give it.
FillAndExpand – places the view so that it has no padding and takes up as much space as the layout will give
it.
StartAndExpand – places the view at the start of the layout and takes up as much space as the parent will
give.
For more information, see Expansion.
Positioning
Views in a StackLayout can be positioned and sized using LayoutOptions . Each view can be given
VerticalOptions and HorizontalOptions , defining how the views will position themselves relative to the layout.
The following predefined LayoutOptions are available:
Center – centers the view within the layout.
End – places the view at the end of the layout (bottom or right-most boundary).
Fill – places the view so that it has no padding.
Start – places the view at the start of the layout.
The following code demonstrates setting layout options:
In XAML:
In C#:
layout.Children.Add(button);
layout.Children.Add(oneBox);
layout.Children.Add(twoBox);
layout.Children.Add(threeBox);
Content = layout;
}
}
Related Links
LayoutOptions
Layout (sample)
BusinessTumble Example (sample)
Xamarin.Forms AbsoluteLayout
12/7/2018 • 7 minutes to read • Edit Online
Purpose
Because of the positioning model of AbsoluteLayout , the layout makes it relatively straightforward to position
elements so that they are flush with any side of the layout, or centered. With proportional sizes and positions,
elements in an AbsoluteLayout can scale automatically to any view size. For items where only the position but not
the size should scale, absolute and proportional values can be mixed.
AbsoluteLayout could be used anywhere elements need to be positioned within a view and is especially useful
when aligning elements to edges.
Usage
Proportional Layouts
AbsoluteLayout has a unique anchor model whereby the anchor of the element is positioned relative to its
element as the element is positioned relative to the layout when proportional positioning is used. When absolute
positioning is used, the anchor is at (0,0) within the view. This has two important consequences:
Elements cannot be positioned off screen using proportional values.
Elements can be reliably positioned along any side of the layout or in the center, regardless of the size of the
layout or device.
AbsoluteLayout , like RelativeLayout , is able to position elements so that they overlap.
Note in the following screenshot, the anchor of the box is a white dot. Notice the relationship between the anchor
and the box as it moves through the layout:
Specifying Values
Views within an AbsoluteLayout are positioned using four values:
X – the x (horizontal) position of the view's anchor
Y – the y (vertical) position of the view's anchor
Width – the width of the view
Height – the height of the view
Each of those values can be set as a proportional value or an absolute value.
Values are specified as a combination of bounds and a flag. LayoutBounds is a Rectangle consisting of four values:
x , y , width , height .
AbsoluteLayoutFlags
AbsoluteLayoutFlags specifies how values will be interpreted and has the following predefined options:
None – interprets all values as absolute. This is the default value if no layout flags are specified.
All – interprets all values as proportional.
WidthProportional – interprets the Width value as proportional and all other values as absolute.
HeightProportional – interprets only the height value as proportional with all other values absolute.
XProportional – interprets the X value as proportional, while treating all other values as absolute.
YProportional – interprets the Y value as proportional, while treating all other values as absolute.
PositionProportional – interprets the X and Y values as proportional, while the size values are interpreted
as absolute.
SizeProportional – interprets the Width and Height values as proportional while the position values are
absolute.
In XAML, bounds and flags are set as part of the definition of views within the layout, using the
AbsoluteLayout.LayoutBounds property. Bounds are set as a comma-separated list of values, X , Y , Width , and
Height , in that order. Flags are also specified in the declaration of views in the layout using the
AbsoluteLayout.LayoutFlags property. Note that flags can be combined in XAML using a comma-separated list.
Consider the following example:
var bottomLabel = new Label { Text = "I'm bottom center on every device.", LineBreakMode =
LineBreakMode.WordWrap };
AbsoluteLayout.SetLayoutBounds (bottomLabel, new Rectangle (.5, 1, .5, .1));
AbsoluteLayout.SetLayoutFlags (bottomLabel, AbsoluteLayoutFlags.All);
layout.Children.Add (bottomLabel);
layout.Children.Add (centerLabel);
layout.Children.Add (rightBox);
layout.Children.Add (leftBox);
layout.Children.Add (topBox);
Content = layout;
}
}
Proportional Values
Proportional values define a relationship between a layout and a view. This relationship defines a child view's
position or scale value as a proportion of the corresponding value of the parent layout. These values are expressed
as double s with values between 0 and 1.
Proportional values are used to position and size views within the layout. So, when a view's width is set as a
proportion, the resultant width value is the proportion multiplied by the AbsoluteLayout 's width. For example,
with an AbsoluteLayout of width 500 and a view set to have a proportional width of .5, the rendered width of the
view will be 250 (500 x .5).
To use proportional values, set LayoutBounds using (x, y) proportions and proportional sizes, then set LayoutFlags
to All .
In XAML:
<Label Text="I'm bottom center on every device."
AbsoluteLayout.LayoutBounds=".5,1,.5,.1" AbsoluteLayout.LayoutFlags="All" />
In C#:
var label = new Label {Text = "I'm bottom center on every device."};
AbsoluteLayout.SetLayoutBounds(label, new Rectangle(.5,1,.5,.1));
AbsoluteLayout.SetLayoutFlags(label, AbsoluteLayoutFlags.All);
Absolute Values
Absolute values explicitly define where views should be positioned within the layout. Unlike proportional values,
absolute values are capable of positioning and sizing a view that does not fit within the bounds of the layout.
Using absolute values for positioning can be dangerous when the size of the layout is not known. When using
absolute positions, an element in the center of the screen at one size could be offset at any other size. It is
important to test your app across the various screen sizes of your supported devices.
To use absolute layout values, set LayoutBounds using (x, y) coordinates and explicit sizes, then set LayoutFlags to
None .
In XAML:
In C#:
var label = new Label {Text = "I'm centered on iPhone 4 but no other device."};
AbsoluteLayout.SetLayoutBounds(label, new Rectangle(115,150,100,100));
Related Links
Creating Mobile Apps with Xamarin.Forms, Chapter 14
AbsoluteLayout
Layout (sample)
BusinessTumble Example (sample)
Xamarin.Forms RelativeLayout
4/26/2019 • 5 minutes to read • Edit Online
Purpose
RelativeLayout can be used to position views on screen relative to the overall layout or to other views.
Usage
Understanding Constraints
Positioning and sizing a view within a RelativeLayout is done with constraints. A constraint expression can
include the following information:
Type – whether the constraint is relative to the parent or to another view.
Property – which property to use as the basis for the constraint.
Factor – the factor to apply to the property value.
Constant – the value to use as an offset of the value.
ElementName – the name of the view that the constraint is relative to.
In XAML, constraints are expressed as ConstraintExpression s. Consider the following example:
In C#, constraints are expressed a little differently, using functions rather than expressions on the view. Constraints
are specified as arguments to the layout's Add method:
NOTE
Because of the way constraints are defined, it is possible to make more complex layouts in C# than can be specified with
XAML.
Both of the examples above define constraints as RelativeToParent – that is, their values are relative to the parent
element. It is also possible to define constraints as relative to another view. This allows for more intuitive (to the
developer) layouts and can make the intent of your layout code more readily apparent.
Consider a layout where one element needs to be 20 pixels lower than another. If both elements are defined with
constant values, the lower could have its Y constraint defined as a constant that is 20 pixels greater than the Y
constraint of the higher element. That approach falls short if the higher element is positioned using a proportion,
so that the pixel size isn't known. In that case, constraining the element based on another element's position is
more robust:
<RelativeLayout>
<BoxView Color="Red" x:Name="redBox"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height,Factor=.15,Constant=0}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=1,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=.8,Constant=0}" />
<BoxView Color="Blue"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView,
ElementName=redBox,Property=Y,Factor=1,Constant=20}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView,
ElementName=redBox,Property=X,Factor=1,Constant=20}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.5,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=.5,Constant=0}" />
</RelativeLayout>
This produces the following output, with the blue box's position determined relative to the position of the red box:
Sizing
Views laid out by RelativeLayout have two options for specifying their size:
HeightRequest & WidthRequest
RelativeLayout.WidthConstraint & RelativeLayout.HeightConstraint
HeightRequest and WidthRequest specify the intended height and width of the view, but may be overridden by
layouts as needed. WidthConstraint and HeightConstraint support setting the height and width as a value relative
to the layout's or another view's properties, or as a constant value.
Related Links
Layout (sample)
BusinessTumble Example (sample)
Xamarin.Forms Grid
4/25/2019 • 10 minutes to read • Edit Online
Usage
Unlike traditional tables, Grid does not infer the number and sizes of rows and columns from the content.
Instead, Grid has RowDefinitions and ColumnDefinitions collections. These hold definitions of how many rows
and columns will be laid out. Views are added to Grid with specified row and column indices, which identify
which row and column a view should be placed in.
Rows and Columns
Row and column information is stored in Grid 's RowDefinitions & ColumnDefinitions properties, which are each
collections of RowDefinition and ColumnDefinition objects, respectively. RowDefinition has a single property,
Height , and ColumnDefinition has a single property, Width . The options for height and width are as follows:
Auto – automatically sizes to fit content in the row or column. Specified as GridUnitType.Auto in C# or as
Auto in XAML.
Proportional(*) – sizes columns and rows as a proportion of the remaining space. Specified as a value and
GridUnitType.Star in C# and as #* in XAML, with # being your desired value. Specifying one row/column
with * will cause it to fill the available space.
Absolute – sizes columns and rows with specific, fixed height and width values. Specified as a value and
GridUnitType.Absolute in C# and as # in XAML, with # being your desired value.
NOTE
The width values for columns are set as * by default in Xamarin.Forms, which ensures that the column will fill the available
space. The height values for rows are also set as * by default.
Consider an app that needs three rows and two columns. The bottom row needs to be exactly 200px tall and the
top row needs to be twice as tall as the middle row. The left column needs to be wide enough to fit the content and
the right column needs to fill the remaining space.
In XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
In C#:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Top Left" Grid.Row="0" Grid.Column="0" />
<Label Text="Top Right" Grid.Row="0" Grid.Column="1" />
<Label Text="Bottom Left" Grid.Row="1" Grid.Column="0" />
<Label Text="Bottom Right" Grid.Row="1" Grid.Column="1" />
</Grid>
In C#:
var grid = new Grid();
grid.Children.Add(topLeft, 0, 0);
grid.Children.Add(topRight, 1, 0);
grid.Children.Add(bottomLeft, 0, 1);
grid.Children.Add(bottomRight, 1, 1);
The above code creates grid with four labels, two columns, and two rows. Note that each label will have the same
size and that the rows will expand to use all available space.
In the example above, views are added to the Grid.Children collection using the Add overload that specifies left
and top arguments. When using the Add overload that specifies left, right, top, and bottom arguments, while the
left and top arguments will always refer to cells within the Grid , the right and bottom arguments may appear to
refer to cells that are outside the Grid . This is because the right argument must always be greater than the left
argument, and the bottom argument must always be greater than the top argument. The following example shows
equivalent code using both Add overloads:
// left, top
grid.Children.Add(topLeft, 0, 0);
grid.Children.Add(topRight, 1, 0);
grid.Children.Add(bottomLeft, 0, 1);
grid.Children.Add(bottomRight, 1, 1);
Spacing
Grid has properties to control spacing between rows and columns. The following properties are available for
customizing the Grid :
ColumnSpacing – the amount of space between columns. The default value of this property is 6.
RowSpacing – the amount of space between rows. The default value of this property is 6.
The following XAML specifies a Grid with two columns, one row, and 5 px of spacing between columns:
<Grid ColumnSpacing="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
In C#:
var grid = new Grid { ColumnSpacing = 5 };
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star)});
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star)});
Spans
Often when working with a grid, there is an element that should occupy more than one row or column. Consider a
simple calculator application:
Notice that the 0 button spans two columns, just like on the built-in calculators for each platform. This is
accomplished using the ColumnSpan property, which specifies how many columns an element should occupy. The
XAML for that button:
And in C#:
Note that in code, static methods of the Grid class are used to perform positioning changes including changes to
ColumnSpan and RowSpan . Also note that, unlike other properties that can be set at any time, properties set using
the static methods must already be in the grid before they are changed.
The complete XAML for the above calculator app is as follows:
Notice that both the label at the top of the grid and the zero button are occuping more than one column. Although
a similar layout could be achieved using nested grids, the ColumnSpan & RowSpan approach is simpler.
The C# implementation:
public CalculatorGridCode ()
{
Title = "Calculator - C#";
BackgroundColor = Color.FromHex ("#404040");
Content = controlGrid;
}
Related Links
Creating Mobile Apps with Xamarin.Forms, Chapter 17
Grid
Layout (sample)
BusinessTumble Example (sample)
The Xamarin.Forms FlexLayout
5/1/2019 • 23 minutes to read • Edit Online
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FlexLayoutDemos"
x:Class="FlexLayoutDemos.SimpleStackPage"
Title="Simple Stack">
<FlexLayout Direction="Column"
AlignItems="Center"
JustifyContent="SpaceEvenly">
With that change, this one Label is positioned at the left edge of the FlexLayout when the reading order is
left-to-right.
The JustifyContent property is of type FlexJustify , and specifies how items are arranged on the main
axis. The SpaceEvenly option allocates all leftover vertical space equally between all the items, and above
the first item, and below the last item.
If you were using a StackLayout , you would need to assign the VerticalOptions property of each item to
CenterAndExpand to achieve a similar effect. But the CenterAndExpand option would allocate twice as much
space between each item than before the first item and after the last item. You can mimic the
CenterAndExpand option of VerticalOptions by setting the JustifyContent property of FlexLayout to
SpaceAround .
These FlexLayout properties are discussed in more detail in the section The bindable properties in detail
below.
Using FlexLayout for wrapping items
The Photo Wrapping page of the FlexLayoutDemos sample demonstrates how FlexLayout can wrap its
children to additional rows or columns. The XAML file instantiates the FlexLayout and assigns two properties of
it:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FlexLayoutDemos.PhotoWrappingPage"
Title="Photo Wrapping">
<Grid>
<ScrollView>
<FlexLayout x:Name="flexLayout"
Wrap="Wrap"
JustifyContent="SpaceAround" />
</ScrollView>
<ActivityIndicator x:Name="activityIndicator"
IsRunning="True"
VerticalOptions="Center" />
</Grid>
</ContentPage>
The Direction property of this FlexLayout is not set, so it has the default setting of Row , meaning that the
children are arranged in rows and the main axis is horizontal.
The Wrap property is of an enumeration type FlexWrap . If there are too many items to fit on a row, then this
property setting causes the items to wrap to the next row.
Notice that the FlexLayout is a child of a ScrollView . If there are too many rows to fit on the page, then the
ScrollView has a default Orientation property of Vertical and allows vertical scrolling.
The JustifyContent property allocates leftover space on the main axis (the horizontal axis) so that each item is
surrounded by the same amount of blank space.
The code-behind file accesses a collection of sample photos and adds them to the Children collection of the
FlexLayout :
public partial class PhotoWrappingPage : ContentPage
{
// Class for deserializing JSON list of sample bitmaps
[DataContract]
class ImageList
{
[DataMember(Name = "photos")]
public List<string> Photos = null;
}
public PhotoWrappingPage ()
{
InitializeComponent ();
LoadBitmapCollection();
}
activityIndicator.IsRunning = false;
activityIndicator.IsVisible = false;
}
}
<FlexLayout Direction="Column">
</FlexLayout>
Here it is running:
The navigation and aside areas are rendered with a BoxView on the left and right.
The first FlexLayout in the XAML file has a vertical main axis and contains three children arranged in a column.
These are the header, the body of the page, and the footer. The nested FlexLayout has a horizontal main axis with
three children arranged in a row.
Three attached bindable properties are demonstrated in this program:
The Order attached bindable property is set on the first BoxView . This property is an integer with a default
value of 0. You can use this property to change the layout order. Generally developers prefer the content of
the page to appear in markup prior to the navigation items and aside items. Setting the Order property on
the first BoxView to a value less than its other siblings causes it to appear as the first item in the row.
Similarly, you can ensure that an item appears last by setting the Order property to a value greater than its
siblings.
The Basis attached bindable property is set on the two BoxView items to give them a width of 50 pixels.
This property is of type FlexBasis , a structure that defines a static property of type FlexBasis named
Auto , which is the default. You can use Basis to specify a pixel size or a percentage that indicates how
much space the item occupies on the main axis. It is called a basis because it specifies an item size that is the
basis of all subsequent layout.
The Grow property is set on the nested Layout and on the Label child representing the content. This
property is of type float and has a default value of 0. When set to a positive value, all the remaining space
along the main axis is allocated to that item and to siblings with positive values of Grow . The space is
allocated proportionally to the values, somewhat like the star specification in a Grid .
The first Grow attached property is set on the nested FlexLayout , indicating that this FlexLayout is to
occupy all the unused vertical space within the outer FlexLayout . The second Grow attached property is
set on the Label representing the content, indicating that this content is to occupy all the unused
horizontal space within the inner FlexLayout .
There is also a similar Shrink attached bindable property that you can use when the size of children
exceeds the size of the FlexLayout but wrapping is not desired.
Catalog items with FlexLayout
The Catalog Items page in the FlexLayoutDemos sample is similar to Example 1 in Section 1.1 of the CSS Flex
Layout Box specification except that it displays a horizontally scrollable series of pictures and descriptions of three
monkeys:
Each of the three monkeys is a FlexLayout contained in a Frame that is given an explicit height and width, and
which is also a child of a larger FlexLayout . In this XAML file, most of the properties of the FlexLayout children
are specified in styles, all but one of which is an implicit style:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FlexLayoutDemos"
x:Class="FlexLayoutDemos.CatalogItemsPage"
Title="Catalog Items">
<ContentPage.Resources>
<Style TargetType="Frame">
<Setter Property="BackgroundColor" Value="LightYellow" />
<Setter Property="BorderColor" Value="Blue" />
<Setter Property="Margin" Value="10" />
<Setter Property="CornerRadius" Value="15" />
</Style>
<Style TargetType="Label">
<Setter Property="Margin" Value="0, 4" />
</Style>
<Style TargetType="Image">
<Setter Property="FlexLayout.Order" Value="-1" />
<Setter Property="FlexLayout.AlignSelf" Value="Center" />
</Style>
<Style TargetType="Button">
<Setter Property="Text" Value="LEARN MORE" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="White" />
<Setter Property="BackgroundColor" Value="Green" />
<Setter Property="BorderRadius" Value="20" />
</Style>
</ContentPage.Resources>
<ScrollView Orientation="Both">
<FlexLayout>
<Frame WidthRequest="300"
HeightRequest="480">
<FlexLayout Direction="Column">
<Label Text="Seated Monkey"
Style="{StaticResource headerLabel}" />
<Label Text="This monkey is laid back and relaxed, and likes to watch the world go by." />
<Label Text=" • Doesn't make a lot of noise" />
<Label Text=" • Often smiles mysteriously" />
<Label Text=" • Sleeps sitting up" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.SeatedMonkey.jpg}"
WidthRequest="180"
HeightRequest="180" />
<Label FlexLayout.Grow="1" />
<Button />
</FlexLayout>
</Frame>
<Frame WidthRequest="300"
HeightRequest="480">
<FlexLayout Direction="Column">
<Label Text="Banana Monkey"
Style="{StaticResource headerLabel}" />
<Label Text="Watch this monkey eat a giant banana." />
<Label Text=" • More fun than a barrel of monkeys" />
<Label Text=" • Banana not included" />
<Label Text=" • Banana not included" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.Banana.jpg}"
WidthRequest="240"
HeightRequest="180" />
<Label FlexLayout.Grow="1" />
<Button />
</FlexLayout>
</Frame>
<Frame WidthRequest="300"
HeightRequest="480">
<FlexLayout Direction="Column">
<Label Text="Face-Palm Monkey"
Style="{StaticResource headerLabel}" />
<Label Text="This monkey reacts appropriately to ridiculous assertions and actions." />
<Label Text=" • Cynical but not unfriendly" />
<Label Text=" • Seven varieties of grimaces" />
<Label Text=" • Doesn't laugh at your jokes" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.FacePalm.jpg}"
WidthRequest="180"
HeightRequest="180" />
<Label FlexLayout.Grow="1" />
<Button />
</FlexLayout>
</Frame>
</FlexLayout>
</ScrollView>
</ContentPage>
The implicit style for the Image includes settings of two attached bindable properties of Flexlayout :
<Style TargetType="Image">
<Setter Property="FlexLayout.Order" Value="-1" />
<Setter Property="FlexLayout.AlignSelf" Value="Center" />
</Style>
The Order setting of –1 causes the Image element to be displayed first in each of the nested FlexLayout views
regardless of its position within the children collection. The AlignSelf property of Center causes the Image to
be centered within the FlexLayout . This overrides the setting of the AlignItems property, which has a default
value of Stretch , meaning that the Label and Button children are stretched to the full width of the FlexLayout .
Within each of the three FlexLayout views, a blank Label precedes the Button , but it has a Grow setting of 1.
This means that all the extra vertical space is allocated to this blank Label , which effectively pushes the Button to
the bottom.
In XAML, you can specify the value of this property using the enumeration member names in lowercase,
uppercase, or mixed case, or you can use two additional strings shown in parentheses that are the same as the
CSS indicators. (The "column-reverse" and "row -reverse" strings are defined in the FlexDirectionTypeConverter
class used by the XAML parser.)
Here's the Experiment page showing (from left to right), the Row direction, Column direction, and ColumnReverse
direction:
Notice that for the Reverse options, the items start at the right or bottom.
The Wrap property
The Wrap property is of type FlexWrap , an enumeration with three members:
NoWrap , the default
Wrap
Reverse (or "wrap-reverse" in XAML )
From left to right, these screens show the NoWrap , Wrap and Reverse options for 12 children:
When the Wrap property is set to NoWrap and the main axis is constrained (as in this program), and the main axis
is not wide or tall enough to fit all the children, the FlexLayout attempts to make the items smaller, as the iOS
screenshot demonstrates. You can control the shrinkness of the items with the Shrink attached bindable property.
The JustifyContent property
The JustifyContent property is of type FlexJustify , an enumeration with six members:
Start (or "flex-start" in XAML ), the default
Center
End (or "flex-end" in XAML )
SpaceBetween (or "space-between" in XAML )
SpaceAround (or "space-around" in XAML )
SpaceEvenly
This property specifies how the items are spaced on the main axis, which is the horizontal axis in this example:
In all three screenshots, the Wrap property is set to Wrap . The Start default is shown in the previous Android
screenshot. The iOS screenshot here shows the Center option: all the items are moved to the center. The three
other options beginning with the word Space allocate the extra space not occupied by the items. SpaceBetween
allocates the space equally between the items; SpaceAround puts equal space around each item, while SpaceEvenly
puts equal space between each item, and before the first item and after the last item on the row.
The AlignItems property
The AlignItems property is of type FlexAlignItems , an enumeration with four members:
Stretch , the default
Center
Start (or "flex-start" in XAML )
End (or "flex-end" in XAML )
This is one of two properties (the other being AlignContent ) that indicates how children are aligned on the cross
axis. Within each row, the children are stretched (as shown in the previous screenshot), or aligned on the start,
center, or end of each item, as shown in the following three screenshots:
In the iOS screenshot, the tops of all the children are aligned. In the Android screenshots, the items are vertically
centered based on the tallest child. In the UWP screenshot, the bottoms of all the items are aligned.
For any individual item, the AlignItems setting can be overridden with the AlignSelf attached bindable property.
The AlignContent property
The AlignContent property is of type FlexAlignContent , an enumeration with seven members:
Stretch , the default
Center
Start (or "flex-start" in XAML )
End (or "flex-end" in XAML )
SpaceBetween (or "space-between" in XAML )
SpaceAround (or "space-around" in XAML )
SpaceEvenly
Like AlignItems , the AlignContent property also aligns children on the cross axis, but affects entire rows or
columns:
In the iOS screenshot, both rows are at the top; in the Android screenshot they're in the center; and in the UWP
screenshot they're at the bottom. The rows can also be spaced in various ways:
The AlignContent has no effect when there is only one row or column.
For any individual child of the FlexLayout , this property setting overrides the AlignItems property set on the
FlexLayout itself. The default setting of Auto means to use the AlignItems setting.
For a Label element named label (or example), you can set the AlignSelf property in code like this:
FlexLayout.SetAlignSelf(label, FlexAlignSelf.Center);
Notice that there is no reference to the FlexLayout parent of the Label . In XAML, you set the property like this:
In code, you can set the Basis property for a Label named label to 40 device-independent units like this:
The second argument to the FlexBasis constructor is named isRelative and indicates whether the size is
relative ( true ) or absolute ( false ). The argument has a default value of false , so you can also use the following
code:
An implicit conversion from float to FlexBasis is defined, so you can simplify it even further:
FlexLayout.SetBasis(label, 40);
You can set the size to 25% of the FlexLayout parent like this:
The Basis Experiment page of the FlexLayoutDemos sample allows you to experiment with the Basis
property. The page displays a wrapped column of five Label elements with alternating background and
foreground colors. Two Slider elements let you specify Basis values for the second and fourth Label :
The iOS screenshot at the left shows the two Label elements being given heights in device-independent units.
The Android screen shows them being given heights that are a fraction of the total height of the FlexLayout . If the
Basis is set at 100%, then the child is the height of the FlexLayout , and will wrap to the next column and occupy
the entire height of that column, as the UWP screenshot demonstrates: It appears as if the five children are
arranged in a row, but they're actually arranged in five columns.
The Grow Property
The Grow attached bindable property is of type int . The default value is 0, and the value must be greater than or
equal to 0.
The Grow property plays a role when the Wrap property is set to NoWrap and the row of children has a total
width less than the width of the FlexLayout , or the column of children has a shorter height than the FlexLayout .
The Grow property indicates how to apportion the leftover space among the children.
In the Grow Experiment page, five Label elements of alternating colors are arranged in a column, and two
Slider elements allow you to adjust the Grow property of the second and fourth Label . The iOS screenshot at
the far left shows the default Grow properties of 0:
If any one child is given a positive Grow value, then that child takes up all the remaining space, as the Android
screenshot demonstrates. This space can also be allocated among two or more children. In the UWP screenshot,
the Grow property of the second Label is set to 0.5, while the Grow property of the fourth Label is 1.5, which
gives the fourth Label three times as much of the leftover space as the second Label .
How the child view uses that space depends on the particular type of child. For a Label , the text can be positioned
within the total space of the Label using the properties HorizontalTextAlignment and VerticalTextAlignment .
The Shrink Property
The Shrink attached bindable property is of type int . The default value is 1, and the value must be greater than
or equal to 0.
The Shrink property plays a role when the Wrap property is set to NoWrap and the aggregate width of a row of
children is greater than the width of the FlexLayout , or the aggregate height of a single column of children is
greater than the height of the FlexLayout . Normally the FlexLayout will display these children by constricting
their sizes. The Shrink property can indicate which children are given priority in being displayed at their full sizes.
The Shrink Experiment page creates a FlexLayout with a single row of five Label children that require more
space than the FlexLayout width. The iOS screenshot at the left shows all the Label elements with default values
of 1:
In the Android screenshot, the Shrink value for the second Label is set to 0, and that Label is displayed in its
full width. Also, the fourth Label is given a Shrink value greater than one, and it has shrunk. The UWP
screenshot shows both Label elements being given a Shrink value of 0 to allow them to be displayed in their full
size, if that is possible.
You can set both the Grow and Shrink values to accommodate situations where the aggregate child sizes might
sometimes be less than or sometimes greater than the size of the FlexLayout .
The original CatalogItemsPage.xaml file has five Style definitions in its Resources section with 15 Setter
objects. In the CssCatalogItemsPage.xaml file, that has been reduced to two Style definitions with just four
Setter objects. These styles supplement the CSS style sheet for properties that the Xamarin.Forms CSS styling
feature currently doesn't support:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FlexLayoutDemos"
x:Class="FlexLayoutDemos.CssCatalogItemsPage"
Title="CSS Catalog Items">
<ContentPage.Resources>
<StyleSheet Source="CatalogItemsStyles.css" />
<Style TargetType="Frame">
<Setter Property="BorderColor" Value="Blue" />
<Setter Property="CornerRadius" Value="15" />
</Style>
<Style TargetType="Button">
<Setter Property="Text" Value="LEARN MORE" />
<Setter Property="BorderRadius" Value="20" />
</Style>
</ContentPage.Resources>
<ScrollView Orientation="Both">
<FlexLayout>
<Frame>
<FlexLayout Direction="Column">
<Label Text="Seated Monkey" StyleClass="header" />
<Label Text="This monkey is laid back and relaxed, and likes to watch the world go by." />
<Label Text=" • Doesn't make a lot of noise" />
<Label Text=" • Often smiles mysteriously" />
<Label Text=" • Sleeps sitting up" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.SeatedMonkey.jpg}" />
<Label StyleClass="empty" />
<Button />
</FlexLayout>
</Frame>
<Frame>
<FlexLayout Direction="Column">
<Label Text="Banana Monkey" StyleClass="header" />
<Label Text="Watch this monkey eat a giant banana." />
<Label Text=" • More fun than a barrel of monkeys" />
<Label Text=" • Banana not included" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.Banana.jpg}" />
<Label StyleClass="empty" />
<Button />
</FlexLayout>
</Frame>
<Frame>
<FlexLayout Direction="Column">
<Label Text="Face-Palm Monkey" StyleClass="header" />
<Label Text="This monkey reacts appropriately to ridiculous assertions and actions." />
<Label Text=" • Cynical but not unfriendly" />
<Label Text=" • Seven varieties of grimaces" />
<Label Text=" • Doesn't laugh at your jokes" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.FacePalm.jpg}" />
<Label StyleClass="empty" />
<Button />
</FlexLayout>
</Frame>
</FlexLayout>
</ScrollView>
</ContentPage>
The CSS style sheet is referenced in the first line of the Resources section:
<StyleSheet Source="CatalogItemsStyles.css" />
Notice also that two elements in each of the three items include StyleClass settings:
frame {
width: 300;
height: 480;
background-color: lightyellow;
margin: 10;
}
label {
margin: 4 0;
}
label.header {
margin: 8 0;
font-size: large;
color: blue;
}
label.empty {
flex-grow: 1;
}
image {
height: 180;
order: -1;
align-self: center;
}
button {
font-size: large;
color: white;
background-color: green;
}
Several FlexLayout attached bindable properties are referenced here. In the label.empty selector, you'll see the
flex-grow attribute, which styles an empty Label to provide some blank space above the Button . The image
selector contains an order attribute and an align-self attribute, both of which correspond to FlexLayout
attached bindable properties.
You've seen that you can set properties directly on the FlexLayout and you can set attached bindable properties
on the children of a FlexLayout . Or, you can set these properties indirectly using traditional XAML -based styles or
CSS styles. What's important is to know and understand these properties. These properties are what makes the
FlexLayout truly flexible.
Purpose
ScrollView can be used to ensure that larger views display well on smaller phones. For example, a layout that
works on an iPhone 6s may be clipped on an iPhone 4s. Using a ScrollView would allow the clipped portions of
the layout to be displayed on the smaller screen.
Usage
NOTE
ScrollView s should not be nested. In addition, ScrollView s should not be nested with other controls that provide
scrolling, like ListView and WebView .
ScrollView exposes a Content property which can be set to a single view or layout. Consider this example of a
layout with a very large boxView, followed by an Entry :
<ContentPage.Content>
<ScrollView>
<StackLayout>
<BoxView BackgroundColor="Red" HeightRequest="600" WidthRequest="150" />
<Entry />
</StackLayout>
</ScrollView>
</ContentPage.Content>
In C#:
var scroll = new ScrollView();
Content = scroll;
var stack = new StackLayout();
stack.Children.Add(new BoxView { BackgroundColor = Color.Red, HeightRequest = 600, WidthRequest = 600 });
stack.Children.Add(new Entry());
Notice that when the user starts to enter text in the Entry , the view scrolls to keep it visible on screen:
Properties
ScrollView defines the following properties:
ContentSize gets a Size value that represents the size of the content.
Orientation gets or sets a ScrollOrientation enumeration value that represents the scrolling direction of the
ScrollView .
ScrollX gets a doublethat represents the current X scroll position.
ScrollY gets a double that represents the current Y scroll position.
HorizontalScrollBarVisibility gets or sets a ScrollBarVisibility value that represents when the horizontal
scroll bar is visible.
VerticalScrollBarVisibility gets or sets a ScrollBarVisibility value that represents when the vertical scroll
bar is visible.
Methods
ScrollView provides a ScrollToAsync method, which can be used to scroll the view either using coordinates or by
specifying a particular view that should be made visible.
When using coordinates, specify the x and y coordinates, along with a boolean indicating whether the scrolling
should be animated:
scroll.ScrollToAsync(0, 150, true); //scrolls so that the position at 150px from the top is visible
scroll.ScrollToAsync(label, ScrollToPosition.Start, true); //scrolls so that the label is at the start of the
list
When scrolling to a particular element, the ScrollToPosition enumeration specifes where in the view the element
will appear:
Center – scrolls the element to the center of the visible portion of the view.
End – scrolls the element to the end of the visible portion of the view.
MakeVisible – scrolls the element so that it is visible within the view.
Start – scrolls the element to the start of the visible portion of the view.
The IsAnimated property specifies how the view will be scrolled. When set to true, a smooth animation will be
used, rather than instantly moving the content into view.
Events
ScrollView defines just one event, Scrolled . Scrolled is raised when the view has finished scrolling. The event
handler for Scrolled takes ScrolledEventArgs , which has the ScrollX and ScrollY properties. The following
demonstrates how to update a label with the current scroll position of a ScrollView :
Note that scroll positions may be negative, due to the bounce effect when scrolling at the end of a list.
Related Links
Layout (sample)
BusinessTumble Example (sample)
Layout Options in Xamarin.Forms
12/7/2018 • 5 minutes to read • Edit Online
Overview
The LayoutOptions structure encapsulates two layout preferences:
Alignment – the view's preferred alignment, which determines its position and size within its parent layout.
Expansion – used only by a StackLayout , and indicates if the view should use extra space, if it's available.
These layout preferences can be applied to a View , relative to its parent, by setting the HorizontalOptions or
VerticalOptions property of the View to one of the public fields from the LayoutOptions structure. The public
fields are as follows:
Start
Center
End
Fill
StartAndExpand
CenterAndExpand
EndAndExpand
FillAndExpand
The Start , Center , End , and Fill fields are used to define the view's alignment within the parent layout:
For horizontal alignment, Start positions the View on the left hand side of the parent layout, and for vertical
alignment, it positions the View at the top of the parent layout.
For horizontal and vertical alignment, Center horizontally or vertically centers the View .
For horizontal alignment, End positions the View on the right hand side of the parent layout, and for vertical
alignment, it positions the View at the bottom of the parent layout.
For horizontal alignment, Fill ensures that the View fills the width of the parent layout, and for vertical
alignment, it ensures that the View fills the height of the parent layout.
The StartAndExpand , CenterAndExpand , EndAndExpand , and FillAndExpand values are used to define the alignment
preference, and whether the view will occupy more space if available within the parent StackLayout .
NOTE
The default value of a view's HorizontalOptions and VerticalOptions properties is LayoutOptions.Fill .
Alignment
Alignment controls how a view is positioned within its parent layout when the parent layout contains unused
space (that is, the parent layout is larger than the combined size of all its children).
A StackLayout only respects the Start , Center , End , and Fill LayoutOptions fields on child views that are in
the opposite direction to the StackLayout orientation. Therefore, child views within a vertically oriented
StackLayout can set their HorizontalOptions properties to one of the Start , Center , End , or Fill fields.
Similarly, child views within a horizontally oriented StackLayout can set their VerticalOptions properties to one
of the Start , Center , End , or Fill fields.
A StackLayout does not respect the Start , Center , End , and Fill LayoutOptions fields on child views that are
in the same direction as the StackLayout orientation. Therefore, a vertically oriented StackLayout ignores the
Start , Center , End , or Fill fields if they are set on the VerticalOptions properties of child views. Similarly, a
horizontally oriented StackLayout ignores the Start , Center , End , or Fill fields if they are set on the
HorizontalOptions properties of child views.
NOTE
LayoutOptions.Fill generally overrides size requests specified using the HeightRequest and WidthRequest properties.
The following XAML code example demonstrates a vertically oriented StackLayout where each child Label sets
its HorizontalOptions property to one of the four alignment fields from the LayoutOptions structure:
<StackLayout Margin="0,20,0,0">
...
<Label Text="Start" BackgroundColor="Gray" HorizontalOptions="Start" />
<Label Text="Center" BackgroundColor="Gray" HorizontalOptions="Center" />
<Label Text="End" BackgroundColor="Gray" HorizontalOptions="End" />
<Label Text="Fill" BackgroundColor="Gray" HorizontalOptions="Fill" />
</StackLayout>
NOTE
Note that enabling expansion doesn't change the size of a view unless it uses LayoutOptions.FillAndExpand .
The following XAML code example demonstrates a vertically oriented StackLayout where each child Label sets
its VerticalOptions property to one of the four expansion fields from the LayoutOptions structure:
<StackLayout Margin="0,20,0,0">
...
<BoxView BackgroundColor="Red" HeightRequest="1" />
<Label Text="Start" BackgroundColor="Gray" VerticalOptions="StartAndExpand" />
<BoxView BackgroundColor="Red" HeightRequest="1" />
<Label Text="Center" BackgroundColor="Gray" VerticalOptions="CenterAndExpand" />
<BoxView BackgroundColor="Red" HeightRequest="1" />
<Label Text="End" BackgroundColor="Gray" VerticalOptions="EndAndExpand" />
<BoxView BackgroundColor="Red" HeightRequest="1" />
<Label Text="Fill" BackgroundColor="Gray" VerticalOptions="FillAndExpand" />
<BoxView BackgroundColor="Red" HeightRequest="1" />
</StackLayout>
Summary
This article explained the effect that each LayoutOptions structure value has on the alignment and expansion of a
view, relative to its parent. The Start , Center , End , and Fill fields are used to define the view's alignment
within the parent layout, and the StartAndExpand , CenterAndExpand , EndAndExpand , and FillAndExpand fields are
used to define the alignment preference, and to determine whether the view will occupy more space, if available,
within a StackLayout .
Related Links
LayoutOptions (sample)
LayoutOptions
Margin and Padding
7/12/2018 • 2 minutes to read • Edit Online
The Margin and Padding properties control layout behavior when an element is rendered in the user interface.
This article demonstrates the difference between the two properties, and how to set them.
Overview
Margin and padding are related layout concepts:
The Margin property represents the distance between an element and its adjacent elements, and is used to
control the element's rendering position, and the rendering position of its neighbors. Margin values can be
specified on layout and view classes.
The Padding property represents the distance between an element and its child elements, and is used to
separate the control from its own content. Padding values can be specified on layout classes.
The following diagram illustrates the two concepts:
Note that Margin values are additive. Therefore, if two adjacent elements specify a margin of 20 pixels, the
distance between the elements will be 40 pixels. In addition, margin and padding are additive when both are
applied, in that the distance between an element and any content will be the margin plus padding.
Specifying a Thickness
The Margin and Padding properties are both of type Thickness . There are three possibilities when creating a
Thickness structure:
Create a Thickness structure defined by a single uniform value. The single value is applied to the left, top,
right, and bottom sides of the element.
Create a Thickness structure defined by horizontal and vertical values. The horizontal value is symmetrically
applied to the left and right sides of the element, with the vertical value being symmetrically applied to the top
and bottom sides of the element.
Create a Thickness structure defined by four distinct values that are applied to the left, top, right, and bottom
sides of the element.
The following XAML code example shows all three possibilities:
<StackLayout Padding="0,20,0,0">
<Label Text="Xamarin.Forms" Margin="20" />
<Label Text="Xamarin.iOS" Margin="10, 15" />
<Label Text="Xamarin.Android" Margin="0, 20, 15, 5" />
</StackLayout>
NOTE
Thickness values can be negative, which typically clips or overdraws the content.
Summary
This article demonstrated the difference between the Margin and Padding properties, and how to set them. The
properties control layout behavior when an element is rendered in the user interface.
Related Links
Margin
Padding
Thickness
Device Orientation
4/1/2019 • 10 minutes to read • Edit Online
Controlling Orientation
When using Xamarin.Forms, the supported method of controlling device orientation is to use the settings for each
individual project.
iOS
On iOS, device orientation is configured for applications using the Info.plist file. This file will include orientation
settings for iPhone & iPod, as well as settings for iPad if the app includes it as a target. The following are
instructions specific to your IDE. Use the IDE options at the top of this document to select which instructions you'd
like to see:
Visual Studio
Visual Studio for Mac
In Visual Studio, open the iOS project and open Info.plist. The file will open into a configuration panel, starting
with the iPhone Deployment Info tab:
To configure iPad orientation, select the iPad Deployment Info tab at the top left of the panel, then select from
the available orientations:
Android
To control the orientation on Android, open MainActivity.cs and set the orientation using the attribute decorating
the MainActivity class:
namespace MyRotatingApp.Droid
{
[Activity (Label = "MyRotatingApp.Droid", Icon = "@drawable/icon", Theme = "@style/MainTheme",
MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Landscape)] //This is what controls orientation
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate (Bundle bundle)
...
NOTE
There is an existing, free NuGet package for receiving notifications of orientation changes in shared code. See the GitHub
repo for more information.
Alternatively, it's possible to override the OnSizeAllocated method on a Page , inserting any layout change logic
there. The OnSizeAllocated method is called whenever a Page is allocated a new size, which happens whenever
the device is rotated. Note that the base implementation of OnSizeAllocated performs important layout functions,
so it is important to call the base implementation in the override:
Once a change in device orientation has been detected, you may want to add or remove additional views to/from
your user interface to react to the change in available space. For example, consider the built-in calculator on each
platform in portrait:
and landscape:
Notice that the apps take advantage of the available space by adding more functionality in landscape.
Responsive Layout
It is possible to design interfaces using the built-in layouts so that they transition gracefully when the device is
rotated. When designing interfaces that will continue to be appealing when responding to changes in orientation
consider the following general rules:
Pay attention to ratios – changes in orientation can cause problems when certain assumptions are made with
regards to ratios. For example, a view that would have plenty of space in 1/3 of the vertical space of a screen in
portrait may not fit into 1/3 of the vertical space in landscape.
Be careful with absolute values – absolute (pixel) values that make sense in portrait may not make sense in
landscape. When absolute values are necessary, use nested layouts to isolate their impact. For example, it
would be reasonable to use absolute values in a TableView ItemTemplate when the item template has a
guaranteed uniform height.
The above rules also apply when implementing interfaces for multiple screen sizes and are generally considered
best-practice. The rest of this guide will explain specific examples of responsive layouts using each of the primary
layouts in Xamarin.Forms.
NOTE
For clarity, the following sections demonstrate how to implement responsive layouts using just one type of Layout at a
time. In practice, it is often simpler to mix Layout s to achieve a desired layout using the simpler or most intuitive Layout
for each component.
StackLayout
Consider the following application, displayed in portrait:
and landscape:
Some C# is used to change the orientation of outerStack based on the orientation of the device:
</ScrollView>
and landscape:
That is accomplished with the following 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"
x:Class="ResponsiveLayout.GridPageXaml"
Title="Grid - XAML">
<ContentPage.Content>
<Grid x:Name="outerGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Grid x:Name="innerGrid" Grid.Row="0" Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="deer.jpg" Grid.Row="0" Grid.Column="0" HeightRequest="300" WidthRequest="300"
/>
<Grid x:Name="controlsGrid" Grid.Row="0" Grid.Column="1" >
<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" />
<Label Text="Date:" Grid.Row="1" Grid.Column="0" />
<Label Text="Tags:" Grid.Row="2" Grid.Column="0" />
<Entry Grid.Row="0" Grid.Column="1" />
<Entry Grid.Row="1" Grid.Column="1" />
<Entry Grid.Row="2" Grid.Column="1" />
</Grid>
</Grid>
<Grid x:Name="buttonsGrid" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Previous" Grid.Column="0" />
<Button Text="Save" Grid.Column="1" />
<Button Text="Next" Grid.Column="2" />
</Grid>
</Grid>
</ContentPage.Content>
</ContentPage>
Related Links
Layout (sample)
BusinessTumble Example (sample)
Responsive Layout (sample)
Display an Image based on Screen Orientation
Layout for Tablet and Desktop apps
1/29/2019 • 2 minutes to read • Edit Online
Xamarin.Forms supports all device types available on the supported platforms, so in addition to phones, apps can
also run on:
iPads,
Android tablets,
Windows tablets and desktop computers (running Windows 10).
This page briefly discusses:
the supported device types, and
how to optimize layouts for tablets versus phones.
Device Types
Larger screen devices are available for all of the platforms supported by Xamarin.Forms.
iPads (iOS )
The Xamarin.Forms template automatically includes iPad support by configuring the Info.plist > Devices setting
to Universal (which means both iPhone and iPad are supported).
To provide a pleasant startup experience, and ensure the full screen resolution is used on all devices, you should
make sure an iPad-specific launch screen (using a storyboard) is provided. This ensures the app is rendered
correctly on iPad mini, iPad, and iPad Pro devices.
Prior to iOS 9 all apps took up the full screen on the device, but some iPads can now perform split screen
multitasking. This means your app could take up just a slim column on the side of the screen, 50% of the width of
the screen, or the entire screen.
Split-screen functionality means you should design your app to work well with as little as 320 pixels wide, or as
much as 1366 pixels wide.
Android Tablets
The Android ecosystem has a myriad of supported screen sizes, from small phones up to large tablets.
Xamarin.Forms can support all screen sizes, but as with the other platforms you might want to adjust your user
interface for larger devices.
When supporting many different screen resolutions, you can provide your native image resources in different
sizes to optimize the user experience. Review the Android resources documentation (and in particular creating
resources for varying screen sizes) for more information on how to structure the folders and filenames in your
Android app project to include optimized image resources in your app.
Windows Tablets and Desktops
To support tablets and desktop computers running Windows, you'll need to use Windows UWP support, which
builds universal apps that run on Windows 10.
Apps running on Windows tablets and desktops can be resized to arbitrary dimensions in addition to running full-
screen.
Optimizing for Tablet and Desktop
You can adjust your Xamarin.Forms user interface depending on whether a phone or tablet/desktop device is
being used. This means you can optimize the user-experience for large-screen devices such as tablets and desktop
computers.
Device.Idiom
You can use the Device class to change the behavior of your app or user interface. Using the Device.Idiom
enumeration you can
if (Device.Idiom == TargetIdiom.Phone)
{
HeroImage.Source = ImageSource.FromFile("hero.jpg");
} else {
HeroImage.Source = ImageSource.FromFile("herotablet.jpg");
}
This approach can be expanded to make significant changes to individual page layouts, or even to render entirely
different pages on larger screens.
Leveraging MasterDetailPage
The MasterDetailPage is ideal for larger screens, especially on the iPad where it uses the UISplitViewController to
provide a native iOS experience.
Review this Xamarin blog post to see how you can adapt your user interface so that phones use one layout and
larger screens can use another (with the MasterDetailPage ).
Related Links
Xamarin Blog
MyShoppe sample
Bindable Layouts in Xamarin.Forms
4/26/2019 • 4 minutes to read • Edit Online
NOTE
The ItemTemplate property takes precedence when both the ItemTemplate and ItemTemplateSelector properties are
set.
The Layout<T> class exposes a Children collection, to which the child elements of a layout are added. When the
BinableLayout.ItemsSource property is set to a collection of items and attached to a Layout<T> -derived class, each
item in the collection is added to the Layout<T>.Children collection for display by the layout. The Layout<T> -
derived class will then update its child views when the underlying collection changes. For more information about
the Xamarin.Forms layout cycle, see Creating a Custom Layout.
Bindable layouts should only be used when the collection of items to be displayed is small, and scrolling and
selection isn't required. While scrolling can be provided by wrapping a bindable layout in a ScrollView , this is not
recommended as bindable layouts lack UI virtualization. When scrolling is required, a scrollable view that includes
UI virtualization, such as ListView or CollectionView , should be used. Failure to observe this recommendation
can lead to performance issues.
IMPORTANT
While it's technically possible to attach a bindable layout to any layout class that derives from the Layout<T> class, it's not
always practical to do so, particularly for the AbsoluteLayout , Grid , and RelativeLayout classes. For example, consider
the scenario of wanting to display a collection of data in a Grid using a bindable layout, where each item in the collection is
an object containing multiple properties. Each row in the Grid should display an object from the collection, with each
column in the Grid displaying one of the object's properties. Because the DataTemplate for the bindable layout can only
contain a single object, it's necessary for that object to be a layout class containing multiple views that each display one of
the object's properties in a specific Grid column. While this scenario can be realised with bindable layouts, it results in a
parent Grid containing a child Grid for each item in the bound collection, which is a highly inefficient and problematic
use of the Grid layout.
When the BindableLayout.ItemsSource attached property is set on a layout, but the BindableLayout.ItemTemplate
attached property isn't set, every item in the IEnumerable collection will be displayed by a Label that's created by
the BindableLayout class.
In this example, every item in the TopFollowers collection will be displayed by a CircleImage view defined in the
DataTemplate :
For more information about data templates, see Xamarin.Forms Data Templates.
The DataTemplateSelector used in the sample application is shown in the following example:
For more information about data template selectors, see Creating a Xamarin.Forms DataTemplateSelector.
Related links
Bindable Layout Demo (sample)
Creating a Custom Layout
Xamarin.Forms Data Templates
Creating a Xamarin.Forms DataTemplateSelector
Creating a Custom Layout
4/24/2019 • 14 minutes to read • Edit Online
Overview
In Xamarin.Forms, all layout classes derive from the Layout<T> class and constrain the generic type to View and
its derived types. In turn, the Layout<T> class derives from the Layout class, which provides the mechanism for
positioning and sizing child elements.
Every visual element is responsible for determining its own preferred size, which is known as the requested size.
Page , Layout , and Layout<View> derived types are responsible for determining the location and size of their
child, or children, relative to themselves. Therefore, layout involves a parent-child relationship, where the parent
determines what the size of its children should be, but will attempt to accommodate the requested size of the
child.
A thorough understanding of the Xamarin.Forms layout and invalidation cycles is required to create a custom
layout. These cycles will now be discussed.
Layout
Layout begins at the top of the visual tree with a page, and it proceeds through all branches of the visual tree to
encompass every visual element on a page. Elements that are parents to other elements are responsible for sizing
and positioning their children relative to themselves.
The VisualElement class defines a Measure method that measures an element for layout operations, and a
Layout method that specifies the rectangular area the element will be rendered within. When an application
starts and the first page is displayed, a layout cycle consisting first of Measure calls, and then Layout calls, starts
on the Page object:
1. During the layout cycle, every parent element is responsible for calling the Measure method on its children.
2. After the children have been measured, every parent element is responsible for calling the Layout method on
its children.
This cycle ensures that every visual element on the page receives calls to the Measure and Layout methods. The
process is shown in the following diagram:
NOTE
Note that layout cycles can also occur on a subset of the visual tree if something changes to affect the layout. This includes
items being added or removed from a collection such as in a StackLayout , a change in the IsVisible property of an
element, or a change in the size of an element.
Every Xamarin.Forms class that has a Content or a Children property has an overridable LayoutChildren
method. Custom layout classes that derive from Layout<View> must override this method and ensure that the
Measure and Layout methods are called on all the element's children, to provide the desired custom layout.
In addition, every class that derives from Layout or Layout<View> must override the OnMeasure method, which is
where a layout class determines the size that it needs to be by making calls to the Measure methods of its
children.
NOTE
Elements determine their size based on constraints, which indicate how much space is available for an element within the
element's parent. Constraints passed to the Measure and OnMeasure methods can range from 0 to
Double.PositiveInfinity . An element is constrained, or fully constrained, when it receives a call to its Measure
method with non-infinite arguments - the element is constrained to a particular size. An element is unconstrained, or
partially constrained, when it receives a call to its Measure method with at least one argument equal to
Double.PositiveInfinity – the infinite constraint can be thought of as indicating autosizing.
Invalidation
Invalidation is the process by which a change in an element on a page triggers a new layout cycle. Elements are
considered invalid when they no longer have the correct size or position. For example, if the FontSize property
of a Button changes, the Button is said to be invalid because it will no longer have the correct size. Resizing the
Button may then have a ripple effect of changes in layout through the rest of a page.
Elements invalidate themselves by invoking the InvalidateMeasure method, generally when a property of the
element changes that might result in a new size of the element. This method fires the MeasureInvalidated event,
which the element's parent handles to trigger a new layout cycle.
The Layout class sets a handler for the MeasureInvalidated event on every child added to its Content property
or Children collection, and detaches the handler when the child is removed. Therefore, every element in the
visual tree that has children is alerted whenever one of its children changes size. The following diagram illustrates
how a change in the size of an element in the visual tree can cause changes that ripple up the tree:
However, the Layout class attempts to restrict the impact of a change in a child's size on the layout of a page. If
the layout is size constrained, then a child size change does not affect anything higher than the parent layout in
the visual tree. However, usually a change in the size of a layout affects how the layout arranges its children.
Therefore, any change in a layout's size will start a layout cycle for the layout, and the layout will receive calls to
its OnMeasure and LayoutChildren methods.
The Layout class also defines an InvalidateLayout method that has a similar purpose to the InvalidateMeasure
method. The InvalidateLayout method should be invoked whenever a change is made that affects how the
layout positions and sizes its children. For example, the Layout class invokes the InvalidateLayout method
whenever a child is added to or removed from a layout.
The InvalidateLayout can be overridden to implement a cache to minimize repetitive invocations of the Measure
methods of the layout's children. Overriding the InvalidateLayout method will provide a notification of when
children are added to or removed from the layout. Similarly, the OnChildMeasureInvalidated method can be
overridden to provide a notification when one of the layout's children changes size. For both method overrides, a
custom layout should respond by clearing the cache. For more information, see Calculating and Caching Data.
NOTE
When enumerating children in the OnMeasure and LayoutChildren overrides, skip any child whose IsVisible
property is set to false . This will ensure that the custom layout won't leave space for invisible children.
1. [optional] Override the InvalidateLayout method to be notified when children are added to or removed from
the layout. For more information, see Overriding the InvalidateLayout Method.
2. [optional] Override the OnChildMeasureInvalidated method to be notified when one of the layout's children
changes size. For more information, see Overriding the OnChildMeasureInvalidated Method.
NOTE
Note that the OnMeasure override won't be invoked if the size of the layout is governed by its parent, rather than its
children. However, the override will be invoked if one or both of the constraints are infinite, or if the layout class has non-
default HorizontalOptions or VerticalOptions property values. For this reason, the LayoutChildren override can't
rely on child sizes obtained during the OnMeasure method call. Instead, LayoutChildren must invoke the Measure
method on the layout's children, before invoking the Layout method. Alternatively, the size of the children obtained in the
OnMeasure override can be cached to avoid later Measure invocations in the LayoutChildren override, but the layout
class will need to know when the sizes need to be obtained again. For more information, see Calculating and Caching
Layout Data.
The layout class can then be consumed by adding it to a Page , and by adding children to the layout. For more
information, see Consuming the WrapLayout.
Creating a WrapLayout
The sample application demonstrates an orientation-sensitive WrapLayout class that arranges its children
horizontally across the page, and then wraps the display of subsequent children to additional rows.
The WrapLayout class allocates the same amount of space for each child, known as the cell size, based on the
maximum size of the children. Children smaller than the cell size can be positioned within the cell based on their
HorizontalOptions and VerticalOptions property values.
The layoutDataCache field is used to store multiple LayoutData values. When the application starts, two
LayoutData objects will be cached into the layoutDataCache dictionary for the current orientation – one for the
constraint arguments to the OnMeasure override, and one for the width and height arguments to the
LayoutChildren override. When rotating the device into landscape orientation, the OnMeasure override and the
LayoutChildren override will again be invoked, which will result in another two LayoutData objects being cached
into the dictionary. However, when returning the device to portrait orientation, no further calculations are
required because the layoutDataCache already has the required data.
The following code example shows the GetLayoutData method, which calculates the properties of the LayoutData
structured based on a particular size:
LayoutData GetLayoutData(double width, double height)
{
Size size = new Size(width, height);
int visibleChildCount = 0;
Size maxChildSize = new Size();
int rows = 0;
int columns = 0;
LayoutData layoutData = new LayoutData();
if (visibleChildCount != 0)
{
// Calculate the number of rows and columns.
if (Double.IsPositiveInfinity(width))
{
columns = visibleChildCount;
rows = 1;
}
else
{
columns = (int)((width + ColumnSpacing) / (maxChildSize.Width + ColumnSpacing));
columns = Math.Max(1, columns);
rows = (visibleChildCount + columns - 1) / columns;
}
if (Double.IsPositiveInfinity(width))
cellSize.Width = maxChildSize.Width;
else
cellSize.Width = (width - ColumnSpacing * (columns - 1)) / columns;
if (Double.IsPositiveInfinity(height))
cellSize.Height = maxChildSize.Height;
else
cellSize.Height = (height - RowSpacing * (rows - 1)) / rows;
layoutDataCache.Add(size, layoutData);
return layoutData;
}
The GetLayoutData method performs the following operations:
It determines whether a calculated LayoutData value is already in the cache and returns it if it's available.
Otherwise, it enumerates through all the children, invoking the Measure method on each child with an infinite
width and height, and determines the maximum child size.
Provided that there's at least one visible child, it calculates the number of rows and columns required, and then
calculates a cell size for the children based on the dimensions of the WrapLayout . Note that the cell size is
usually slightly wider than the maximum child size, but that it could also be smaller if the WrapLayout isn't
wide enough for the widest child or tall enough for the tallest child.
It stores the new LayoutData value in the cache.
Adding Properties Backed by Bindable Properties
The WrapLayout class defines ColumnSpacing and RowSpacing properties, whose values are used to separate the
rows and columns in the layout, and which are backed by bindable properties. The bindable properties are shown
in the following code example:
The property-changed handler of each bindable property invokes the InvalidateLayout method override to
trigger a new layout pass on the WrapLayout . For more information, see Overriding the InvalidateLayout Method
and Overriding the OnChildMeasureInvalidated Method.
Overriding the OnMeasure Method
The OnMeasure override is shown in the following code example:
The override invokes the GetLayoutData method and constructs a SizeRequest object from the returned data,
while also taking into account the RowSpacing and ColumnSpacing property values. For more information about
the GetLayoutData method, see Calculating and Caching Data.
IMPORTANT
The Measure and OnMeasure methods should never request an infinite dimension by returning a SizeRequest value
with a property set to Double.PositiveInfinity . However, at least one of the constraint arguments to OnMeasure can
be Double.PositiveInfinity .
if (layoutData.VisibleChildCount == 0)
{
return;
}
double xChild = x;
double yChild = y;
int row = 0;
int column = 0;
The override begins with a call to the GetLayoutData method, and then enumerates all of the children to size and
position them within each child's cell. This is achieved by invoking the LayoutChildIntoBoundingRegion method,
which is used to position a child within a rectangle based on its HorizontalOptions and VerticalOptions property
values. This is equivalent to making a call to the child's Layout method.
NOTE
Note that the rectangle passed to the LayoutChildIntoBoundingRegion method includes the whole area in which the
child can reside.
For more information about the GetLayoutData method, see Calculating and Caching Data.
Overriding the InvalidateLayout Method
The InvalidateLayout override is invoked when children are added to or removed from the layout, or when one
of the WrapLayout properties changes value, as shown in the following code example:
The override invalidates the layout and discards all the cached layout information.
NOTE
To stop the Layout class invoking the InvalidateLayout method whenever a child is added to or removed from a
layout, override the ShouldInvalidateOnChildAdded and ShouldInvalidateOnChildRemoved methods, and return
false . The layout class can then implement a custom process when children are added or removed.
The override invalidates the child layout, and discards all of the cached layout information.
Consuming the WrapLayout
The WrapLayout class can be consumed by placing it on a Page derived type, as demonstrated in the following
XAML code example:
public ImageWrapLayoutPageCS()
{
wrapLayout = new WrapLayout();
Children can then be added to the WrapLayout as required. The following code example shows Image elements
being added to the WrapLayout :
return null;
}
When the page containing the WrapLayout appears, the sample application asynchronously accesses a remote
JSON file containing a list of photos, creates an Image element for each photo, and adds it to the WrapLayout .
This results in the appearance shown in the following screenshots:
The following screenshots show the WrapLayout after it's been rotated to landscape orientation:
The number of columns in each row depends on the photo size, the screen width, and the number of pixels per
device-independent unit. The Image elements asynchronously load the photos, and therefore the WrapLayout
class will receive frequent calls to its LayoutChildren method as each Image element receives a new size based
on the loaded photo.
Related Links
WrapLayout (sample)
Custom Layouts
Creating Custom Layouts in Xamarin.Forms (video)
Layout
Layout
VisualElement
Layout Compression
12/7/2018 • 4 minutes to read • Edit Online
Overview
Xamarin.Forms performs layout using two series of recursive method calls:
Layout begins at the top of the visual tree with a page, and it proceeds through all branches of the visual tree to
encompass every visual element on a page. Elements that are parents to other elements are responsible for
sizing and positioning their children relative to themselves.
Invalidation is the process by which a change in an element on a page triggers a new layout cycle. Elements are
considered invalid when they no longer have the correct size or position. Every element in the visual tree that
has children is alerted whenever one of its children changes sizes. Therefore, a change in the size of an element
in the visual tree can cause changes that ripple up the tree.
For more information about how Xamarin.Forms performs layout, see Creating a Custom Layout.
The result of the layout process is a hierarchy of native controls. However, this hierarchy includes additional
container renderers and wrappers for platform renderers, further inflating the view hierarchy nesting. The deeper
the level of nesting, the greater the amount of work that Xamarin.Forms has to perform to display a page. For
complex layouts, the view hierarchy can be both deep and broad, with multiple levels of nesting.
For example, consider the following button from the sample application for logging into Facebook:
This button is specified as a custom control with the following XAML view hierarchy:
<ContentView ...>
<StackLayout>
<StackLayout ...>
<AbsoluteLayout ...>
<Button ... />
<Image ... />
<Image ... />
<BoxView ... />
<Label ... />
<Button ... />
</AbsoluteLayout>
</StackLayout>
<Label ... />
</StackLayout>
</ContentView>
The resulting nested view hierarchy can be examined with Xamarin Inspector. On Android, the nested view
hierarchy contains 17 views:
Layout compression, which is available for Xamarin.Forms applications on the iOS and Android platforms, aims to
flatten the view nesting by removing specified layouts from the visual tree, which can improve page-rendering
performance. The performance benefit that's delivered varies depending on the complexity of a page, the version
of the operating system being used, and the device on which the application is running. However, the biggest
performance gains will be seen on older devices.
NOTE
While this article focuses on the results of applying layout compression on Android, it's equally applicable to iOS.
Layout Compression
In XAML, layout compression can be enabled by setting the CompressedLayout.IsHeadless attached property to
true on a layout class:
<StackLayout CompressedLayout.IsHeadless="true">
...
</StackLayout>
Alternatively, it can be enabled in C# by specifying the layout instance as the first argument to the
CompressedLayout.SetIsHeadless method:
CompressedLayout.SetIsHeadless(stackLayout, true);
IMPORTANT
Since layout compression removes a layout from the visual tree, it's not suitable for layouts that have a visual appearance, or
that obtain touch input. Therefore, layouts that set VisualElement properties (such as BackgroundColor , IsVisible ,
Rotation , Scale , TranslationX and TranslationY or that accept gestures, are not candidates for layout
compression. However, enabling layout compression on a layout that sets visual appearance properties, or that accepts
gestures, will not result in a build or runtime error. Instead, layout compression will be applied and visual appearance
properties, and gesture recognition, will silently fail.
For the Facebook button, layout compression can be enabled on the three layout classes:
<StackLayout CompressedLayout.IsHeadless="true">
<StackLayout CompressedLayout.IsHeadless="true" ...>
<AbsoluteLayout CompressedLayout.IsHeadless="true" ...>
...
</AbsoluteLayout>
</StackLayout>
...
</StackLayout>
Compared to the original nested view hierarchy of 17 views, this represents a reduction in the number of views of
17%. While this reduction may appear insignificant, the view reduction over an entire page can be more
significant.
Fast Renderers
Fast renderers reduce the inflation and rendering costs of Xamarin.Forms controls on Android by flattening the
resulting native view hierarchy. This further improves performance by creating fewer objects, which in turn results
in a less complex visual tree and less memory use. For more information about fast renderers, see Fast Renderers.
For the Facebook button in the sample application, combining layout compression and fast renderers produces a
nested view hierarchy of 8 views:
Compared to the original nested view hierarchy of 17 views, this represents a reduction of 52%.
The sample application contains a page extracted from a real application. Without layout compression and fast
renderers, the page produces a nested view hierarchy of 130 views on Android. Enabling fast renderers and layout
compression on appropriate layout classes reduces the nested view hierarchy to 70 views, a reduction of 46%.
Summary
Layout compression removes specified layouts from the visual tree in an attempt to improve page rendering
performance. The performance benefit that this delivers varies depending on the complexity of a page, the version
of the operating system being used, and the device on which the application is running. However, the biggest
performance gains will be seen on older devices.
Related Links
Creating a Custom Layout
Fast Renderers
LayoutCompression (sample)
Xamarin.Forms ListView
3/21/2019 • 2 minutes to read • Edit Online
IMPORTANT
CollectionView is a view for presenting lists of data using different layout specifications. It aims to provide a more
flexible, and performant alternative to ListView . For more information, see Xamarin.Forms CollectionView.
Use Cases
Make sure ListView is the right control for your needs. ListView can be used in any situation where you are
displaying scrollable lists of data. ListViews support context actions and data binding.
ListView should not be confused with TableView. The TableView control is a better option whenever you have a
non-bound list of options or data. For example, the iOS settings app, which has a mostly predefined set of
options, is better suited to use TableView than ListView.
Also note that a ListView is best suited for homogeneous data – that is, all data should be of the same type. This
is because only one type of cell can be used for each row in the list. TableViews can support multiple cell types, so
they are a better option when you need to mix views.
Components
ListView has a number of components available to exercise the native functionality of each platform. Each of
these components is described below:
Headers and Footers – Text or view to display at the beginning and end of a list, separate from list's data.
Headers and footers can be bound to a data source independently from the ListView's data source.
Groups – Data in a ListView can be grouped for easier navigation. Groups are typically data bound:
Cells – Data in a ListView is presented in cells. Each cell corresponds to a row of data. There are built-in cells
to choose from, or you can define your own custom cell. Both built-in and custom cells can be used/defined in
XAML or code.
Built-in – Built in cells, especially TextCell and ImageCell, can be great for performance, since they
correspond to native controls on each platform.
TextCell – Displays a string of text, optionally with detail text. Detail text is rendered as a second
line in a smaller font with an accent color.
ImageCell – Displays an image with text. Appears as a TextCell with an image on the left.
Custom Cells – Custom cells are great when you need to present complex data. For example, a custom
view could be used to present a list of songs, including album and artist:
To learn more about customizing cells in a ListView, see Customizing ListView Cell Appearance.
Functionality
ListView supports a number of interaction styles, including:
Pull-to-Refresh – ListView supports pull-to-refresh on each platform.
Context Actions – ListView supports taking action on individual items in a list. For example, you can
implement swipe-to-action on iOS, or long-tap actions on Android.
Selection – You can listen for selections and deselections to take action when a row is tapped.
To learn more about the interactivity features of ListView, see Actions & Interactivity with ListView.
Related Links
Working With ListView (sample)
Two Way Binding (sample)
Built In Cells (sample)
Custom Cells (sample)
Grouping (sample)
Custom Renderer View (sample)
ListView Interactivity (sample)
ListView Data Sources
4/26/2019 • 2 minutes to read • Edit Online
ItemsSource
A ListViewis populated with data using the ItemsSource property, which can accept any collection implementing
IEnumerable . The simplest way to populate a ListView involves using an array of strings:
<ListView>
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>mono</x:String>
<x:String>monodroid</x:String>
<x:String>monotouch</x:String>
<x:String>monorail</x:String>
<x:String>monodevelop</x:String>
<x:String>monotone</x:String>
<x:String>monopoly</x:String>
<x:String>monomodal</x:String>
<x:String>mononucleosis</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
Data Binding
Data binding is the "glue" that binds the properties of a user interface object to the properties of some CLR object,
such as a class in your ViewModel. Data binding is useful because it simplifies the development of user interfaces
by replacing a lot of boring boilerplate code.
Data binding works by keeping objects in sync as their bound values change. Instead of having to write event
handlers for every time a control's value changes, you establish the binding and enable binding in your ViewModel.
For more information on data binding, see Data Binding Basics which is part four of the Xamarin.Forms XAML
Basics article series.
Binding Cells
Properties of cells (and children of cells) can be bound to properties of objects in the ItemsSource . For example, a
ListView could be used to present a list of employees.
The employee class:
public EmployeeListPage()
{
//defined in XAML to follow
EmployeeView.ItemsSource = employees;
...
}
public EmployeeListPage()
{
...
employees.Add(new Employee{ DisplayName="Rob Finnerty"});
employees.Add(new Employee{ DisplayName="Bill Wrestler"});
employees.Add(new Employee{ DisplayName="Dr. Geri-Beth Hooper"});
employees.Add(new Employee{ DisplayName="Dr. Keith Joyce-Purdy"});
employees.Add(new Employee{ DisplayName="Sheri Spruce"});
employees.Add(new Employee{ DisplayName="Burt Indybrick"});
}
This XAML example defines a ContentPage that contains a ListView . The data source of the ListView is set via
the ItemsSource attribute. The layout of each row in the ItemsSource is defined within the ListView.ItemTemplate
element. This results in the following screenshots:
Binding SelectedItem
Often you'll want to bind to the selected item of a ListView , rather than use an event handler to respond to
changes. To do this in XAML, bind the SelectedItem property:
<ListView x:Name="listView"
SelectedItem="{Binding Source={x:Reference SomeLabel},
Path=Text}">
…
</ListView>
Assuming listView 's ItemsSource is a list of strings, SomeLabel will have its text property bound to the
SelectedItem .
Related Links
Two Way Binding (sample)
Customizing ListView Cell Appearance
2/7/2019 • 5 minutes to read • Edit Online
Built in Cells
Xamarin.Forms comes with built-in cells that work for many simple applications:
TextCell – for displaying text
ImageCell – for displaying an image with text.
Two additional cells, SwitchCell and EntryCell are available, however they aren't commonly used with
ListView . See TableView for more information about these cells.
TextCell
TextCell is a cell for displaying text, optionally with a second line as detail text.
TextCells are rendered as native controls at runtime, so performance is very good compared to a custom
ViewCell . TextCells are customizable, allowing you to set:
Text – the text that is shown on the first line, in large font.
Detail – the text that is shown underneath the first line, in a smaller font.
TextColor – the color of the text.
DetailColor – the color of the detail text
ImageCell
ImageCell , like TextCell , can be used for displaying text and secondary detail text, and it offers great
performance by using each platform's native controls. ImageCell differs from TextCell in that it displays an
image to the left of the text.
ImageCell is useful when you need to display a list of data with a visual aspect, such as a list of contacts or
movies. ImageCells are customizable, allowing you to set:
Text – the text that is shown on the first line, in large font
Detail – the text that is shown underneath the first line, in a smaller font
TextColor – the color of the text
DetailColor – the color of the detail text
ImageSource – the image to display next to the text
Custom Cells
When the built-in cells don't provide the required layout, custom cells implemented the required layout. For
example, you may want to present a cell with two labels that have equal weight. A TextCell would be insufficient
because the TextCell has one label that is smaller. Most cell customizations add additional read-only data (such
as additional labels, images or other display information).
All custom cells must derive from ViewCell , the same base class that all of the built-in cell types use.
Xamarin.Forms 2 introduced a new caching behavior on the ListView control which can be set to improve
scrolling performance for some types of custom cells.
This is an example of a custom cell:
XAML
The XAML to create the above layout is below:
//set bindings
left.SetBinding (Label.TextProperty, "title");
right.SetBinding (Label.TextProperty, "subtitle");
image.SetBinding (Image.SourceProperty, "image");
In your constructor for the page with the ListView , set the ListView's ItemTemplate property to a new
DataTemplate :
Note that the constructor for DataTemplate takes a type. The typeof operator gets the CLR type for CustomCell .
Binding Context Changes
When binding to a custom cell type's BindableProperty instances, the UI controls displaying the
BindableProperty values should use the OnBindingContextChanged override to set the data to be displayed in each
cell, rather than the cell constructor, as demonstrated in the following code example:
if (BindingContext != null) {
nameLabel.Text = Name;
ageLabel.Text = Age.ToString ();
locationLabel.Text = Location;
}
}
}
The OnBindingContextChanged override will be called when the BindingContextChanged event fires, in response to
the value of the BindingContext property changing. Therefore, when the BindingContext changes, the UI controls
displaying the BindableProperty values should set their data. Note that the BindingContext should be checked
for a null value, as this can be set by Xamarin.Forms for garbage collection, which in turn will result in the
OnBindingContextChanged override being called.
Alternatively, UI controls can bind to the BindableProperty instances to display their values, which removes the
need to override the OnBindingContextChanged method.
NOTE
When overriding OnBindingContextChanged , ensure that the base class's OnBindingContextChanged method is called so
that registered delegates receive the BindingContextChanged event.
In XAML, binding the custom cell type to data can be achieved as shown in the following code example:
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<local:CustomCell Name="{Binding Name}" Age="{Binding Age}" Location="{Binding Location}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This binds the Name , Age , and Location bindable properties in the CustomCell instance, to the Name , Age , and
Location properties of each object in the underlying collection.
On iOS and Android, if the ListView is recycling elements and the custom cell uses a custom renderer, the
custom renderer must correctly implement property change notification. When cells are reused their property
values will change when the binding context is updated to that of an available cell, with PropertyChanged events
being raised. For more information, see Customizing a ViewCell. For more information about cell recycling, see
Caching Strategy.
Related Links
Built in Cells (sample)
Custom Cells (sample)
Binding Context Changed (sample)
Customizing ListView Appearance
3/14/2019 • 6 minutes to read • Edit Online
Grouping
Often, large sets of data can become unwieldy when presented in a continuously scrolling list. Enabling grouping
can improve the user experience in these cases by better organizing the content and activating platform-specific
controls that make navigating data easier.
When grouping is activated for a ListView , a header row is added for each group.
To enable grouping:
Create a list of lists (a list of groups, each group being a list of elements).
Set the ListView 's ItemsSource to that list.
Set IsGroupingEnabled to true.
Set GroupDisplayBinding to bind to the property of the groups that is being used as the title of the group.
[Optional] Set GroupShortNameBinding to bind to the property of the groups that is being used as the short name
for the group. The short name is used for the jump lists (right-side column on iOS ).
Start by creating a class for the groups:
In the above code, All is the list that will be given to our ListView as the binding source. Title and ShortName
are the properties that will be used for group headings.
At this stage, All is an empty list. Add a static constructor so that the list will be populated at program start:
static PageTypeGroup()
{
List<PageTypeGroup> Groups = new List<PageTypeGroup> {
new PageTypeGroup ("Alfa", "A"){
new PageModel("Amelia", "Cedar", new switchCellPage(),""),
new PageModel("Alfie", "Spruce", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Ava", "Pine", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Archie", "Maple", new switchCellPage(), "grapefruit.jpg")
},
new PageTypeGroup ("Bravo", "B"){
new PageModel("Brooke", "Lumia", new switchCellPage(),""),
new PageModel("Bobby", "Xperia", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Bella", "Desire", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Ben", "Chocolate", new switchCellPage(), "grapefruit.jpg")
}
}
All = Groups; //set the publicly accessible list
}
In the above code, we can also call Add on elements of groups , which are instances of type PageTypeGroup . This is
possible because PageTypeGroup inherits from List<PageModel> . This is an example of the list of lists pattern noted
above.
Here is the XAML for displaying the grouped list:
In XAML:
<ListView.Header>
<StackLayout Orientation="Horizontal">
<Label Text="Header"
TextColor="Olive"
BackgroundColor="Red" />
</StackLayout>
</ListView.Header>
<ListView.Footer>
<StackLayout Orientation="Horizontal">
<Label Text="Footer"
TextColor="Gray"
BackgroundColor="Blue" />
</StackLayout>
</ListView.Footer>
Scrollbar Visibility
ListView has and VerticalScrollBarVisibility properties, which get or set a
HorizontalScrollBarVisibility
ScrollBarVisibility value that represents when the horizontal, or vertical, scroll bar is visible. Both properties can
be set to the following values:
Default indicates the default scroll bar behavior for the platform, and is the default value for the
HorizontalScrollBarVisibility and VerticalScrollBarVisibility properties.
Always indicates that scroll bars will be visible, even when the content fits in the view.
Never indicates that scroll bars will not be visible, even if the content doesn't fit in the view.
Row Separators
Separator lines are displayed between ListView elements by default on iOS and Android. If you'd prefer to hide
the separator lines on iOS and Android, set the SeparatorVisibility property on your ListView. The options for
SeparatorVisibility are:
SepratorDemoListView.SeparatorVisibility = SeparatorVisibility.Default;
XAML:
<ListView x:Name="SeparatorDemoListView" SeparatorVisibility="Default" />
None:
C#:
SepratorDemoListView.SeparatorVisibility = SeparatorVisibility.None;
XAML:
SepratorDemoListView.SeparatorColor = Color.Green;
XAML:
Row Heights
All rows in a ListView have the same height by default. ListView has two properties that can be used to change that
behavior:
HasUnevenRows – true / false value, rows have varying heights if set to true . Defaults to false .
RowHeight – sets the height of each row when HasUnevenRows is false .
You can set the height of all rows by setting the RowHeight property on the ListView .
Custom Fixed Row Height
C#:
RowHeightDemoListView.RowHeight = 100;
XAML:
RowHeightDemoListView.HasUnevenRows = true;
XAML:
The OnImageTapped event handler is executed in response to an Image in a cell being tapped, and increases the size
of the Image displayed in the cell so that it's easily viewed.
Note that there is a strong possibility of performance degradation if this feature is overused.
Related Links
Grouping (sample)
Custom Renderer View (sample)
Dynamic Resizing of Rows (sample)
1.4 release notes
1.3 release notes
ListView Interactivity
3/6/2019 • 5 minutes to read • Edit Online
Single indicates that a single item can be selected, with the selected item being highlighted. This is the default
value.
None indicates that items cannot be selected.
When a user taps an item, two events are fired:
ItemSelected fires when a new item is selected.
ItemTapped fires when an item is tapped.
Tapping the same item twice will fire two ItemTapped events, but will only fire a single ItemSelected event.
NOTE
The ItemTappedEventArgs class, which contains the event arguments for the ItemTapped event, has Group and Item
properties, and an ItemIndex property whose value represents the index in the ListView of the tapped item. Similarly,
the SelectedItemChangedEventArgs class, which contains the event arguments for the ItemSelected event, has a
SelectedItem property, and a SelectedItemIndex property whose value represents the index in the ListView of the
selected item.
When the SelectionMode property is set to Single , items in the ListView can be selected, the ItemSelected and
ItemTapped events will be fired, and the SelectedItem property will be set to the value of the selected item.
When the SelectionMode property is set to None , items in the ListView cannot be selected, the ItemSelected
event will not be fired, and the SelectedItem property will remain null . However, ItemTapped events will still be
fired and the tapped item will be briefly highlighted during the tap.
When an item has been selected and the SelectionMode property is changed from Single to None , the
SelectedItem property will be set to null and the ItemSelected event will be fired with a null item.
The following screenshots show a ListView with the default selection mode:
Disabling Selection
To disable ListView selection set the SelectionMode property to None :
Context Actions
Often, users will want to take action on an item in a ListView . For example, consider a list of emails in the Mail
app. On iOS, you can swipe to delete a message::
Context actions can be implemented in C# and XAML. Below you'll find specific guides for both, but first let's take
a look at some key implementation details for both.
Context Actions are created using MenuItem s. Tap events for MenuItems are raised by the MenuItem itself, not the
ListView. This is different from how tap events are handled for cells, where the ListView raises the event rather
than the cell. Because the ListView is raising the event, its event handler is given key information, like which item
was selected or tapped.
By default, a MenuItem has no way of knowing which cell it belongs to. CommandParameter is available on MenuItem
to store objects, such as the object behind the MenuItem's ViewCell. CommandParameter can be set in both XAML
and C#.
C#
Context actions can be implemented in any Cell subclass (as long as it isn't being used as a group header) by
creating MenuItem s and adding them to the ContextActions collection for the cell. You have the following
properties can be configured for the context action:
Text – the string that appears in the menu item.
Clicked – the event when the item is clicked.
IsDestructive – (optional) when true the item is rendered differently on iOS.
Multiple context actions can be added to a cell, however only one should have IsDestructive set to true . The
following code demonstrates how context actions would be added to a ViewCell :
var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true }; // red background
deleteAction.SetBinding (MenuItem.CommandParameterProperty, new Binding ("."));
deleteAction.Clicked += async (sender, e) => {
var mi = ((MenuItem)sender);
Debug.WriteLine("Delete Context Action clicked: " + mi.CommandParameter);
};
// add to the ViewCell's ContextActions property
ContextActions.Add (moreAction);
ContextActions.Add (deleteAction);
XAML
MenuItem s can also be created in a XAML collection declaratively. The XAML below demonstrates a custom cell
with two context actions implemented:
<ListView x:Name="ContextDemoList">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Clicked="OnMore" CommandParameter="{Binding .}"
Text="More" />
<MenuItem Clicked="OnDelete" CommandParameter="{Binding .}"
Text="Delete" IsDestructive="True" />
</ViewCell.ContextActions>
<StackLayout Padding="15,0">
<Label Text="{Binding title}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
NOTE
The NavigationPageRenderer for Android has an overridable UpdateMenuItemIcon method that can be used to load icons
from a custom Drawable . This override makes it possible to use SVG images as icons on MenuItem instances on Android.
Pull to Refresh
Users have come to expect that pulling down on a list of data will refresh that list. ListView supports this out-of-
the-box. To enable pull-to-refresh functionality, set IsPullToRefreshEnabled to true :
<ListView ...
IsPullToRefreshEnabled="true" />
listView.IsPullToRefreshEnabled = true;
A spinner appears during the refresh, which is black by default. However, the spinner color can be changed on iOS
and Android by setting the RefreshControlColor property to a Color :
<ListView ...
IsPullToRefreshEnabled="true"
RefreshControlColor="Red" />
listView.RefreshControlColor = Color.Red;
ListView fires the Refreshing event to initiate the refresh, and the IsRefreshing property will be set to true .
Whatever code is required to refresh the contents of the ListView should then be executed by the event handler
for the Refreshing event, or by the method executed by the RefreshCommand . Once the ListView is refreshed, the
IsRefreshing property should be set to false , or the EndRefresh method should be called, to indicate that the
refresh is complete.
NOTE
When defining a RefreshCommand , the CanExecute method of the command can be specified to enable or disable the
command.
Related Links
ListView Interactivity (sample)
ListView Performance
12/7/2018 • 7 minutes to read • Edit Online
Caching Strategy
ListViews are often used to display much more data than can fit onscreen. Consider a music app, for example. A
library of songs may have thousands of entries. The simple approach, which would be to create a row for every
song, would have poor performance. That approach wastes valuable memory and can slow scrolling to a crawl.
Another approach is to create and destroy rows as data is scrolled into view. This requires constant instantiation
and cleanup of view objects, which can be very slow.
To conserve memory, the native ListView equivalents for each platform have built-in features for re-using rows.
Only the cells visible on screen are loaded in memory and the content is loaded into existing cells. This prevents
the application from needing to instantiate thousands of objects, saving time and memory.
Xamarin.Forms permits ListView cell re-use through the ListViewCachingStrategy enumeration, which has the
following values:
NOTE
The Universal Windows Platform (UWP) ignores the RetainElement caching strategy, because it always uses caching to
improve performance. Therefore, by default it behaves as if the RecycleElement caching strategy is applied.
RetainElement
The RetainElement caching strategy specifies that the ListView will generate a cell for each item in the list, and is
the default ListView behavior. It should generally be used in the following circumstances:
When each cell has a large number of bindings (20-30+).
When the cell template changes frequently.
When testing reveals that the RecycleElement caching strategy results in a reduced execution speed.
It's important to recognize the consequences of the RetainElement caching strategy when working with custom
cells. Any cell initialization code will need to run for each cell creation, which may be multiple times per second. In
this circumstance, layout techniques that were fine on a page, like using multiple nested StackLayout instances,
become performance bottlenecks when they are setup and destroyed in real time as the user scrolls.
RecycleElement
The RecycleElement caching strategy specifies that the ListView will attempt to minimize its memory footprint
and execution speed by recycling list cells. This mode does not always offer a performance improvement, and
testing should be performed to determine any improvements. However, it is generally the preferred choice, and
should be used in the following circumstances:
When each cell has a small to moderate number of bindings.
When each cell's BindingContext defines all of the cell data.
When each cell is largely similar, with the cell template unchanging.
During virtualization the cell will have its binding context updated, and so if an application uses this mode it must
ensure that binding context updates are handled appropriately. All data about the cell must come from the binding
context or consistency errors may occur. This can be accomplished by using data binding to display cell data.
Alternatively, cell data should be set in the OnBindingContextChanged override, rather than in the custom cell's
constructor, as demonstrated in the following code example:
public CustomCell ()
{
image = new Image();
View = image;
}
RecycleElementAndDataTemplate
The RecycleElementAndDataTemplate caching strategy builds on the RecycleElement caching strategy by additionally
ensuring that when a ListView uses a DataTemplateSelector to select a DataTemplate , DataTemplate s are cached
by the type of item in the list. Therefore, DataTemplate s are selected once per item type, instead of once per item
instance.
NOTE
The RecycleElementAndDataTemplate caching strategy has a pre-requisite that the DataTemplate s returned by the
DataTemplateSelector must use the DataTemplate constructor that takes a Type .
<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This has the same effect as setting the caching strategy argument in the constructor in C#; note that there is no
CachingStrategy property on ListView .
Then the ListViewCachingStrategy enumeration value can be specified from XAML by using the x:Arguments
syntax:
<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
</local:CustomListView>
Maps initialization
When adding maps to a Xamarin.Forms application, Xamarin.Forms.Maps is a separate NuGet package that
you should add to every project in the solution. On Android, this also has a dependency on GooglePlayServices
(another NuGet) which is downloaded automatically when you add Xamarin.Forms.Maps.
After installing the NuGet package, some initialization code is required in each application project, after the
Xamarin.Forms.Forms.Init method call. For iOS use the following code:
Xamarin.FormsMaps.Init();
Xamarin.FormsMaps.Init(this, bundle);
For the Universal Windows Platform (UWP ) use the following code:
Xamarin.FormsMaps.Init("INSERT_AUTHENTICATION_TOKEN_HERE");
Platform configuration
Additional configuration steps are required on some platforms before the map will display.
iOS
To access location services on iOS, you must set the following keys in Info.plist:
iOS 11
NSLocationWhenInUseUsageDescription– for using location services when the app is in use
NSLocationAlwaysAndWhenInUseUsageDescription – for using location services at all times
iOS 10 and earlier
NSLocationWhenInUseUsageDescription – for using location services when the app is in use
NSLocationAlwaysUsageDescription – for using location services at all times
To support iOS 11 and earlier, you can include all three keys: NSLocationWhenInUseUsageDescription ,
NSLocationAlwaysAndWhenInUseUsageDescription , and NSLocationAlwaysUsageDescription .
The XML representation for these keys in Info.plist is shown below. You should update the string values to
reflect how your application is using the location information:
<key>NSLocationAlwaysUsageDescription</key>
<string>Can we use your location at all times?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can we use your location when your app is being used?</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Can we use your location at all times?</string>
The Info.plist entries can also be added in Source view while editing the Info.plist file:
Android
To use the Google Maps API v2 on Android you must generate an API key and add it to your Android project.
Follow the instructions in the Xamarin doc on obtaining a Google Maps API v2 key. After following those
instructions, paste the API key in the Properties/AndroidManifest.xml file (view source and find/update the
following element):
<application ...>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR_API_KEY" />
</application>
Without a valid API key the maps control will display as a gray box on Android.
NOTE
Note that, in order for your APK to access Google Maps, you must include SHA-1 fingerprints and package names for
every keystore (debug and release) that you use to sign your APK. For example, if you use one computer for debug and
another computer for generating the release APK, you should include the SHA-1 certificate fingerprint from the debug
keystore of the first computer and the SHA-1 certificate fingerprint from the release keystore of the second computer. Also
remember to edit the key credentials if the app's Package Name changes. See obtaining a Google Maps API v2 key.
You'll also need to enable appropriate permissions by right-clicking on the Android project and selecting
Options > Build > Android Application and ticking the following:
AccessCoarseLocation
AccessFineLocation
AccessLocationExtraCommands
AccessMockLocation
AccessNetworkState
AccessWifiState
Internet
The last two are required because applications require a network connection to download map data. Read about
Android permissions to learn more.
In addition, Android 9 has removed the Apache HTTP client library from the bootclasspath, and so it isn't
available to applications that target API 28 or higher. The following line must be added to the application node
of your AndroidManifest.xml file to continue using the Apache HTTP client in applications that target API 28
or higher:
<application ...>
...
<uses-library android:name="org.apache.http.legacy" android:required="false" />
</application>
Using maps
See the MapPage.cs in the MobileCRM sample for an example of how the map control can be used in code. A
simple MapPage class might look like this - notice that a new MapSpan is created to position the map's view:
public class MapPage : ContentPage {
public MapPage() {
var map = new Map(
MapSpan.FromCenterAndRadius(
new Position(37,-122), Distance.FromMiles(0.3))) {
IsShowingUser = true,
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand
};
var stack = new StackLayout { Spacing = 0 };
stack.Children.Add(map);
Content = stack;
}
}
Map type
The map content can also be changed by setting the MapType property, to show a regular street map (the
default), satellite imagery or a combination of both.
map.MapType == MapType.Street;
To change the zoom level of the map without altering the location, create a new MapSpan using the current
location from the VisibleRegion.Center property of the map control. A Slider could be used to control map
zoom like this (however zooming directly in the map control cannot currently update the value of the slider):
PinType can be set to one of the following values, which may affect the way the pin is rendered (depending on
the platform):
Generic
Place
SavedPin
SearchResult
Using XAML
Maps can also be positioned in XAML layouts as shown in this snippet.
NOTE
An additional xmlns namespace definition is required to reference the Xamarin.Forms.Maps controls.
The MapRegion and Pins can be set in code using the MyMap reference (or whatever the map is named).
MyMap.MoveToRegion(
MapSpan.FromCenterAndRadius(
new Position(37,-122), Distance.FromMiles(1)));
Therefore, a Map can be populated with data by using data binding to bind its ItemsSource property to an
IEnumerable collection:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
x:Class="WorkingWithMaps.PinItemsSourcePage">
<Grid>
...
<maps:Map x:Name="map"
ItemsSource="{Binding Locations}">
<maps:Map.ItemTemplate>
<DataTemplate>
<maps:Pin Position="{Binding Position}"
Address="{Binding Address}"
Label="{Binding Description}" />
</DataTemplate>
</maps:Map.ItemTemplate>
</maps:Map>
...
</Grid>
</ContentPage>
The property data binds to the Locations property of the connected view model, which returns an
ItemsSource
ObservableCollection of Location objects, which is a custom type. Each Location object defines Address and
Description properties, of type string , and a Position property, of type Position .
The appearance of each item in the IEnumerable collection is defined by setting the ItemTemplate property to a
DataTemplate that contains a Pin object that data binds to appropriate properties.
The following screenshots show a Map displaying a Pin collection using data binding:
Related links
MapsSample
Map Custom Renderer
Xamarin.Forms Samples
Xamarin.Forms Picker
3/6/2019 • 2 minutes to read • Edit Online
The Picker view is a control for selecting a text item from a list of data.
The Xamarin.Forms Picker displays a short list of items, from which the user can select an item. Picker defines
the following properties:
Title of type string , which defaults to null .
TitleColor of type Color , the color used to display the Title text.
ItemsSource of type IList , the source list of items to display, which defaults to null .
SelectedIndex of type int , the index of the selected item, which defaults to -1.
SelectedItem of type object , the selected item, which defaults to null .
TextColor of type Color , the color used to display the text, which defaults to Color.Default .
FontAttributes of type FontAttributes , which defaults to FontAtributes.None .
FontFamily of type string , which defaults to null .
FontSize of type double , which defaults to -1.0.
All of the properties are backed by BindableProperty objects, which means that they can be styled, and the
properties can be targets of data bindings. The SelectedIndex and SelectedItem properties have a default
binding mode of BindingMode.TwoWay , which means that they can be targets of data bindings in an application that
uses the Model-View -ViewModel (MVVM ) architecture. For information about setting font properties, see Fonts.
A Picker doesn't show any data when it's first displayed. Instead, the value of its Title property is shown as a
placeholder on the iOS and Android platforms:
When the Picker gains focus, its data is displayed and the user can select an item:
The Picker fires a SelectedIndexChanged event when the user selects an item. Following selection, the selected
item is displayed by the Picker :
Related links
Picker
Setting a Picker's ItemsSource Property
3/6/2019 • 4 minutes to read • Edit Online
<Picker x:Name="picker"
Title="Select a monkey"
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>
NOTE
Note that the x:Array element requires a Type attribute indicating the type of the items in the array.
NOTE
Item selection behavior in a Picker can be customized on iOS with a platform-specific. For more information, see
Controlling Picker Item Selection.
The following code example shows how to retrieve the SelectedItem property value from the Picker in XAML:
In addition, an event handler can be executed when the SelectedIndexChanged event fires:
if (selectedIndex != -1)
{
monkeyNameLabel.Text = (string)picker.ItemsSource[selectedIndex];
}
}
This method obtains the SelectedIndex property value, and uses the value to retrieve the selected item from the
ItemsSource collection. This is functionally equivalent to retrieving the selected item from the SelectedItem
property. Note that each item in the ItemsSource collection is of type object , and so must be cast to a string for
display.
NOTE
A Picker can be initialized to display a specific item by setting the SelectedIndex or SelectedItem properties.
However, these properties must be set after initializing the ItemsSource collection.
The ItemsSource property data binds to the Monkeys property of the connected view model, which returns an
IList<Monkey> collection. The following code example shows the Monkey class, which contains four properties:
When binding to a list of objects, the Picker must be told which property to display from each object. This is
achieved by setting the ItemDisplayBinding property to the required property from each object. In the code
examples above, the Picker is set to display each Monkey.Name property value.
Responding to item selection
Data binding can be used to set an object to the SelectedItem property value when it changes:
NOTE
Note that the SelectedItem and SelectedIndex properties both support two-way bindings by default.
Related links
Picker Demo (sample)
Monkey App (sample)
Bindable Picker (sample)
Picker API
Adding Data to a Picker's Items Collection
3/6/2019 • 2 minutes to read • Edit Online
In addition to adding data using the Items.Add method, data can also be inserted into the collection by using the
Items.Insert method.
NOTE
Item selection behavior in a Picker can be customized on iOS with a platform-specific. For more information, see
Controlling Picker Item Selection.
The following code example shows the OnPickerSelectedIndexChanged event handler method, which is executed
when the SelectedIndexChanged event fires:
if (selectedIndex != -1)
{
monkeyNameLabel.Text = picker.Items[selectedIndex];
}
}
This method obtains the SelectedIndex property value, and uses the value to retrieve the selected item from the
Items collection. Because each item in the Items collection is a string , they can be displayed by a Label
without requiring a cast.
NOTE
A Picker can be initialized to display a specific item by setting the SelectedIndex property. However, the
SelectedIndex property must be set after initializing the Items collection.
Related links
Picker Demo (sample)
Picker
Xamarin.Forms Slider
3/6/2019 • 12 minutes to read • Edit Online
WARNING
Internally, the Slider ensures that Minimum is less than Maximum . If Minimum or Maximum are ever set so that
Minimum is not less than Maximum , an exception is raised. See the Precautions section below for more information on
setting the Minimum and Maximum properties.
The Slider coerces the Value property so that it is between Minimum and Maximum , inclusive. If the Minimum
property is set to a value greater than the Value property, the Slider sets the Value property to Minimum .
Similarly, if Maximum is set to a value less than Value , then Slider sets the Value property to Maximum .
Slider defines a ValueChanged event that is fired when the Value changes, either through user manipulation of
the Slider or when the program sets the Value property directly. A ValueChanged event is also fired when the
Value property is coerced as described in the previous paragraph.
The object that accompanies the ValueChanged event has two properties, both of type
ValueChangedEventArgs
double : OldValue and NewValue . At the time the event is fired, the value of NewValue is the same as the Value
property of the Slider object.
Slider also defines DragStarted and DragCompleted events, that are fired at the beginning and end of the drag
action. Unlike the ValueChanged event, the DragStarted and DragCompleted events are only fired through user
manipulation of the Slider . When the DragStarted event fires, the DragStartedCommand , of type ICommand , is
executed. Similarly, when the DragCompleted event fires, the DragCompletedCommand , of type ICommand , is executed.
WARNING
Do not use unconstrained horizontal layout options of Center , Start , or End with Slider . On both Android and the
UWP, the Slider collapses to a bar of zero length, and on iOS, the bar is very short. Keep the default
HorizontalOptions setting of Fill , and don't use a width of Auto when putting Slider in a Grid layout.
The Slider also defines several properties that affect its appearance:
MinimumTrackColor is the bar color on the left side of the thumb.
MaximumTrackColor is the bar color on the right side of the thumb.
ThumbColor is the thumb color.
ThumbImage is the image to use for the thumb, of type FileImageSource .
NOTE
The ThumbColor and ThumbImage properties are mutually exclusive. If both properties are set, the ThumbImage property
will take precedence.
The is initialized to have a Maximum property of 360. The ValueChanged handler of the Slider uses the
Slider
Value property of the slider object to set the Rotation property of the first Label and uses the String.Format
method with the NewValue property of the event arguments to set the Text property of the second Label . These
two approaches to obtain the current value of the Slider are interchangeable.
Here's the program running on iOS, Android, and Universal Windows Platform (UWP ) devices:
The second Label displays the text "(uninitialized)" until the Slider is manipulated, which causes the first
ValueChanged event to be fired. Notice that the number of decimal places that are displayed is different for each
platform. These differences are related to the platform implementations of the Slider and are discussed later in
this article in the section Platform implementation differences.
Creating a Slider in XAML
The Basic Slider XAML page is functionally the same as Basic Slider Code but implemented mostly in XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SliderDemos.BasicSliderXamlPage"
Title="Basic Slider XAML"
Padding="10, 0">
<StackLayout>
<Label x:Name="rotatingLabel"
Text="ROTATING TEXT"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider Maximum="360"
ValueChanged="OnSliderValueChanged" />
<Label x:Name="displayLabel"
Text="(uninitialized)"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
The code-behind file contains the handler for the ValueChanged event:
public partial class BasicSliderXamlPage : ContentPage
{
public BasicSliderXamlPage()
{
InitializeComponent();
}
It's also possible for the event handler to obtain the Slider that is firing the event through the sender argument.
The Value property contains the current value:
If the Slider object were given a name in the XAML file with an x:Name attribute (for example, "slider"), then the
event handler could reference that object directly:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SliderDemos.BasicSliderBindingsPage"
Title="Basic Slider Bindings"
Padding="10, 0">
<StackLayout>
<Label Text="ROTATING TEXT"
Rotation="{Binding Source={x:Reference slider},
Path=Value}"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Maximum="360" />
<Label x:Name="displayLabel"
Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The Slider value is {0:F0}'}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
The Rotation property of the first Label is bound to the Value property of the Slider , as is the Text property
of the second Label with a StringFormat specification. The Basic Slider Bindings page functions a little
differently from the two previous pages: When the page first appears, the second Label displays the text string
with the value. This is a benefit of using data binding. To display text without data binding, you'd need to
specifically initialize the Text property of the Label or simulate a firing of the ValueChanged event by calling the
event handler from the class constructor.
Precautions
The value of the Minimum property must always be less than the value of the Maximum property. The following
code snippet causes the Slider to raise an exception:
// Throws an exception!
Slider slider = new Slider
{
Minimum = 10,
Maximum = 20
};
The C# compiler generates code that sets these two properties in sequence, and when the Minimum property is set
to 10, it is greater than the default Maximum value of 1. You can avoid the exception in this case by setting the
Maximum property first:
Setting Maximum to 20 is not a problem because it is greater than the default Minimum value of 0. When Minimum
is set, the value is less than the Maximum value of 20.
The same problem exists in XAML. Set the properties in an order that ensures that Maximum is always greater than
Minimum :
<Slider Maximum="20"
Minimum="10" ... />
You can set the Minimum and Maximum values to negative numbers, but only in an order where Minimum is always
less than Maximum :
<Slider Minimum="-20"
Maximum="-10" ... />
The Value property is always greater than or equal to the Minimum value and less than or equal to Maximum . If
Value is set to a value outside that range, the value will be coerced to lie within the range, but no exception is
raised. For example, this code will not raise an exception:
<Slider ValueChanged="OnSliderValueChanged"
Maximum="20"
Minimum="10" />
When Minimum is set to 10, Value is also set to 10, and the ValueChanged event is fired. This might occur before
the rest of the page has been constructed, and the handler might attempt to reference other elements on the page
that have not yet been created. You might want to add some code to the ValueChanged handler that checks for
null values of other elements on the page. Or, you can set the ValueChanged event handler after the Slider
values have been initialized.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SliderDemos.RgbColorSlidersPage"
Title="RGB Color Sliders">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Slider">
<Setter Property="Maximum" Value="255" />
</Style>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="10">
<BoxView x:Name="boxView"
Color="Black"
VerticalOptions="FillAndExpand" />
<Slider x:Name="redSlider"
ValueChanged="OnSliderValueChanged" />
<Slider x:Name="greenSlider"
ValueChanged="OnSliderValueChanged" />
<Slider x:Name="blueSlider"
ValueChanged="OnSliderValueChanged" />
A Style gives all three Slider elements a range of 0 to 255. The Slider elements share the same ValueChanged
handler, which is implemented in the code-behind file:
public partial class RgbColorSlidersPage : ContentPage
{
public RgbColorSlidersPage()
{
InitializeComponent();
}
boxView.Color = Color.FromRgb((int)redSlider.Value,
(int)greenSlider.Value,
(int)blueSlider.Value);
}
}
The first section sets the Text property of one of the Label instances to a short text string indicating the value of
the Slider in hexadecimal. Then, all three Slider instances are accessed to create a Color value from the RGB
components:
ViewModels and the INotifyPropertyChanged interface are discussed in the article Data Binding.
The HslColorSlidersPage.xaml file instantiates the HslColorViewModel and sets it to the page's BindingContext
property. This allows all the elements in the XAML file to bind to properties in the ViewModel:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:SliderDemos"
x:Class="SliderDemos.HslColorSlidersPage"
Title="HSL Color Sliders">
<ContentPage.BindingContext>
<local:HslColorViewModel Color="Chocolate" />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="10">
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />
As the Slider elements are manipulated, the BoxView and Label elements are updated from the ViewModel:
The StringFormat component of the Binding markup extension is set for a format of "F2" to display two decimal
places. (String formatting in data bindings is discussed in the article String Formatting.) However, the UWP
version of the program is limited to values of 0, 0.1, 0.2, ... 0.9, and 1.0. This is a direct result of the implementation
of the UWP Slider as described above in the section Platform implementation differences.
Related Links
Slider Demos sample
Slider API
Xamarin.Forms Stepper
12/7/2018 • 7 minutes to read • Edit Online
All of these properties are backed by BindableProperty objects. The Value property has a default binding mode
of BindingMode.TwoWay , which means that it's suitable as a binding source in an application that uses the Model-
View -ViewModel (MVVM ) architecture.
WARNING
Internally, the Stepper ensures that Minimum is less than Maximum . If Minimum or Maximum are ever set so that
Minimum is not less than Maximum , an exception is raised. For more information on setting the Minimum and Maximum
properties, see Precautions section.
The Stepper coerces the Value property so that it is between Minimum and Maximum , inclusive. If the Minimum
property is set to a value greater than the Value property, the Stepper sets the Value property to Minimum .
Similarly, if Maximum is set to a value less than Value , then Stepper sets the Value property to Maximum .
Stepper defines a ValueChanged event that is fired when the Value changes, either through user manipulation of
the Stepper or when the application sets the Value property directly. A ValueChanged event is also fired when
the Value property is coerced as described in the previous paragraph.
The object that accompanies the ValueChanged event has two properties, both of type
ValueChangedEventArgs
double : OldValue and NewValue . At the time the event is fired, the value of NewValue is the same as the Value
property of the Stepper object.
The Stepperis initialized to have a Maximum property of 360, and an Increment property of 30. Manipulating the
Stepper changes the selected value incrementally between Minimum to Maximum based on the value of the
Increment property. The ValueChanged handler of the Stepper uses the Value property of the stepper object to
set the Rotation property of the first Label and uses the string.Format method with the NewValue property of
the event arguments to set the Text property of the second Label . These two approaches to obtain the current
value of the Stepper are interchangeable.
The following screenshots show the Basic Stepper Code page:
The second Label displays the text "(uninitialized)" until the Stepper is manipulated, which causes the first
ValueChanged event to be fired.
Creating a Stepper in XAML
The Basic Stepper XAML page is functionally the same as Basic Stepper Code but implemented mostly in
XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StepperDemo.BasicStepperXAMLPage"
Title="Basic Stepper XAML">
<StackLayout Margin="20">
<Label x:Name="_rotatingLabel"
Text="ROTATING TEXT"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Stepper Maximum="360"
Increment="30"
HorizontalOptions="Center"
ValueChanged="OnStepperValueChanged" />
<Label x:Name="_displayLabel"
Text="(uninitialized)"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
The code-behind file contains the handler for the ValueChanged event:
public partial class BasicStepperXAMLPage : ContentPage
{
public BasicStepperXAMLPage()
{
InitializeComponent();
}
It's also possible for the event handler to obtain the Stepper that is firing the event through the sender
argument. The Value property contains the current value:
If the Stepper object were given a name in the XAML file with an x:Name attribute (for example, "stepper"), then
the event handler could reference that object directly:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StepperDemo.BasicStepperBindingsPage"
Title="Basic Stepper Bindings">
<StackLayout Margin="20">
<Label Text="ROTATING TEXT"
Rotation="{Binding Source={x:Reference _stepper}, Path=Value}"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Stepper x:Name="_stepper"
Maximum="360"
Increment="30"
HorizontalOptions="Center" />
<Label Text="{Binding Source={x:Reference _stepper}, Path=Value, StringFormat='The Stepper value is
{0:F0}'}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
The Rotation property of the first Label is bound to the Value property of the Stepper , as is the Text
property of the second Label with a StringFormat specification. The Basic Stepper Bindings page functions a
little differently from the two previous pages: When the page first appears, the second Label displays the text
string with the value. This is a benefit of using data binding. To display text without data binding, you'd need to
specifically initialize the Text property of the Label or simulate a firing of the ValueChanged event by calling the
event handler from the class constructor.
Precautions
The value of the Minimum property must always be less than the value of the Maximum property. The following
code snippet causes the Stepper to raise an exception:
// Throws an exception!
Stepper stepper = new Stepper
{
Minimum = 180,
Maximum = 360
};
The C# compiler generates code that sets these two properties in sequence, and when the Minimum property is set
to 180, it is greater than the default Maximum value of 100. You can avoid the exception in this case by setting the
Maximum property first:
Setting Maximum to 360 is not a problem because it is greater than the default Minimum value of 0. When Minimum
is set, the value is less than the Maximum value of 360.
The same problem exists in XAML. Set the properties in an order that ensures that Maximum is always greater than
Minimum :
<Stepper Maximum="360"
Minimum="180" ... />
You can set the Minimum and Maximum values to negative numbers, but only in an order where Minimum is always
less than Maximum :
<Stepper Minimum="-360"
Maximum="-180" ... />
The Value property is always greater than or equal to the Minimum value and less than or equal to Maximum . If
Value is set to a value outside that range, the value will be coerced to lie within the range, but no exception is
raised. For example, this code will not raise an exception:
<Stepper ValueChanged="OnStepperValueChanged"
Maximum="360"
Minimum="180" />
When Minimum is set to 180, Value is also set to 180, and the ValueChanged event is fired. This might occur
before the rest of the page has been constructed, and the handler might attempt to reference other elements on
the page that have not yet been created. You might want to add some code to the ValueChanged handler that
checks for null values of other elements on the page. Or, you can set the ValueChanged event handler after the
Stepper values have been initialized.
Related Links
Stepper Demos sample
Stepper API
Styling Xamarin.Forms Apps
3/20/2019 • 2 minutes to read • Edit Online
Introduction
Xamarin.Forms applications often contain multiple controls that have an identical appearance. Setting the
appearance of each individual control can be repetitive and error prone. Instead, styles can be created that
customize control appearance by grouping and setting properties available on the control type.
Explicit Styles
An explicit style is one that is selectively applied to controls by setting their Style properties.
Implicit Styles
An implicit style is one that's used by all controls of the same TargetType , without requiring each control to
reference the style.
Global Styles
Styles can be made available globally by adding them to the application's ResourceDictionary . This helps to avoid
duplication of styles across pages or controls.
Style Inheritance
Styles can inherit from other styles to reduce duplication and enable reuse.
Dynamic Styles
Styles do not respond to property changes, and remain unchanged for the duration of an application. However,
applications can respond to style changes dynamically at runtime by using dynamic resources.
Device Styles
Xamarin.Forms includes six dynamic styles, known as device styles, in the Devices.Styles class. All six styles can
be applied to Label instances only.
Style Classes
Xamarin.Forms style classes enable multiple styles to be applied to a control, without resorting to style inheritance.
Introduction to Xamarin.Forms Styles
3/8/2019 • 4 minutes to read • Edit Online
Styles allow the appearance of visual elements to be customized. Styles are defined for a specific type and contain
values for the properties available on that type.
Xamarin.Forms applications often contain multiple controls that have an identical appearance. For example, an
application may have multiple Label instances that have the same font options and layout options, 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="Styles.NoStylesPage"
Title="No Styles"
Icon="xaml.png">
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="These labels"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
FontSize="Large" />
<Label Text="are not"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
FontSize="Large" />
<Label Text="using styles"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
FontSize="Large" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The following code example shows the equivalent page created in C#:
public class NoStylesPageCS : ContentPage
{
public NoStylesPageCS ()
{
Title = "No Styles";
Icon = "csharp.png";
Padding = new Thickness (0, 20, 0, 0);
Each Label instance has identical property values for controlling the appearance of the text displayed by the
Label . This results in the appearance shown in the following screenshots:
Setting the appearance of each individual control can be repetitive and error prone. Instead, a style can be created
that defines the appearance, and then applied to the required controls.
Create a style
The Style class groups a collection of property values into one object that can then be applied to multiple visual
element instances. This helps to reduce repetitive markup, and allows an applications appearance to be more easily
changed.
Although styles were designed primarily for XAML -based applications, they can also be created in C#:
Style instances created in XAML are typically defined in a ResourceDictionary that's assigned to the
Resources collection of a control, page, or to the Resources collection of the application.
Style instances created in C# are typically defined in the page's class, or in a class that can be globally
accessed.
Choosing where to define a Style impacts where it can be used:
Style instances defined at the control level can only be applied to the control and to its children.
Style instances defined at the page level can only be applied to the page and to its children.
Style instances defined at the application level can be applied throughout the application.
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.
To apply a Style , the target object must be a VisualElement that matches the TargetType property value of the
Style , as shown in the following XAML code example:
Styles lower in the view hierarchy take precedence over those defined higher up. For example, setting a Style that
sets Label.TextColor to Red at the application level will be overridden by a page level style that sets
Label.TextColor to Green . Similarly, a page level style will be overridden by a control level style. In addition, if
Label.TextColor is set directly on a control property, this takes precedence over any styles.
The articles in this section demonstrate and explain how to create and apply explicit and implicit styles, how to
create global styles, style inheritance, how to respond to style changes at runtime, and how to use the in-built styles
included in Xamarin.Forms.
NOTE
What is StyleId?
Prior to Xamarin.Forms 2.2, the StyleId property was used to identify individual elements in an application for
identification in UI testing, and in theme engines such as Pixate. However, Xamarin.Forms 2.2 introduced the AutomationId
property, which has superseded the StyleId property.
Related links
XAML Markup Extensions
Style
Setter
Explicit Styles in Xamarin.Forms
1/30/2019 • 4 minutes to read • Edit Online
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ExplicitStylesPage" Title="Explicit"
Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="labelRedStyle" TargetType="Label">
<Setter Property="HorizontalOptions"
Value="Center" />
<Setter Property="VerticalOptions"
Value="CenterAndExpand" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
<Style x:Key="labelGreenStyle" TargetType="Label">
...
<Setter Property="TextColor" Value="Green" />
</Style>
<Style x:Key="labelBlueStyle" TargetType="Label">
...
<Setter Property="TextColor" Value="Blue" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="These labels"
Style="{StaticResource labelRedStyle}" />
<Label Text="are demonstrating"
Style="{StaticResource labelGreenStyle}" />
<Label Text="explicit styles,"
Style="{StaticResource labelBlueStyle}" />
<Label Text="and an explicit style override"
Style="{StaticResource labelBlueStyle}"
TextColor="Teal" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The ResourceDictionary defines three explicit styles that are applied to the page's Label instances. Each Style is
used to display text in a different color, while also setting the font size and horizontal and vertical layout options.
Each Style is applied to a different Label by setting its Style properties using the StaticResource markup
extension. This results in the appearance shown in the following screenshots:
In addition, the final Label has a Style applied to it, but also overrides the TextColor property to a different
Color value.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ExplicitStylesPage" Title="Explicit"
Icon="xaml.png">
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="labelRedStyle" TargetType="Label">
...
</Style>
...
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="These labels" Style="{StaticResource labelRedStyle}" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>
In this example, the explicit Style instances are assigned to the Resources collection of the StackLayout control.
The styles can then be applied to the control and its children.
For information about creating styles in an application's ResourceDictionary , see Global Styles.
The constructor defines three explicit styles that are applied to the page's Label instances. Each explicit Style is
added to the ResourceDictionary using the Add method, specifying a key string to refer to the Style instance.
Each Style is applied to a different Label by setting their Style properties.
However, there is no advantage to using a ResourceDictionary here. Instead, Style instances can be assigned
directly to the Style properties of the required visual elements, and the ResourceDictionary can be removed, as
shown in the following code example:
public class ExplicitStylesPageCS : ContentPage
{
public ExplicitStylesPageCS ()
{
var labelRedStyle = new Style (typeof(Label)) {
...
};
var labelGreenStyle = new Style (typeof(Label)) {
...
};
var labelBlueStyle = new Style (typeof(Label)) {
...
};
...
Content = new StackLayout {
Children = {
new Label { Text = "These labels", Style = labelRedStyle },
new Label { Text = "are demonstrating", Style = labelGreenStyle },
new Label { Text = "explicit styles,", Style = labelBlueStyle },
new Label { Text = "and an explicit style override", Style = labelBlueStyle,
TextColor = Color.Teal }
}
};
}
}
The constructor defines three explicit styles that are applied to the page's Label instances. Each Style is used to
display text in a different color, while also setting the font size and horizontal and vertical layout options. Each
Style is applied to a different Label by setting its Style properties. In addition, the final Label has a Style
applied to it, but also overrides the TextColor property to a different Color value.
Related links
XAML Markup Extensions
Basic Styles (sample)
Working with Styles (sample)
ResourceDictionary
Style
Setter
Implicit Styles in Xamarin.Forms
1/30/2019 • 4 minutes to read • Edit Online
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Styles;assembly=Styles"
x:Class="Styles.ImplicitStylesPage" Title="Implicit" Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Setter Property="HorizontalOptions" Value="Fill" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BackgroundColor" Value="Yellow" />
<Setter Property="FontAttributes" Value="Italic" />
<Setter Property="TextColor" Value="Blue" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Entry Text="These entries" />
<Entry Text="are demonstrating" />
<Entry Text="implicit styles," />
<Entry Text="and an implicit style override" BackgroundColor="Lime" TextColor="Red" />
<local:CustomEntry Text="Subclassed Entry is not receiving the style" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The ResourceDictionary defines a single implicit style that's applied to the page's Entry instances. The Style is
used to display blue text on a yellow background, while also setting other appearance options. The Style is added
to the page's ResourceDictionary without specifying an x:Key attribute. Therefore, the Style is applied to all the
Entry instances implicitly as they match the TargetType property of the Style exactly. However, the Style is
not applied to the CustomEntry instance, which is a subclassed Entry . This results in the appearance shown in the
following screenshots:
In addition, the fourth Entry overrides the BackgroundColor and TextColor properties of the implicit style to
different Color values.
Create an implicit style at the control level
In addition to creating implicit styles at the page level, they can also be created at the control level, as shown in the
following code example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Styles;assembly=Styles"
x:Class="Styles.ImplicitStylesPage" Title="Implicit" Icon="xaml.png">
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Setter Property="HorizontalOptions" Value="Fill" />
...
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Entry Text="These entries" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>
In this example, the implicit Style is assigned to the Resources collection of the StackLayout control. The implicit
style can then be applied to the control and its children.
For information about creating styles in an application's ResourceDictionary , see Global Styles.
...
Resources = new ResourceDictionary ();
Resources.Add (entryStyle);
The constructor defines a single implicit style that's applied to the page's Entry instances. The Style is used to
display blue text on a yellow background, while also setting other appearance options. The Style is added to the
page's ResourceDictionary without specifying a key string. Therefore, the Style is applied to all the Entry
instances implicitly as they match the TargetType property of the Style exactly. However, the Style is not
applied to the CustomEntry instance, which is a subclassed Entry .
<Style TargetType="Button"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="Red" />
</Style>
Placing this style in a page-level ResourceDictionary will result in it being applied to all Button instances on the
page, and also to any controls that derive from Button . However, if the ApplyToDerivedTypes property remained
unset, the style would only be applied to Button instances.
The equivalent C# code is:
var buttonStyle = new Style(typeof(Button))
{
ApplyToDerivedTypes = true,
Setters =
{
new Setter
{
Property = VisualElement.BackgroundColorProperty,
Value = Color.Red
}
}
};
Related links
XAML Markup Extensions
Basic Styles (sample)
Working with Styles (sample)
ResourceDictionary
Style
Setter
Global Styles in Xamarin.Forms
1/30/2019 • 3 minutes to read • Edit Online
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.App">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BorderColor" Value="Lime" />
<Setter Property="BorderRadius" Value="5" />
<Setter Property="BorderWidth" Value="5" />
<Setter Property="WidthRequest" Value="200" />
<Setter Property="TextColor" Value="Teal" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
This ResourceDictionary defines a single explicit style, buttonStyle , which will be used to set the appearance of
Button instances. However, global styles can be explicit or implicit.
The following code example shows a XAML page applying the buttonStyle to the page's Button instances:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ApplicationStylesPage"
Title="Application" Icon="xaml.png">
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Button Text="These buttons" Style="{StaticResource buttonStyle}" />
<Button Text="are demonstrating" Style="{StaticResource buttonStyle}" />
<Button Text="application style overrides" Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ApplicationStylesPage"
Title="Application" Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
...
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
...
<Setter Property="TextColor" Value="Blue" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Button Text="These buttons" Style="{StaticResource buttonStyle}" />
<Button Text="are demonstrating" Style="{StaticResource buttonStyle}" />
<Button Text="application style overrides" Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The original buttonStyle , defined at application level, is overridden by the buttonStyle instance defined at page
level. In addition, the page level style is overridden by the control level buttonStyle . Therefore, the Button
instances are displayed with blue text, as shown in the following screenshots:
Create a global style in C#
Style instances can be added to the application's Resources collection in C# by creating a new
ResourceDictionary , and then by adding the Style instances to the ResourceDictionary , as shown in the following
code example:
The constructor defines a single explicit style for applying to Button instances throughout the application. Explicit
Style instances are added to the ResourceDictionary using the Add method, specifying a key string to refer to
the Style instance. The Style instance can then be applied to any controls of the correct type in the application.
However, global styles can be explicit or implicit.
The following code example shows a C# page applying the buttonStyle to the page's Button instances:
public class ApplicationStylesPageCS : ContentPage
{
public ApplicationStylesPageCS ()
{
...
Content = new StackLayout {
Children = {
new Button { Text = "These buttons", Style = (Style)Application.Current.Resources
["buttonStyle"] },
new Button { Text = "are demonstrating", Style = (Style)Application.Current.Resources
["buttonStyle"] },
new Button { Text = "application styles", Style = (Style)Application.Current.Resources
["buttonStyle"]
}
}
};
}
}
The buttonStyle is applied to the Button instances by setting their Style properties, and controls the
appearance of the Button instances.
Related links
XAML Markup Extensions
Basic Styles (sample)
Working with Styles (sample)
ResourceDictionary
Style
Setter
Style Inheritance in Xamarin.Forms
1/30/2019 • 3 minutes to read • Edit Online
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.StyleInheritancePage"
Title="Inheritance" Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
<Setter Property="HorizontalOptions"
Value="Center" />
<Setter Property="VerticalOptions"
Value="CenterAndExpand" />
</Style>
<Style x:Key="labelStyle" TargetType="Label"
BasedOn="{StaticResource baseStyle}">
...
<Setter Property="TextColor" Value="Teal" />
</Style>
<Style x:Key="buttonStyle" TargetType="Button"
BasedOn="{StaticResource baseStyle}">
<Setter Property="BorderColor" Value="Lime" />
...
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="These labels"
Style="{StaticResource labelStyle}" />
...
<Button Text="So is the button"
Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The baseStyle targets View instances, and sets the HorizontalOptions and VerticalOptions properties. The
baseStyle is not set directly on any controls. Instead, labelStyle and buttonStyle inherit from it, setting
additional bindable property values. The labelStyle and buttonStyle are then applied to the Label instances
and Button instance, by setting their Style properties. This results in the appearance shown in the following
screenshots:
NOTE
An implicit style can be derived from an explicit style, but an explicit style can't be derived from an implicit style.
In this example, labelStyle and buttonStyle are control level resources, while baseStyle is a page level resource.
However, while labelStyle and buttonStyle inherit from baseStyle , it's not possible for baseStyle to inherit
from labelStyle or buttonStyle , due to their respective locations in the view hierarchy.
Style inheritance in C#
The equivalent C# page, where Style instances are assigned directly to the Style properties of the required
controls, is shown in the following code example:
public class StyleInheritancePageCS : ContentPage
{
public StyleInheritancePageCS ()
{
var baseStyle = new Style (typeof(View)) {
Setters = {
new Setter {
Property = View.HorizontalOptionsProperty, Value = LayoutOptions.Center },
...
}
};
The baseStyletargets View instances, and sets the HorizontalOptions and VerticalOptions properties. The
baseStyle is not set directly on any controls. Instead, labelStyle and buttonStyle inherit from it, setting
additional bindable property values. The labelStyle and buttonStyle are then applied to the Label instances
and Button instance, by setting their Style properties.
Related links
XAML Markup Extensions
Basic Styles (sample)
Working with Styles (sample)
ResourceDictionary
Style
Setter
Dynamic Styles in Xamarin.Forms
1/30/2019 • 4 minutes to read • Edit Online
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesPage" Title="Dynamic"
Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
<Style x:Key="blueSearchBarStyle"
TargetType="SearchBar"
BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="greenSearchBarStyle"
TargetType="SearchBar">
...
</Style>
...
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<SearchBar Placeholder="These SearchBar controls"
Style="{DynamicResource searchBarStyle}" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>
The SearchBar instances use the DynamicResource markup extension to reference a Style named searchBarStyle ,
which is not defined in the XAML. However, because the Style properties of the SearchBar instances are set
using a DynamicResource , the missing dictionary key doesn't result in an exception being thrown.
Instead, in the code-behind file, the constructor creates a ResourceDictionary entry with the key searchBarStyle ,
as shown in the following code example:
public partial class DynamicStylesPage : ContentPage
{
bool originalStyle = true;
public DynamicStylesPage ()
{
InitializeComponent ();
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
}
When the OnButtonClicked event handler is executed, searchBarStyle will switch between blueSearchBarStyle
and greenSearchBarStyle . This results in the appearance shown in the following screenshots:
The following code example demonstrates the equivalent page in C#:
public DynamicStylesPageCS ()
{
...
var baseStyle = new Style (typeof(View)) {
...
};
var blueSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var greenSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
...
var searchBar1 = new SearchBar { Placeholder = "These SearchBar controls" };
searchBar1.SetDynamicResource (VisualElement.StyleProperty, "searchBarStyle");
...
Resources = new ResourceDictionary ();
Resources.Add ("blueSearchBarStyle", blueSearchBarStyle);
Resources.Add ("greenSearchBarStyle", greenSearchBarStyle);
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
In C#, the instances use the SetDynamicResource method to reference searchBarStyle . The
SearchBar
OnButtonClicked event handler code is identical to the XAML example, and when executed, searchBarStyle will
switch between blueSearchBarStyle and greenSearchBarStyle .
The SearchBar instances use the StaticResource markup extension to reference a Style named
tealSearchBarStyle . This Style sets some additional properties and uses the BaseResourceKey property to
reference searchBarStyle . The DynamicResource markup extension is not required because tealSearchBarStyle
will not change, except for the Style it derives from. Therefore, tealSearchBarStyle maintains a link to
searchBarStyle and is altered when the base style changes.
In the code-behind file, the constructor creates a ResourceDictionary entry with the key searchBarStyle , as per the
previous example that demonstrated dynamic styles. When the OnButtonClicked event handler is executed,
searchBarStyle will switch between blueSearchBarStyle and greenSearchBarStyle . This results in the appearance
shown in the following screenshots:
The following code example demonstrates the equivalent page in C#:
public DynamicStylesInheritancePageCS ()
{
...
var baseStyle = new Style (typeof(View)) {
...
};
var blueSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var greenSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var tealSearchBarStyle = new Style (typeof(SearchBar)) {
BaseResourceKey = "searchBarStyle",
...
};
...
Resources = new ResourceDictionary ();
Resources.Add ("blueSearchBarStyle", blueSearchBarStyle);
Resources.Add ("greenSearchBarStyle", greenSearchBarStyle);
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
The tealSearchBarStyle is assigned directly to the Style property of the SearchBar instances. This Style sets
some additional properties, and uses the BaseResourceKey property to reference searchBarStyle . The
SetDynamicResource method isn't required here because tealSearchBarStyle will not change, except for the Style
it derives from. Therefore, tealSearchBarStyle maintains a link to searchBarStyle and is altered when the base
style changes.
Related links
XAML Markup Extensions
Dynamic Styles (sample)
Working with Styles (sample)
ResourceDictionary
Style
Setter
Device Styles in Xamarin.Forms
1/30/2019 • 2 minutes to read • Edit Online
All six styles can only be applied to Label instances. For example, a Label that's displaying the body of a
paragraph might set its Style property to BodyStyle .
The following code example demonstrates using the device styles in a XAML page:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DeviceStylesPage" Title="Device"
Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="myBodyStyle" TargetType="Label"
BaseResourceKey="BodyStyle">
<Setter Property="TextColor" Value="Accent" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="Title style"
Style="{DynamicResource TitleStyle}" />
<Label Text="Subtitle text style"
Style="{DynamicResource SubtitleStyle}" />
<Label Text="Body style"
Style="{DynamicResource BodyStyle}" />
<Label Text="Caption style"
Style="{DynamicResource CaptionStyle}" />
<Label Text="List item detail text style"
Style="{DynamicResource ListItemDetailTextStyle}" />
<Label Text="List item text style"
Style="{DynamicResource ListItemTextStyle}" />
<Label Text="No style" />
<Label Text="My body style"
Style="{StaticResource myBodyStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The device styles are bound to using the DynamicResource markup extension. The dynamic nature of the styles can
be seen in iOS by changing the Accessibility settings for text size. The appearance of the device styles is different
on each platform, as shown in the following screenshots:
Device styles can also be derived from by setting the BaseResourceKey property to the key name for the device
style. In the code example above, myBodyStyle inherits from BodyStyle and sets an accented text color. For more
information about dynamic style inheritance, see Dynamic Style Inheritance.
The following code example demonstrates the equivalent page in C#:
Title = "Device";
Icon = "csharp.png";
Padding = new Thickness (0, 20, 0, 0);
The Style property of each Label instance is set to the appropriate property from the Devices.Styles class.
Accessibility
The device styles respect accessibility preferences, so font sizes will change as the accessibility preferences are
altered on each platform. Therefore, to support accessible text, ensure that the device styles are used as the basis
for any text styles within your application.
The following screenshots demonstrate the device styles on each platform, with the smallest accessible font size:
The following screenshots demonstrate the device styles on each platform, with the largest accessible font size:
Related links
Text Styles
XAML Markup Extensions
Dynamic Styles (sample)
Working with Styles (sample)
Device.Styles
ResourceDictionary
Style
Setter
Xamarin.Forms Style Classes
2/2/2019 • 3 minutes to read • Edit Online
IMPORTANT
Multiple styles can share the same class name, provided they target different types. This enables multiple style classes, that
are identically named, to target different types.
The following example shows three BoxView style classes, and a VisualElement style class:
<ContentPage ...>
<ContentPage.Resources>
<Style TargetType="BoxView"
Class="Separator">
<Setter Property="BackgroundColor"
Value="#CCCCCC" />
<Setter Property="HeightRequest"
Value="1" />
</Style>
<Style TargetType="BoxView"
Class="Rounded">
<Setter Property="BackgroundColor"
Value="#1FAECE" />
<Setter Property="HorizontalOptions"
Value="Start" />
<Setter Property="CornerRadius"
Value="10" />
</Style>
<Style TargetType="BoxView"
Class="Circle">
<Setter Property="BackgroundColor"
Value="#1FAECE" />
<Setter Property="WidthRequest"
Value="100" />
<Setter Property="HeightRequest"
Value="100" />
<Setter Property="HorizontalOptions"
Value="Start" />
<Setter Property="CornerRadius"
Value="50" />
</Style>
<Style TargetType="VisualElement"
Class="Rotated"
ApplyToDerivedTypes="true">
<Setter Property="Rotation"
Value="45" />
</Style>
</ContentPage.Resources>
</ContentPage>
The Separator , Rounded , and Circle style classes each set BoxView properties to specific values.
The Rotated style class has a TargetType of VisualElement , which means it can only be applied to VisualElement
instances. However, its ApplyToDerivedTypes property is set to true , which ensures that it can be applied to any
controls that derive from VisualElement , such as BoxView . For more information about applying a style to a
derived type, see Apply a style to derived types.
The equivalent C# code is:
The following example shows three BoxView instances, each set to different style classes:
<ContentPage ...>
<ContentPage.Resources>
...
</ContentPage.Resources>
<StackLayout Margin="20">
<BoxView StyleClass="Separator" />
<BoxView WidthRequest="100"
HeightRequest="100"
HorizontalOptions="Center"
StyleClass="Rounded, Rotated" />
<BoxView HorizontalOptions="Center"
StyleClass="Circle" />
</StackLayout>
</ContentPage>
In this example, the first BoxView is styled to be a line separator, while the third BoxView is circular. The second
BoxView has two style classes applied to it, which give it rounded corners and rotate it 45 degrees:
IMPORTANT
Multiple style classes can be applied to a control because the StyleClass property is of type IList<string> . When this
occurs, style classes are applied in ascending list order. Therefore, when multiple style classes set identical properties, the
property in the style class that's in the highest list position will take precedence.
The equivalent C# code is:
...
Content = new StackLayout
{
Children =
{
new BoxView { StyleClass = new [] { "Separator" } },
new BoxView { WidthRequest = 100, HeightRequest = 100, HorizontalOptions = LayoutOptions.Center,
StyleClass = new [] { "Rounded", "Rotated" } },
new BoxView { HorizontalOptions = LayoutOptions.Center, StyleClass = new [] { "Circle" } }
}
};
Related links
Basic Styles (sample)
Styling Xamarin.Forms apps using Cascading Style
Sheets (CSS)
5/1/2019 • 12 minutes to read • Edit Online
^contentpage {
background-color: lightgray;
}
#listView {
background-color: lightgray;
}
stacklayout {
margin: 20;
}
.mainPageTitle {
font-style: bold;
font-size: medium;
}
.mainPageSubtitle {
margin-top: 15;
}
.detailPageTitle {
font-style: bold;
font-size: medium;
text-align: center;
}
.detailPageSubtitle {
text-align: center;
font-style: italic;
}
listview image {
height: 60;
width: 60;
}
stacklayout>image {
height: 200;
width: 200;
}
In Xamarin.Forms, CSS style sheets are parsed and evaluated at runtime, rather than compile time, and style
sheets are re-parsed on use.
NOTE
Currently, all of the styling that's possible with XAML styling cannot be performed with CSS. However, XAML styles can be
used to supplement CSS for properties that are currently unsupported by Xamarin.Forms. For more information about
XAML styles, see Styling Xamarin.Forms Apps using XAML Styles.
The MonkeyAppCSS sample demonstrates using CSS to style a simple app, and is shown in the following
screenshots:
Consuming a style sheet
The process for adding a style sheet to a solution is as follows:
1. Add an empty CSS file to your .NET Standard library project.
2. Set the build action of the CSS file to EmbeddedResource.
Loading a style sheet
There are a number of approaches that can be used to load a style sheet.
XAML
A style sheet can be loaded and parsed with the StyleSheet class before being added to a ResourceDictionary :
<Application ...>
<Application.Resources>
<StyleSheet Source="/Assets/styles.css" />
</Application.Resources>
</Application>
The StyleSheet.Source property specifies the style sheet as a URI relative to the location of the enclosing XAML
file, or relative to the project root if the URI starts with a / .
WARNING
The CSS file will fail to load if its build action is not set to EmbeddedResource.
Alternatively, a style sheet can be loaded and parsed with the StyleSheet class, before being added to a
ResourceDictionary , by inlining it in a CDATA section:
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet>
<![CDATA[
^contentpage {
background-color: lightgray;
}
]]>
</StyleSheet>
</ContentPage.Resources>
...
</ContentPage>
this.Resources.Add(StyleSheet.FromAssemblyResource(
IntrospectionExtensions.GetTypeInfo(typeof(MyPage)).Assembly,
"MyProject.Assets.styles.css"));
}
}
The first argument to the StyleSheet.FromAssemblyResource method is the assembly containing the style sheet,
while the second argument is a string representing the resource identifier. The resource identifier can be
obtained from the Properties window when the CSS file is selected.
Alternatively, a style sheet can be loaded from a StringReader and added to a ResourceDictionary :
The argument to the StyleSheet.FromReader method is the TextReader that has read the style sheet.
Selecting elements and applying properties
CSS uses selectors to determine which elements to target. Styles with matching selectors are applied
consecutively, in definition order. Styles defined on a specific item are always applied last. For more information
about supported selectors, see Selector Reference.
CSS uses properties to style a selected element. Each property has a set of possible values, and some properties
can affect any type of element, while others apply to groups of elements. For more information about supported
properties, see Property Reference.
Selecting elements by type
Elements in the visual tree can be selected by type with the case insensitive element selector:
stacklayout {
margin: 20;
}
This selector identifies any StackLayout elements on pages that consume the style sheet, and sets their margins to
a uniform thickness of 20.
NOTE
The element selector does not identify subclasses of the specified type.
^contentpage {
background-color: lightgray;
}
This selector identifies any ContentPage elements that consume the style sheet, and sets their background color to
lightgray .
NOTE
The ^base selector is specific to Xamarin.Forms, and isn't part of the CSS specification.
#listView {
background-color: lightgray;
}
This selector identifies the element whose StyleId property is set to listView . However, if the StyleId property
is not set, the selector will fall back to using the x:Name of the element. Therefore, in the following XAML example,
the #listView selector will identify the ListView whose x:Name attribute is set to listView , and will set it's
background color to lightgray .
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<StackLayout>
<ListView x:Name="listView" ...>
...
</ListView>
</StackLayout>
</ContentPage>
.detailPageTitle {
font-style: bold;
font-size: medium;
text-align: center;
}
.detailPageSubtitle {
text-align: center;
font-style: italic;
}
A CSS class can be assigned to a XAML element by setting the StyleClass property of the element to the CSS
class name. Therefore, in the following XAML example, the styles defined by the .detailPageTitle class are
assigned to the first Label , while the styles defined by the .detailPageSubtitle class are assigned to the second
Label .
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<ScrollView>
<StackLayout>
<Label ... StyleClass="detailPageTitle" />
<Label ... StyleClass="detailPageSubtitle"/>
...
</StackLayout>
</ScrollView>
</ContentPage>
listview image {
height: 60;
width: 60;
}
This selector identifies any Image elements that are children of ListView elements, and sets their height and
width to 60. Therefore, in the following XAML example, the listview image selector will identify the Image that's
a child of the ListView , and sets its height and width to 60.
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<StackLayout>
<ListView ...>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
...
<Image ... />
...
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
NOTE
The element element selector does not require the child element to be a direct child of the parent – the child element may
have a different parent. Selection occurs provided that an ancestor is the specified first element.
stacklayout>image {
height: 200;
width: 200;
}
This selector identifies any Image elements that are direct children of StackLayout elements, and sets their height
and width to 200. Therefore, in the following XAML example, the stacklayout>image selector will identify the
Image that's a direct child of the StackLayout , and sets its height and width to 200.
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<ScrollView>
<StackLayout>
...
<Image ... />
...
</StackLayout>
</ScrollView>
</ContentPage>
NOTE
The element>element selector requires that the child element is a direct child of the parent.
Selector reference
The following CSS selectors are supported by Xamarin.Forms:
Styles with matching selectors are applied consecutively, in definition order. Styles defined on a specific item are
always applied last.
TIP
Selectors can be combined without limitation, such as StackLayout>ContentView>label.email .
NOTE
Specificity, and specificity overrides are unsupported.
Property reference
The following CSS properties are supported by Xamarin.Forms (in the Values column, types are italic, while
string literals are gray ):
spacebetween |
spacearound |
spaceevenly |
flex-start | flex-end |
space-between |
space-around | initial
row-reverse |
column-reverse |
initial
initial
The following Xamarin.Forms specific CSS properties are also supported (in the Values column, types are italic,
while string literals are gray ):
only supported on a
ScrollView .
NOTE
initial is a valid value for all properties. It clears the value (resets to default) that was set from another style.
NOTE
CSS thickness values differ from XAML Thickness values. For example, in XAML a two-value Thickness indicates
horizontal then vertical thickness, while a four-value Thickness indicates left, then top, then right, then bottom thickness.
In addition, XAML Thickness values are comma delimited.
NamedSize
The following case insensitive namedsize values are supported:
default
micro
small
medium
large
The exact meaning of each namedsize value is platform-dependent and view -dependent.
Related Links
MonkeyAppCSS (sample)
Resource Dictionaries
Styling Xamarin.Forms Apps using XAML Styles
Xamarin.Forms TableView
3/29/2019 • 5 minutes to read • Edit Online
Use cases
TableView is useful when:
presenting a list of settings,
collecting data in a form, or
showing data that is presented differently from row to row (e.g. numbers, percentages and images).
TableView handles scrolling and laying out rows in attractive sections, a common need for the above scenarios.
The TableView control uses each platform's underlying equivalent view when available, creating a native look for
each platform.
Structure
Elements in a TableView are organized into sections. At the root of the TableView is the TableRoot , which is
parent to one or more TableSection instances. Each TableSection consists of a heading and one or more
ViewCell instances:
<TableView Intent="Settings">
<TableRoot>
<TableSection Title="Ring">
<SwitchCell Text="New Voice Mail" />
<SwitchCell Text="New Mail" On="true" />
</TableSection>
</TableRoot>
</TableView>
The equivalent C# code is:
Appearance
TableView exposes the Intent property, which can be set to any of the TableIntent enumeration members:
Data – for use when displaying data entries. Note that ListView may be a better option for scrolling lists of
data.
Form – for use when the TableView is acting as a Form.
Menu – for use when presenting a menu of selections.
Settings – for use when displaying a list of configuration settings.
The TableIntent value you choose may impact how the TableView appears on each platform. Even if there are
not clear differences, it is a best practice to select the TableIntent that most closely matches how you intend to
use the table.
In addition, the color of the text displayed for each TableSection can be changed by setting the TextColor
property to a Color .
Built-in cells
Xamarin.Forms comes with built-in cells for collecting and displaying information. Although ListView and
TableView can use all of the same cells, SwitchCell and EntryCell are the most relevant for a TableView
scenario.
See ListView Cell Appearance for a detailed description of TextCell and ImageCell.
SwitchCell
SwitchCell is the control to use for presenting and capturing an on/off or true / false state. It defines the
following properties:
Text – text to display beside the switch.
On – whether the switch is displayed as on or off.
OnColor – the Color of the switch when it's in the on position.
The root element under the TableView is the TableRoot , and there is a TableSection immediately underneath
the TableRoot . The ViewCell is defined directly under the TableSection , and a StackLayout is used to manage
the layout of the custom cell, although any layout could be used here.
NOTE
Unlike ListView , TableView does not require that custom (or any) cells are defined in an ItemTemplate .
Row height
The TableView class has two properties that can be used to change the row height of cells:
RowHeight– sets the height of each row to an int .
HasUnevenRows – rows have varying heights if set to true . Note that when setting this property to true , row
heights will automatically be calculated and applied by Xamarin.Forms.
When the height of content in a cell in a TableView is changed, the row height is implicitly updated on Android
and the Universal Windows Platform (UWP ). However, on iOS it must be forced to update by setting the
HasUnevenRows property to true and by calling the Cell.ForceUpdateSize method.
The OnViewCellTapped event handler shows or hides the second Label in the ViewCell , and explicitly updates
the cell's size by calling the Cell.ForceUpdateSize method.
The following screenshots show the cell prior to being tapped upon:
The following screenshots show the cell after being tapped upon:
IMPORTANT
There is a strong possibility of performance degradation if this feature is overused.
Related links
TableView (sample)
Text in Xamarin.Forms
3/6/2019 • 2 minutes to read • Edit Online
Label
The Label view is used to display text. It can show multiple lines of text or a single line of text. Label can present
text with multiple formatting options used in inline. The label view can wrap or truncate text when it can't fit on one
line.
Editor
Editor is used to accept multi-line text input. Editor offers control over colors and fonts.
See the Editor article for more information.
Fonts
Many controls support different font settings using the built-in fonts on each platform, or custom fonts included
with your app. See the Fonts article for more detailed information.
Styles
Refer to working with styles to learn how to set up font, color, and other display properties that apply across
multiple controls.
Related Links
Text (sample)
Xamarin.Forms Label
3/14/2019 • 10 minutes to read • Edit Online
Text decorations
Underline and strikethrough text decorations can be applied to Label instances by setting the
Label.TextDecorations property to one or more TextDecorations enumeration members:
None
Underline
Strikethrough
The following screenshots show the TextDecorations enumeration members applied to Label instances:
NOTE
Text decorations can also be applied to Span instances. For more information about the Span class, see Formatted Text.
Colors
Labels can be set to use a custom text color via the bindable TextColor property.
Special care is necessary to ensure that colors will be usable on each platform. Because each platform has
different defaults for text and background colors, you'll need to be careful to pick a default that works on each.
The following XAML example sets the text color of a Label :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TextSample.LabelPage"
Title="Label Demo">
<StackLayout Padding="5,10">
<Label TextColor="#77d065" FontSize = "20" Text="This is a green label." />
</StackLayout>
</ContentPage>
The following screenshots show the result of setting the TextColor property:
Fonts
For more information about specifying fonts on a Label , see Fonts.
The following XAML example demonstrates setting the MaxLines property on a Label :
<Label Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In facilisis nulla eu felis fringilla
vulputate. Nullam porta eleifend lacinia. Donec at iaculis tellus."
LineBreakMode="WordWrap"
MaxLines="2" />
var label =
{
Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In facilisis nulla eu felis fringilla
vulputate. Nullam porta eleifend lacinia. Donec at iaculis tellus.", LineBreakMode = LineBreakMode.WordWrap,
MaxLines = 2
};
The following screenshots show the result of setting the MaxLines property to 2, when the text is long enough to
occupy more than 2 lines:
Formatted text
Labels expose a FormattedText property that allows the presentation of text with multiple fonts and colors in the
same view.
The FormattedText property is of type FormattedString , which comprises one or more Span instances, set via the
Spans property. The following Span properties can be used to set visual appearance:
BackgroundColor– the color of the span background.
Font – the font for the text in the span.
FontAttributes – the font attributes for the text in the span.
FontFamily – the font family to which the font for the text in the span belongs.
FontSize – the size of the font for the text in the span.
ForegroundColor – the color for the text in the span. This property is obsolete and has been replaced by the
TextColor property.
LineHeight - the multiplier to apply to the default line height of the span. For more information, see Line
Height.
Text – the style to apply to the span.
Text – the text of the span.
TextColor – the color for the text in the span.
TextDecorations - the decorations to apply to the text in the span. For more information, see Text Decorations.
NOTE
The BackgroundColor , Text , and Text bindable properties have a default binding mode of OneWay . For more
information about this binding mode, see The Default Binding Mode in the Binding Mode guide.
In addition, the GestureRecognizers property can be used to define a collection of gesture recognizers that will
respond to gestures on the Span .
The following XAML example demonstrates a FormattedText property that consists of three Span instances:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TextSample.LabelPage"
Title="Label Demo - XAML">
<StackLayout Padding="5,10">
...
<Label LineBreakMode="WordWrap">
<Label.FormattedText>
<FormattedString>
<Span Text="Red Bold, " TextColor="Red" FontAttributes="Bold" />
<Span Text="default, " Style="{DynamicResource BodyStyle}">
<Span.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" />
</Span.GestureRecognizers>
</Span>
<Span Text="italic small." FontAttributes="Italic" FontSize="Small" />
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ContentPage>
IMPORTANT
The Text property of a Span can be set through data binding. For more information, see Data Binding.
Note that a Span can also respond to any gestures that are added to the span's GestureRecognizers collection. For
example, a TapGestureRecognizer has been added to the second Span in the above code examples. Therefore,
when this Span is tapped the TapGestureRecognizer will respond by executing the ICommand defined by the
Command property. For more information about gesture recognizers, see Xamarin.Forms Gestures.
The following screenshots show the result of setting the FormattedString property to three Span instances:
Line height
The vertical height of a Label and a Span can be customized by setting the Label.LineHeight property or
Span.LineHeight to a double value. On iOS and Android these values are multipliers of the original line height,
and on the Universal Windows Platform (UWP ) the Label.LineHeight property value is a multiplier of the label
font size.
NOTE
On iOS, the Label.LineHeight and Span.LineHeight properties change the line height of text that fits on a single
line, and text that wraps onto multiple lines.
On Android, the Label.LineHeight and Span.LineHeight properties only change the line height of text that wraps
onto multiple lines.
On UWP, the Label.LineHeight property changes the line height of text that wraps onto multiple lines, and the
Span.LineHeight property has no effect.
The following XAML example demonstrates setting the LineHeight property on a Label :
<Label Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In facilisis nulla eu felis fringilla
vulputate. Nullam porta eleifend lacinia. Donec at iaculis tellus."
LineBreakMode="WordWrap"
LineHeight="1.8" />
var label =
{
Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In facilisis nulla eu felis fringilla
vulputate. Nullam porta eleifend lacinia. Donec at iaculis tellus.", LineBreakMode = LineBreakMode.WordWrap,
LineHeight = 1.8
};
The following screenshots show the result of setting the Label.LineHeight property to 1.8:
The following XAML example demonstrates setting the LineHeight property on a Span :
<Label LineBreakMode="WordWrap">
<Label.FormattedText>
<FormattedString>
<Span Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In a tincidunt sem. Phasellus
mollis sit amet turpis in rutrum. Sed aliquam ac urna id scelerisque. "
LineHeight="1.8"/>
<Span Text="Nullam feugiat sodales elit, et maximus nibh vulputate id."
LineHeight="1.8" />
</FormattedString>
</Label.FormattedText>
</Label>
The following screenshots show the result of setting the Span.LineHeight property to 1.8:
Hyperlinks
The text displayed by Label and Span instances can be turned into hyperlinks with the following approach:
1. Set the TextColor and TextDecoration properties of the Label or Span .
2. Add a TapGestureRecognizer to the GestureRecognizers collection of the Label or Span , whose Command
property binds to a ICommand , and whose CommandParameter property contains the URL to open.
3. Define the ICommand that will be executed by the TapGestureRecognizer .
4. Write the code that will be executed by the ICommand .
The following code example, taken from the Hyperlink Demos sample, shows a Label whose content is set from
multiple Span instances:
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="Alternatively, click " />
<Span Text="here"
TextColor="Blue"
TextDecorations="Underline">
<Span.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}"
CommandParameter="https://docs.microsoft.com/xamarin/" />
</Span.GestureRecognizers>
</Span>
<Span Text=" to view Xamarin documentation." />
</FormattedString>
</Label.FormattedText>
</Label>
In this example, the first and third Span instances comprise text, while the second Span represents a tappable
hyperlink. It has its text color set to blue, and has an underline text decoration. This creates the appearance of a
hyperlink, as shown in the following screenshots:
When the hyperlink is tapped, the TapGestureRecognizer will respond by executing the ICommand defined by its
Command property. In addition, the URL specified by the CommandParameter property will be passed to the
ICommand as a parameter.
The code-behind for the XAML page contains the TapCommand implementation:
public MainPage()
{
InitializeComponent();
BindingContext = this;
}
The following code example, taken from the Hyperlink Demos sample, shows a HyperlinkSpan class:
public HyperlinkSpan()
{
TextDecorations = TextDecorations.Underline;
TextColor = Color.Blue;
GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => Device.OpenUri(new Uri(Url)))
});
}
}
The HyperlinkSpan class defines a Url property, and associated BindableProperty , and the constructor sets the
hyperlink appearance and the TapGestureRecognizer that will respond when the hyperlink is tapped. When a
HyperlinkSpan is tapped, the TapGestureRecognizer will respond by executing the Device.OpenUri method to open
the URL, specified by the Url property, in a web browser.
The HyperlinkSpan class can be consumed by adding an instance of the class to the XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:HyperlinkDemo"
x:Class="HyperlinkDemo.MainPage">
<StackLayout>
...
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="Alternatively, click " />
<local:HyperlinkSpan Text="here"
Url="https://docs.microsoft.com/appcenter/" />
<Span Text=" to view AppCenter documentation." />
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ContentPage>
Styling labels
The previous sections covered setting Label and Span properties on a per-instance basis. However, sets of
properties can be grouped into one style that is consistently applied to one or many views. This can increase
readability of code and make design changes easier to implement. For more information, see Styles.
Related links
Text (sample)
Hyperlinks (sample)
Creating Mobile Apps with Xamarin.Forms, Chapter 3
Label API
Span API
Xamarin.Forms Entry
3/8/2019 • 9 minutes to read • Edit Online
Display Customization
Setting and Reading Text
The Entry , like other text-presenting views, exposes the Text property. This property can be used to set and
read the text presented by the Entry . The following example demonstrates setting the Text property in XAML:
In C#:
NOTE
The width of an Entry can be defined by setting its WidthRequest property. Do not depend on the width of an Entry
being defined based on the value of its Text property.
var entry = new Entry { Text = "This is a read-only Entry", IsReadOnly = true });
NOTE
The IsReadonly property does not alter the visual appearance of an Entry , unlike the IsEnabled property that also
changes the visual appearance of the Entry to gray.
A MaxLength property value of 0 indicates that no input will be allowed, and a value of int.MaxValue , which is the
default value for an Entry , indicates that there is no effective limit on the number of characters that may be
entered.
Password Fields
Entry provides the IsPassword property. When IsPassword is true , the contents of the field will be presented
as black circles:
In XAML:
In C#:
In C#:
The default value of the CursorPosition property is 0, which indicates that text will be inserted at the start of the
Entry .
In addition, the SelectionLength property can be used to return or set the length of text selection within the
Entry :
<Entry Text="Cursor position and selection length set" CursorPosition="2" SelectionLength="10" />
var entry = new Entry { Text = "Cursor position and selection length set", CursorPosition = 2, SelectionLength
= 10 };
The default value of the SelectionLength property is 0, which indicates that no text is selected.
Customizing the Keyboard
The keyboard that's presented when users interact with an Entry can be set programmatically via the Keyboard
property, to one of the following properties from the Keyboard class:
Chat – used for texting and places where emoji are useful.
Default – the default keyboard.
Email – used when entering email addresses.
Numeric – used when entering numbers.
Plain – used when entering text, without any KeyboardFlags specified.
Telephone – used when entering telephone numbers.
Text – used when entering text.
Url – used for entering file paths & web addresses.
The following XAML code example shows how to customize the default Keyboard to offer word completions and
capitalize every entered character:
The following XAML example shows how to set the return key:
NOTE
The exact appearance of the return key is dependent upon the platform. On iOS, the return key is a text-based button.
However, on the Android and Universal Windows Platforms, the return key is a icon-based button.
When the return key is pressed, the Completed event fires and any ICommand specified by the ReturnCommand
property is executed. In addition, any object specified by the ReturnCommandParameter property will be passed to
the ICommand as a parameter. For more information about commands, see The Command Interface.
Enabling and Disabling Spell Checking
The IsSpellCheckEnabled property controls whether spell checking is enabled. By default, the property is set to
true . As the user enters text, misspellings are indicated.
However, for some text entry scenarios, such as entering a username, spell checking provides a negative
experience and should be disabled by setting the IsSpellCheckEnabled property to false :
NOTE
When the IsSpellCheckEnabled property is set to false , and a custom keyboard isn't being used, the native spell
checker will be disabled. However, if a Keyboard has been set that disables spell checking, such as Keyboard.Chat , the
IsSpellCheckEnabled property is ignored. Therefore, the property cannot be used to enable spell checking for a
Keyboard that explicitly disables it.
NOTE
When the IsTextPredictionEnabled property is set to false , and a custom keyboard isn't being used, text prediction
and automatic text correction is disabled. However, if a Keyboard has been set that disables text prediction, the
IsTextPredictionEnabled property is ignored. Therefore, the property cannot be used to enable text prediction for a
Keyboard that explicitly disables it.
Colors
Entry can be set to use a custom background and text colors via the following bindable properties:
TextColor – sets the color of the text.
BackgroundColor – sets the color shown behind the text.
Special care is necessary to ensure that colors will be usable on each platform. Because each platform has
different defaults for text and background colors, you'll often need to set both if you set one.
Use the following code to set the text color of an entry:
In XAML:
In C#:
In C#:
NOTE
The VisualElement class, from which Entry inherits, also has Focused and Unfocused events.
Completed
The Completed event is used to react to the completion of an interaction with an Entry. Completed is raised when
the user ends input with a field by pressing the return key on the keyboard. The handler for the event is a generic
event handler, taking the sender and EventArgs :
and C#:
After the Completed event fires, any ICommand specified by the ReturnCommand property is executed, with the
object specified by the ReturnCommandParameter property being passed to the ICommand .
TextChanged
The TextChanged event is used to react to a change in the content of a field.
TextChanged is raised whenever the Text of the Entry changes. The handler for the event takes an instance of
TextChangedEventArgs . TextChangedEventArgs provides access to the old and new values of the Entry Text via
the OldTextValue and NewTextValue properties:
and C#:
Related Links
Text (sample)
Entry API
Xamarin.Forms Editor
3/8/2019 • 7 minutes to read • Edit Online
Customization
Setting and Reading Text
The Editor , like other text-presenting views, exposes the Text property. This property can be used to set and
read the text presented by the Editor . The following example demonstrates setting the Text property in XAML:
In C#:
var editor = new Editor { Placeholder = "Enter text here", PlaceholderColor = Color.Olive };
NOTE
The IsReadonly property does not alter the visual appearance of an Editor , unlike the IsEnabled property that also
changes the visual appearance of the Editor to gray.
A MaxLength property value of 0 indicates that no input will be allowed, and a value of int.MaxValue , which is the
default value for an Editor , indicates that there is no effective limit on the number of characters that may be
entered.
Auto -Sizing an Editor
An Editor can be made to auto-size to its content by setting the Editor.AutoSize property to TextChanges ,
which is a value of the EditoAutoSizeOption enumeration. This enumeration has two values:
Disabled indicates that automatic resizing is disabled, and is the default value.
TextChanges indicates that automatic resizing is enabled.
var editor = new Editor { Text = "Enter text here", AutoSize = EditorAutoSizeOption.TextChanges };
When auto-resizing is enabled, the height of the Editor will increase when the user fills it with text, and the
height will decrease as the user deletes text.
NOTE
An Editor will not auto-size if the HeightRequest property has been set.
The following XAML code example shows how to customize the default Keyboard to offer word completions and
capitalize every entered character:
<Editor>
<Editor.Keyboard>
<Keyboard x:FactoryMethod="Create">
<x:Arguments>
<KeyboardFlags>Suggestions,CapitalizeCharacter</KeyboardFlags>
</x:Arguments>
</Keyboard>
</Editor.Keyboard>
</Editor>
However, for some text entry scenarios, such as entering a username, spell checking provides a negative
experience and so should be disabled by setting the IsSpellCheckEnabled property to false :
NOTE
When the IsSpellCheckEnabled property is set to false , and a custom keyboard isn't being used, the native spell
checker will be disabled. However, if a Keyboard has been set that disables spell checking, such as Keyboard.Chat , the
IsSpellCheckEnabled property is ignored. Therefore, the property cannot be used to enable spell checking for a
Keyboard that explicitly disables it.
NOTE
When the IsTextPredictionEnabled property is set to false , and a custom keyboard isn't being used, text prediction
and automatic text correction is disabled. However, if a Keyboard has been set that disables text prediction, the
IsTextPredictionEnabled property is ignored. Therefore, the property cannot be used to enable text prediction for a
Keyboard that explicitly disables it.
Colors
Editor can be set to use a custom background color via the BackgroundColor property. Special care is necessary
to ensure that colors will be usable on each platform. Because each platform has different defaults for text color,
you may need to set a custom background color for each platform. See Working with Platform Tweaks for more
information about optimizing the UI for each platform.
In C#:
public partial class EditorPage : ContentPage
{
public EditorPage ()
{
InitializeComponent ();
var layout = new StackLayout { Padding = new Thickness(5,10) };
this.Content = layout;
//dark blue on UWP & Android, light blue on iOS
var editor = new Editor { BackgroundColor = Device.RuntimePlatform == Device.iOS ?
Color.FromHex("#A4EAFF") : Color.FromHex("#2c3e50") };
layout.Children.Add(editor);
}
}
In XAML:
Interactivity
Editor exposes two events:
TextChanged – raised when the text changes in the editor. Provides the text before and after the change.
Completed – raised when the user has ended input by pressing the return key on the keyboard.
NOTE
The VisualElement class, from which Entry inherits, also has Focused and Unfocused events.
Completed
The Completed event is used to react to the completion of an interaction with an Editor . Completed is raised
when the user ends input with a field by entering the return key on the keyboard. The handler for the event is a
generic event handler, taking the sender and EventArgs :
In XAML:
TextChanged
The TextChanged event is used to react to a change in the content of a field.
TextChanged is raised whenever the Text of the Editor changes. The handler for the event takes an instance of
TextChangedEventArgs . TextChangedEventArgs provides access to the old and new values of the Editor Text via
the OldTextValue and NewTextValue properties:
In 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"
x:Class="TextSample.EditorPage"
Title="Editor Demo">
<ContentPage.Content>
<StackLayout Padding="5,10">
<Editor TextChanged="EditorTextChanged" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Related Links
Text (sample)
Editor API
Fonts in Xamarin.Forms
3/8/2019 • 5 minutes to read • Edit Online
Font size
The FontSize property can be set to a double value, for instance:
label.FontSize = 24;
You can also use the NamedSize enumeration which has four built-in options; Xamarin.Forms chooses the best
size for each platform.
Micro
Small
Medium
Large
The NamedSize enumeration can be used wherever a FontSize can be specified using the Device.GetNamedSize
method to convert the value to a double :
Font attributes
Font styles such as bold and italic can be set on the FontAttributes property. The following values are currently
supported:
None
Bold
Italic
The FontAttribute enumeration can be used as follows (you can specify a single attribute or OR them together):
There is a built-in converter for the FontSize property that allows all font settings to be expressed as a string
value in XAML. In addition, the FontAttributes property can be used to specify font attributes:
Device.RuntimePlatform can also be used in XAML to render a different font on each platform. The example
below uses a custom font face on iOS (MarkerFelt-Thin) and specifies only size/attributes on the other platforms:
When specifying a custom font face, it is always a good idea to use OnPlatform , as it is difficult to find a font that
is available on all platforms.
The steps required for each platform are outlined below. When including custom font files with an application, be
sure to verify that the font's license allows for distribution.
iOS
It is possible to display a custom font by first ensuring that it is loaded, then referring to it by name using the
Xamarin.Forms Font methods. Follow the instructions in this blog post:
1. Add the font file with Build Action: BundleResource, and
2. Update the Info.plist file (Fonts provided by application, or UIAppFonts , key), then
3. Refer to it by name wherever you define a font in Xamarin.Forms!
new Label
{
Text = "Hello, Forms!",
FontFamily = Device.RuntimePlatform == Device.iOS ? "Lobster-Regular" : null // set only for iOS
}
Android
Xamarin.Forms for Android can reference a custom font that has been added to the project by following a
specific naming standard. First add the font file to the Assets folder in the application project and set Build
Action: AndroidAsset. Then use the full path and Font Name separated by a hash (#) as the font name in
Xamarin.Forms, as the code snippet below demonstrates:
new Label
{
Text = "Hello, Forms!",
FontFamily = Device.RuntimePlatform == Device.Android ? "Lobster-Regular.ttf#Lobster-Regular" : null //
set only for Android
}
Windows
Xamarin.Forms for Windows platforms can reference a custom font that has been added to the project by
following a specific naming standard. First add the font file to the /Assets/Fonts/ folder in the application
project and set the Build Action:Content. Then use the full path and font filename, followed by a hash (#) and the
Font Name, as the code snippet below demonstrates:
new Label
{
Text = "Hello, Forms!",
FontFamily = Device.RuntimePlatform == Device.UWP ? "Assets/Fonts/Lobster-Regular.ttf#Lobster" : null //
set only for UWP apps
}
NOTE
Note that the font file name and font name may be different. To discover the font name on Windows, right-click the .ttf file
and select Preview. The font name can then be determined from the preview window.
The common code for the application is now complete. Platform-specific phone dialer code will now be
implemented as a DependencyService.
XAML
You can also use Device.RuntimePlatform in XAML to render a custom font:
This data is used to create a PNG, which can be displayed by any view that can display an ImageSource . This
approach permits font icons, such as emojis, to be displayed by multiple views, as opposed to limiting font icon
display to a single text presenting view, such as a Label .
IMPORTANT
Font icons can only currently be specified by their unicode character representation.
The following XAML example has a single font icon being displayed by an Image view:
<Image BackgroundColor="#D1D1D1">
<Image.Source>
<FontImageSource Glyph=""
FontFamily="{OnPlatform iOS=Ionicons, Android=ionicons.ttf#}"
Size="44" />
</Image.Source>
</Image>
This code displays an XBox icon, from the Ionicons font family, in an Image view. Note that while the unicode
character for this icon is \uf30c , it has to be escaped in XAML and so becomes  . The equivalent C#
code is:
Image image = new Image { BackgroundColor = Color.FromHex("#D1D1D1") };
image.Source = new FontImageSource
{
Glyph = "\uf30c",
FontFamily = Device.RuntimePlatform == Device.iOS ? "Ionicons" : "ionicons.ttf#",
Size = 44
};
The following screenshots, from the Bindable Layouts sample, show several font icons being displayed by a
bindable layout:
Related links
FontsSample
Text (sample)
Bindable Layouts (sample)
Bindable Layouts
Xamarin.Forms Text Styles
12/7/2018 • 2 minutes to read • Edit Online
Built-In Styles
Xamarin.Forms includes several built-in styles for common scenarios:
BodyStyle
CaptionStyle
ListItemDetailTextStyle
ListItemTextStyle
SubtitleStyle
TitleStyle
To apply one of the built-in styles, use the DynamicResource markup extension to specify the style:
label.Style = Device.Styles.TitleStyle;
Custom Styles
Styles consist of setters and setters consist of properties and the values the properties will be set to.
In C#, a custom style for a label with red text of size 30 would be defined as follows:
var label = new Label { Text = "Check out my style.", Style = LabelStyle };
In XAML:
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="LabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="Red"/>
<Setter Property="FontSize" Value="30"/>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<Label Text="Check out my style." Style="{StaticResource LabelStyle}" />
</StackLayout>
</ContentPage.Content>
Note that resources (including all styles) are defined within ContentPage.Resources , which is a sibling of the more
familiar ContentPage.Content element.
Applying Styles
Once a style has been created, it can be applied to any view matching its TargetType .
In XAML, custom styles are applied to views by supplying their Style property with a StaticResource markup
extension referencing the desired style:
In C#, styles can either be applied directly to a view or added to and retrieved from a page's ResourceDictionary .
To add directly:
var label = new Label { Text = "Check out my style.", Style = LabelStyle };
Built-in styles are applied differently, because they need to respond to accessibility settings. To apply built-in styles
in XAML, the DynamicResource markup extension is used:
label.Style = Device.Styles.TitleStyle;
Accessibility
The built-in styles exist to make it easier to respect accessibility preferences. When using any of the built-in styles,
font sizes will automatically increase if a user sets their accessibility preferences accordingly.
Consider the following example of the same page of views styled with the built-in styles with accessibility settings
enabled and disabled:
Disabled:
Enabled:
To ensure accessibility, make sure that built-in styles are used as the basis for any text-related styles within your
app, and that you are using styles consistently. See Styles for more details on extending and working with styles in
general.
Related Links
Creating Mobile Apps with Xamarin.Forms, Chapter 12
Styles
Text (sample)
Style
Xamarin.Forms Themes
12/7/2018 • 2 minutes to read • Edit Online
Xamarin.Forms Themes were announced at Evolve 2016 and are available as a preview for customers to try and
provide feedback.
A theme is added to a Xamarin.Forms application by including the Xamarin.Forms.Theme.Base Nuget
package, plus an additional package that defines a specific theme (eg. Xamarin.Forms.Theme.Light) or else a local
theme can be defined for the application.
Refer to the Light theme and Dark theme pages for instructions on how to add them to an app, or check out the
example custom theme.
IMPORTANT: You should also follow the steps to load theme assemblies (below ) by adding some boilerplate
code to the iOS AppDelegate and Android MainActivity . This will be improved in a future preview release.
Control Appearance
The Light and Dark themes both define a specific visual appearance for the standard controls. Once you add a
theme to the application's resource dictionary, the appearance of the standard controls will change.
The following XAML markup shows some common controls:
<StackLayout Padding="40">
<Label Text="Regular label" />
<Entry Placeholder="type here" />
<Button Text="OK" />
<BoxView Color="Yellow" />
<Switch />
</StackLayout>
StyleClass
The StyleClass property allows a view's appearance to be changed according to a definition provided by a
theme.
The Light and Dark themes both define three different appearances for a BoxView : HorizontalRule , Circle , and
Rounded . This markup shows three different BoxView s wtih different style classes applied:
<StackLayout Padding="40">
<BoxView StyleClass="HorizontalRule" />
<BoxView StyleClass="Circle" />
<BoxView StyleClass="Rounded" />
</StackLayout>
Built-in Classes
In addition to automatically styling the common controls the Light and Dark themes currently support the
following classes that can be applied by setting the StyleClass on these controls:
BoxView
HorizontalRule
Circle
Rounded
Image
Circle
Rounded
Thumbnail
Button
Default
Primary
Success
Info
Warning
Danger
Link
Small
Large
Label
Header
Subheader
Body
Link
Inverse
Troubleshooting
Could not load file or assembly 'Xamarin.Forms.Theme.Light' or one of its dependencies
In the preview release, themes may not be able to load at runtime. Add the code shown below into the relevant
projects to fix this error.
iOS
In the AppDelegate.cs add the following lines after LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.iOS.UnderlineEffect);
Android
In the MainActivity.cs add the following lines after LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.Android.UnderlineEffect);
Related Links
ThemesDemo sample
Xamarin.Forms Light Theme
6/8/2018 • 2 minutes to read • Edit Online
NOTE
Themes require the Xamarin.Forms 2.3 preview release. Check the troubleshooting tips if errors occur.
4. Use StyleClass
Here is an example of buttons and labels in the light theme, along with the markup that produces them.
<StackLayout Padding="20">
<Button Text="Button Default" />
<Button Text="Button Class Default" StyleClass="Default" />
<Button Text="Button Class Primary" StyleClass="Primary" />
<Button Text="Button Class Success" StyleClass="Success" />
<Button Text="Button Class Info" StyleClass="Info" />
<Button Text="Button Class Warning" StyleClass="Warning" />
<Button Text="Button Class Danger" StyleClass="Danger" />
<Button Text="Button Class Link" StyleClass="Link" />
<Button Text="Button Class Default Small" StyleClass="Small" />
<Button Text="Button Class Default Large" StyleClass="Large" />
</StackLayout>
The complete list of built-in classes shows what styles are available for some common controls.
Xamarin.Forms Dark Theme
6/8/2018 • 2 minutes to read • Edit Online
NOTE
Themes require the Xamarin.Forms 2.3 preview release. Check the troubleshooting tips if errors occur.
4. Use StyleClass
Here is an example of buttons and labels in the dark theme, along with the markup that produces them.
<StackLayout Padding="20">
<Button Text="Button Default" />
<Button Text="Button Class Default" StyleClass="Default" />
<Button Text="Button Class Primary" StyleClass="Primary" />
<Button Text="Button Class Success" StyleClass="Success" />
<Button Text="Button Class Info" StyleClass="Info" />
<Button Text="Button Class Warning" StyleClass="Warning" />
<Button Text="Button Class Danger" StyleClass="Danger" />
<Button Text="Button Class Link" StyleClass="Link" />
The complete list of built-in classes shows what styles are available for some common controls.
Creating a Custom Xamarin.Forms Theme
3/30/2019 • 3 minutes to read • Edit Online
In addition to adding a theme from a Nuget package (such as the Light and Dark themes), you can create your own
resource dictionary themes that can be referenced in your app.
Example
The three BoxView s shown on the Themes page are styled according to three classes defined in the two
downloadable themes.
To understand how these work, the following markup creates an equivalent style that you could add directly to
your App.xaml.
Note the Class attribute for Style (as opposed to the x:Key attribute available in earlier versions of
Xamarin.Forms).
<ResourceDictionary>
<!-- DEFINE ANY CONSTANTS -->
<Color x:Key="SeparatorLineColor">#CCCCCC</Color>
<Color x:Key="iOSDefaultTintColor">#007aff</Color>
<Color x:Key="AndroidDefaultAccentColorColor">#1FAECE</Color>
<OnPlatform x:TypeArguments="Color" x:Key="AccentColor">
<On Platform="iOS" Value="{StaticResource iOSDefaultTintColor}" />
<On Platform="Android" Value="{StaticResource AndroidDefaultAccentColorColor}" />
</OnPlatform>
<!-- BOXVIEW CLASSES -->
<Style TargetType="BoxView" Class="HorizontalRule">
<Setter Property="BackgroundColor" Value="{ StaticResource SeparatorLineColor }" />
<Setter Property="HeightRequest" Value="1" />
</Style>
You'll notice that the Rounded class refers to a custom effect CornerRadius . The code for this effect is given below -
to reference it correctly a custom xmlns must be added to the App.xaml's root element:
xmlns:local="clr-namespace:ThemesDemo;assembly=ThemesDemo"
namespace ThemesDemo
{
public static class ThemeEffects
{
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.CreateAttached("CornerRadius", typeof(double), typeof(ThemeEffects), 0.0,
propertyChanged: OnChanged<CornerRadiusEffect, double>);
private static void OnChanged<TEffect, TProp>(BindableObject bindable, object oldValue, object newValue)
where TEffect : Effect, new()
{
if (!(bindable is View view))
{
return;
}
if (EqualityComparer<TProp>.Equals(newValue, default(TProp)))
{
var toRemove = view.Effects.FirstOrDefault(e => e is TEffect);
if (toRemove != null)
{
view.Effects.Remove(toRemove);
}
}
else
{
view.Effects.Add(new TEffect());
}
}
public static void SetCornerRadius(BindableObject view, double radius)
{
view.SetValue(CornerRadiusProperty, radius);
}
namespace ThemesDemo.iOS
{
public class CornerRadiusEffect : PlatformEffect
{
private nfloat _originalRadius;
UpdateCorner();
}
}
if (args.PropertyName == ThemeEffects.CornerRadiusProperty.PropertyName)
{
UpdateCorner();
}
}
namespace ThemesDemo.Droid
{
public class CornerRadiusEffect : BaseEffect
{
private ViewOutlineProvider _originalProvider;
if (!Attached)
{
return;
}
if (args.PropertyName == ThemeEffects.CornerRadiusProperty.PropertyName)
{
Container.Invalidate();
}
}
Time of type TimeSpan , the selected time, which defaults to a TimeSpan of 0. The TimeSpan type indicates a
duration of time since midnight.
Format of type string , a standard or custom .NET formatting string, which defaults to "t", the short time
pattern.
TextColor of type Color , the color used to display the selected time, which defaults to Color.Default .
FontAttributes of type FontAttributes , which defaults to FontAtributes.None .
FontFamily of type string , which defaults to null .
FontSize of type double , which defaults to -1.0.
All of these properties are backed by BindableProperty objects, which means that they can be styled, and the
properties can be targets of data bindings. The Time property has a default binding mode of BindingMode.TwoWay ,
which means that it can be a target of a data binding in an application that uses the Model-View -ViewModel
(MVVM ) architecture.
The TimePicker doesn't include an event to indicate a new selected Time value. If you need to be notified of this,
you can add a handler for the PropertyChanged event.
When the Time property is specified in XAML, the value is converted to a TimeSpan and validated to ensure that
the number of milliseconds is greater than or equal to 0, and that the number of hours is less than 24. The time
components should be separated by colons:
In this example, the Time property is initialized to the SelectedTime property in the ViewModel. Because the
Time property has a binding mode of TwoWay , any new time that the user selects is automatically propagated to
the ViewModel.
If the TimePicker does not contain a binding on its Time property, an application should attach a handler to the
PropertyChanged event to be informed when the user selects a new time.
For information about setting font properties, see Fonts.
<TimePicker ···
HorizontalOptions="Center"
··· />
However, this is not recommended. Depending on the setting of the Format property, selected times might
require different display widths. For example, the "T" format string causes the TimePicker view to display times in
a long format, and "4:15:26 AM" requires a greater display width than the short time format ("t") of "4:15 AM".
Depending on the platform, this difference might cause the TimePicker view to change width in layout, or for the
display to be truncated.
TIP
It's best to use the default HorizontalOptions setting of Fill with TimePicker , and not to use a width of Auto when
putting TimePicker in a Grid cell.
TimePicker in an application
The SetTimer sample includes TimePicker , Entry , and Switch views on its page. The TimePicker can be used
to select a time, and when that time occurs an alert dialog is displayed that reminds the user of the text in the
Entry , provided the Switch is toggled on. Here's the XAML file:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:SetTimer"
x:Class="SetTimer.MainPage">
<StackLayout>
...
<Entry x:Name="_entry"
Placeholder="Enter event to be reminded of" />
<Label Text="Select the time below to be reminded at." />
<TimePicker x:Name="_timePicker"
Time="11:00:00"
Format="T"
PropertyChanged="OnTimePickerPropertyChanged" />
<StackLayout Orientation="Horizontal">
<Label Text="Enable timer:" />
<Switch x:Name="_switch"
HorizontalOptions="EndAndExpand"
Toggled="OnSwitchToggled" />
</StackLayout>
</StackLayout>
</ContentPage>
The Entry lets you enter reminder text that will be displayed when the selected time occurs. The TimePicker is
assigned a Format property of "T" for long time format. It has an event handler attached to the PropertyChanged
event, and the Switch has a handler attached to its Toggled event. These events handlers are in the code-behind
file and call the SetTriggerTime method:
public MainPage()
{
InitializeComponent();
Device.StartTimer(TimeSpan.FromSeconds(1), OnTimerTick);
}
bool OnTimerTick()
{
if (_switch.IsToggled && DateTime.Now >= _triggerTime)
{
_switch.IsToggled = false;
DisplayAlert("Timer Alert", "The '" + _entry.Text + "' timer has elapsed", "OK");
}
return true;
}
void SetTriggerTime()
{
if (_switch.IsToggled)
{
_triggerTime = DateTime.Today + _timePicker.Time;
if (_triggerTime < DateTime.Now)
{
_triggerTime += TimeSpan.FromDays(1);
}
}
}
}
The SetTriggerTimemethod calculates a timer time based on the DateTime.Today property value and the
TimeSpan value returned from the TimePicker . This is necessary because the DateTime.Today property returns a
DateTime indicating the current date, but with a time of midnight. If the timer time has already passed today, then
it's assumed to be tomorrow.
The timer ticks every second, executing the OnTimerTick method that checks whether the Switch is on and
whether the current time is greater than or equal to the timer time. When the timer time occurs, the DisplayAlert
method presents an alert dialog to the user as a reminder.
When the sample is first run, the TimePicker view is initialized to 11am. Tapping the TimePicker invokes the
platform time picker. The platforms implement the time picker in very different ways, but each approach is familiar
to users of that platform:
TIP
On Android, the TimePicker dialog can be customized by overriding the CreateTimePickerDialog method in a custom
renderer. This allows, for example, additional buttons to be added to the dialog.
Provided that the Switch is toggled to the on position, the application displays an alert dialog reminding the user
of the text in the Entry when the selected time occurs:
As soon as the alert dialog is displayed, the Switch is toggled to the off position.
Related links
SetTimer sample
TimePicker API
Xamarin.Forms Visual
3/14/2019 • 2 minutes to read • Edit Online
IMPORTANT
On Android, the material renderers require a minimum version of 5.0 (API 21) or greater, and a TargetFramework of version
9.0 (API 28). In addition, your platform project requires Android support libraries 28.0.0 or greater, and its theme needs to
inherit from a Material Components theme or continue to inherit from an AppCompat theme. For more information, see
Getting started with Material Components for Android.
Material renderers are currently included in the Xamarin.Forms.Visual.Material NuGet package for the following
views:
Button
Entry
Frame
ProgressBar
DatePicker
TimePicker
Picker
ActivityIndicator
Editor
Slider
Stepper
global::Xamarin.Forms.Forms.Init();
FormsMaterial.Init();
On Android, this should occur in MainActivity.cs by invoking the FormsMaterial.Init method after the
Xamarin.Forms.Forms.Init method:
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
FormsMaterial.Init(this, savedInstanceState);
<ContentPage Visual="Material"
...>
...
</ContentPage>
The Visual property can be set to any type that implements IVisual , with the VisualMarker class providing the
following IVisual properties:
Default – indicates that the view should render using the default renderer.
MatchParent – indicates that the view should use the same renderer as its direct parent.
Material – indicates that the view should render using a material renderer.
IMPORTANT
The Visual property is defined in the VisualElement class, with views inheriting the Visual property value from their
parents. Therefore, setting the Visual property on a ContentPage ensures that any supported views in the page will use
that Visual. In addition, the Visual property can be overridden on a view.
The following screenshots show a user interface rendered using the default renderers:
The following screenshots show the same user interface rendered using the material renderers:
The main visible differences between the default renderers and material renderers, shown here, are that the
material renderers capitalize Button text, and round the corners of Frame borders. However, material renderers
use native controls, and therefore there may still be user interface differences between platforms for areas such as
fonts, shadows, colors, and elevation.
NOTE
Material Design components adhere closely to Google's guidelines. As a result, Material Design renderers are biased towards
that sizing and behavior. When you require greater control of styles or behavior, you can still create your own Effect,
Behavior, or Custom Renderer to achieve the detail you require.
using Xamarin.Forms.Material.Android;
In this example, the ExportRendererAttribute specifies that the CustomMaterialProgressBarRenderer class will be
used to render the ProgressBar view, with the IVisual type registered as the third argument.
NOTE
A renderer that specifies an IVisual type, as part of its ExportRendererAttribute , will be used to render opted in views,
rather than the default renderer. At renderer selection time, the Visual property of the view is inspected and included in
the renderer selection process.
Related links
Material Visual (sample)
Create a Xamarin.Forms Visual Renderer
Custom Renderers
Create a Xamarin.Forms Visual Renderer
3/27/2019 • 3 minutes to read • Edit Online
IMPORTANT
Currently the Visual property cannot be changed after the view has been rendered, but this will change in a future
release.
The process for creating and consuming a Xamarin.Forms Visual renderer is:
1. Create platform renderers for the required view. For more information, see Create renderers.
2. Create a type that derives from IVisual . For more information, see Create an IVisual type.
3. Register the IVisual type as part of the ExportRendererAttribute that decorates the renderers. For more
information, see Register the IVisual type.
4. Consume the Visual renderer by setting the Visual property on the view to the IVisual name. For more
information, see Consume the Visual renderer.
5. [optional] Register a name for the IVisual type. For more information, see Register a name for the IVisual
type.
if (e.OldElement != null)
{
// Cleanup
}
if (e.NewElement != null)
{
Control.TitleShadowOffset = new CoreGraphics.CGSize(1, 1);
Control.SetTitleShadowColor(Color.Black.ToUIColor(), UIKit.UIControlState.Normal);
}
}
}
Android
The following code example shows the button renderer for Android:
if (e.OldElement != null)
{
// Cleanup
}
if (e.NewElement != null)
{
Control.SetShadowLayer(5, 3, 3, Color.Black.ToAndroid());
}
}
}
The CustomVisual type can then be registered against the renderer classes, permitting Button objects to opt into
using the renderers.
In this example, the ExportRendererAttribute specifies that the CustomButtonRenderer class will be used to render
consuming Button objects, with the IVisual type registered as the third argument. A renderer that specifies an
IVisual type, as part of its ExportRendererAttribute , will be used to render opted in views, rather than the default
renderer.
<Button Visual="Custom"
Text="CUSTOM BUTTON"
BackgroundColor="{StaticResource PrimaryColor}"
TextColor="{StaticResource SecondaryTextColor}"
HorizontalOptions="FillAndExpand" />
NOTE
In XAML, a type converter removes the need to include the "Visual" suffix in the Visual property value. However, the full
type name can also be specified.
At renderer selection time, the Visual property of the Button is inspected and included in the renderer selection
process. If a renderer isn't located, the Xamarin.Forms default renderer will be used.
The following screenshots show the rendered Button , which displays its text with a shadow:
The IVisual type can then be consumed through its registered name:
<Button Visual="MyVisual"
... />
NOTE
When consuming a Visual through its registered name, any "Visual" suffix must be included.
Related links
Material Visual (sample)
Xamarin.Forms Material Visual
Custom Renderers
The Xamarin.Forms Visual State Manager
5/1/2019 • 15 minutes to read • Edit Online
You can also define your own visual state groups and visual states, as this article will demonstrate.
NOTE
Xamarin.Forms developers familiar with triggers are aware that triggers can also make changes to visuals in the user
interface based on changes in a view's properties or the firing of events. However, using triggers to deal with various
combinations of these changes can become quite confusing. Historically, the Visual State Manager was introduced in
Windows XAML-based environments to alleviate the confusion resulting from combinations of visual states. With the VSM,
the visual states within a visual state group are always mutually exclusive. At any time, only one state in each group is the
current state.
<Entry FontSize="18">
</Entry>
It's given an explicit font size because one of the states will use the FontSize property to double the size of the
text in the Entry .
Next, insert VisualStateManager.VisualStateGroups tags between those tags:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
</VisualStateManager.VisualStateGroups>
</Entry>
VisualStateGroups is an attached bindable property defined by the VisualStateManager class. (For more
information on attached bindable properties, see the article Attached properties.) This is how the
VisualStateGroups property is attached to the Entry object.
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Notice that the VisualStateGroup tag has an x:Name attribute indicating the name of the group. The
VisualStateGroup class defines a Name property that you can use instead:
<VisualStateGroup Name="CommonStates">
You can use either x:Name or Name but not both in the same element.
The VisualStateGroup class defines a property named States , which is a collection of VisualState objects.
States is the content property of VisualStateGroups so you can include the VisualState tags directly between
the VisualStateGroup tags. (Content properties are discussed in the article Essential XAML Syntax.)
The next step is to include a pair of tags for every visual state in that group. These also can be identified using
x:Name or Name :
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
</VisualState>
<VisualState x:Name="Focused">
</VisualState>
<VisualState x:Name="Disabled">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
VisualState defines a property named Setters , which is a collection of Setter objects. These are the same
Setter objects that you use in a Style object.
Setters is not the content property of VisualState , so it is necessary to include property element tags for the
Setters property:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
You can now insert one or more Setter objects between each pair of Setters tags. These are the Setter
objects that define the visual states described earlier:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Each Setter tag indicates the value of a particular property when that state is current. Any property referenced
by a Setter object must be backed by a bindable property.
Markup similar to this is the basis of the VSM on View page in the VsmDemos sample program. The page
includes three Entry views, but only the second one has the VSM markup attached to it:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:VsmDemos"
x:Class="VsmDemos.MainPage"
Title="VSM Demos">
<StackLayout>
<StackLayout.Resources>
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>
<Style TargetType="Label">
<Setter Property="Margin" Value="20, 30, 20, 0" />
<Setter Property="FontSize" Value="Large" />
</Style>
</StackLayout.Resources>
<Entry />
<Entry>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Entry.Triggers>
<DataTrigger TargetType="Entry"
Binding="{Binding Source={x:Reference entry3},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Entry.Triggers>
</Entry>
<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
Notice that the second Entry also has a DataTrigger as part of its Trigger collection. This causes the Entry to
be disabled until something is typed into the third Entry . Here's the page at startup running on iOS, Android,
and the Universal Windows Platform (UWP ):
The current visual state is "Disabled" so the background of the second Entry is pink on the iOS and Android
screens. The UWP implementation of Entry does not allow setting the background color when the Entry is
disabled.
When you enter some text into the third Entry , the second Entry switches into the "Normal" state, and the
background is now lime:
When you touch the second Entry , it gets the input focus. It switches to the "Focused" state and expands to
twice its height:
Notice that the Entry does not retain the lime background when it gets the input focus. As the Visual State
Manager switches between the visual states, the properties set by the previous state are unset. Keep in mind that
the visual states are mutually exclusive. The "Normal" state does not mean solely that the Entry is enabled. It
means that the Entry is enabled and does not have input focus.
If you want the Entry to have a lime background in the "Focused" state, add another Setter to that visual state:
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
In order for these Setter objects to work properly, a VisualStateGroup must contain VisualState objects for all
the states in that group. If there is a visual state that does not have any Setter objects, include it anyway as an
empty tag:
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>
</Setter>
</Style>
The content property for Setter is Value , so the value of the Value property can be specified directly within
those tags. That property is of type VisualStateGroupList :
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
</VisualStateGroupList>
</Setter>
</Style>
Within those tags you can include one of more VisualStateGroup objects:
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label">
<Setter Property="Margin" Value="20, 30, 20, 0" />
<Setter Property="FontSize" Value="Large" />
</Style>
</StackLayout.Resources>
<Entry />
<Entry>
<Entry.Triggers>
<DataTrigger TargetType="Entry"
Binding="{Binding Source={x:Reference entry3},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Entry.Triggers>
</Entry>
<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
Now all the Entry views on this page respond the same way to their visual states. Notice also that the "Focused"
state now includes a second Setter that gives each Entry a lime background also when it has input focus:
VisualStateManager.GoToState(this, "Focused");
This is the only Visual State Manager code that you'll find in the VisualElement class. Because GoToState is
called for every object based on every class that derives from VisualElement , you can use the Visual State
Manager with any VisualElement object to respond to these changes.
Interestingly, the name of the visual state group "CommonStates" is not explicitly referenced in VisualElement .
The group name is not part of the API for the Visual State Manager. Within one of the two sample program
shown so far, you can change the name of the group from "CommonStates" to anything else, and the program
will still work. The group name is merely a general description of the states in that group. It is implicitly
understood that the visual states in any group are mutually exclusive: One state and only one state is current at
any time.
If you want to implement your own visual states, you'll need to call VisualStateManager.GoToState from code.
Most often you'll make this call from the code-behind file of your page class.
The VSM Validation page in the VsmDemos sample shows how to use the Visual State Manager in connection
with input validation. The XAML file consists of two Label elements, an Entry , and Button :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmValidationPage"
Title="VSM Validation">
<StackLayout Padding="10, 10">
<Entry Placeholder="555-555-5555"
FontSize="Large"
Margin="30, 0, 0, 0"
TextChanged="OnTextChanged" />
<Label x:Name="helpLabel"
Text="Phone number must be of the form 555-555-5555, and not begin with a 0 or 1">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ValidityStates">
<VisualState Name="Valid">
<VisualState.Setters>
<Setter Property="TextColor" Value="Transparent" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Label>
<Button x:Name="submitButton"
Text="Submit"
FontSize="Large"
Margin="0, 20"
VerticalOptions="Center"
HorizontalOptions="Center">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ValidityStates">
<VisualState Name="Invalid">
<VisualState.Setters>
<Setter Property="IsEnabled" Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
</ContentPage>
VSM markup is attached to the second Label (named helpLabel ) and the Button (named submitButton ).
There are two mutually-exclusive states, named "Valid" and "Invalid". Notice that each of the two
"ValidationState" groups contains VisualState tags for both "Valid" and "Invalid", although one of them is empty
in each case.
If the Entry does not contain a valid phone number, then the current state is "Invalid", and so the second Label
is visible and the Button is disabled:
When a valid phone number is entered, then the current state becomes "Valid". The second Entry disappears
and the Button is now enabled:
The code-behind file is reponsible for handling the TextChanged event from the Entry . The handler uses a
regular expression to determine if the input string is valid or not. The method in the code-behind file named
GoToState calls the static VisualStateManager.GoToState method for both helpLabel and submitButton :
public partial class VsmValidationPage : ContentPage
{
public VsmValidationPage ()
{
InitializeComponent ();
GoToState(false);
}
Notice also that the GoToState method is called from the constructor to initialize the state. There should always
be a current state. But nowhere in the code is there any reference to the name of the visual state group, although
it's referenced in the XAML as "ValidationStates" for purposes of clarity.
Notice that the code-behind file must take account of every object on the page that is affected by these visual
states, and to call VisualStateManager.GoToState for each of these objects. In this example, it's only two objects
(the Label and the Button ), but it could be several more.
You might wonder: If the code-behind file must reference every object on the page that is affected by these visual
states, why can't the code-behind file simply access the objects directly? It surely could. However, the advantage
of using the VSM is that you can control how visual elements react to different state entirely in XAML, which
keeps all of the UI design in one location. This avoids setting visual appearance by accessing visual elements
directly from the code-behind.
It might be tempting to consider deriving a class from Entry and perhaps defining a property that you can set to
an external validation function. The class that derives from Entry can then call the VisualStateManager.GoToState
method. This scheme would work fine, but only if the Entry were the only object affected by the different visual
states. In this example, a Label and a Button are also be affected. There is no way for VSM markup attached to
an Entry to control other objects on the page, and no way for VSM markup attached to these other objects to
reference a change in visual state from another object.
From top to bottom, the program is running on the Universal Windows Platform, Android, and iOS.
The VSM Adaptive Layout page in the VsmDemos sample defines a group named "OrientationStates" with
two visual states named "Portrait" and "Landscape". (A more complex approach might be based on several
different page or window widths.)
VSM markup occurs in four places in the XAML file. The StackLayout named mainStack contains both the menu
and the content, which is an Image element. This StackLayout should have a vertical orientation in portrait
mode and a horizontal orientation in landscape mode:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmAdaptiveLayoutPage"
Title="VSM Adaptive Layout">
<StackLayout x:Name="mainStack">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ScrollView x:Name="menuScroll">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout x:Name="menuStack">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout.Resources>
<Style TargetType="Button">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="HorizontalOptions" Value="CenterAndExpand" />
<Setter Property="Margin" Value="10, 5" />
<Setter Property="Margin" Value="10, 5" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="Margin" Value="10" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</StackLayout.Resources>
<Button Text="Banana"
Command="{Binding SelectedCommand}"
CommandParameter="Banana.jpg" />
<Button Text="Monkey"
Command="{Binding SelectedCommand}"
CommandParameter="monkey.png" />
<Image x:Name="image"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>
The inner ScrollView named menuScroll and the StackLayout named menuStack implement the menu of
buttons. The orientation of these layouts is opposite of mainStack . The menu should be horizontal in portrait
mode and vertical in landscape mode.
The fourth section of VSM markup is in an implicit style for the buttons themselves. This markup sets
VerticalOptions , HorizontalOptions , and Margin properties specific to the portait and landscape orientations.
The code-behind file sets the BindingContext property of menuStack to implement Button commanding, and
also attaches a handler to the SizeChanged event of the page:
public partial class VsmAdaptiveLayoutPage : ContentPage
{
public VsmAdaptiveLayoutPage ()
{
InitializeComponent ();
menuStack.BindingContext = this;
}
The SizeChanged handler calls VisualStateManager.GoToState for the two StackLayout and ScrollView elements,
and then loops through the children of menuStack to call VisualStateManager.GoToState for the Button elements.
It may seem as if the code-behind file can handle orientation changes more directly by setting properties of
elements in the XAML file, but the Visual State Manager is definitely a more structured approach. All the visuals
are kept in the XAML file, where they become easier to examine, maintain, and modify.
Related links
VsmDemos
Xamarin.Forms WebView
4/26/2019 • 10 minutes to read • Edit Online
Content
WebView supports the following types of content:
HTML & CSS websites – WebView has full support for websites written using HTML & CSS, including
JavaScript support.
Documents – Because WebView is implemented using native components on each platform, WebView is
capable of showing documents that are viewable on each platform. That means that PDF files work on iOS and
Android.
HTML strings – WebView can show HTML strings from memory.
Local Files – WebView can present any of the content types above embedded in the app.
NOTE
WebView on Windows does not support Silverlight, Flash or any ActiveX controls, even if they are supported by Internet
Explorer on that platform.
Websites
To display a website from the internet, set the WebView 's Source property to a string URL:
var browser = new WebView
{
Source = "http://xamarin.com"
};
NOTE
URLs must be fully formed with the protocol specified (i.e. it must have "http://" or "https://" prepended to it).
NOTE
If your application requires a connection to an insecure website, you should always enter the domain as an exception using
NSExceptionDomains instead of turning ATS off completely using NSAllowsArbitraryLoads . NSAllowsArbitraryLoads
should only be used in extreme emergency situations.
The following demonstrates how to enable a specific domain (in this case xamarin.com) to bypass ATS
requirements:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>xamarin.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
...
</key>
It is best practice to only enable some domains to bypass ATS, allowing you to use trusted sites while benefitting
from the additional security on untrusted domains. The following demonstrates the less secure method of
disabling ATS for the app:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads </key>
<true/>
</dict>
...
</key>
See App Transport Security for more information about this new feature in iOS 9.
HTML Strings
If you want to present a string of HTML defined dynamically in code, you'll need to create an instance of
HtmlWebViewSource :
In the above code, @ is used to mark the HTML as a string literal, meaning all the usual escape characters are
ignored.
NOTE
It may be necessary to set the WidthRequest and HeightRequest properties of the WebView to see the HTML content,
depending upon the layout the WebView is a child of. For example, this is required in a StackLayout .
CSS:
html,body {
margin:0;
padding:10;
}
body,p,h1 {
font-family: Chalkduster;
}
Note that the fonts specified in the above CSS will need to be customized for each platform, as not every platform
has the same fonts.
To display local content using a WebView , you'll need to open the HTML file like any other, then load the contents
as a string into the Html property of an HtmlWebViewSource . For more information on opening files, see Working
with Files.
The following screenshots show the result of displaying local content on each platform:
Although the first page has been loaded, the WebView has no knowledge of where the HTML came from. That is a
problem when dealing with pages that reference local resources. Examples of when that might happen include
when local pages link to each other, a page makes use of a separate JavaScript file, or a page links to a CSS
stylesheet.
To solve this, you need to tell the WebView where to find files on the filesystem. Do that by setting the BaseUrl
property on the HtmlWebViewSource used by the WebView .
Because the filesystem on each of the operating systems is different, you need to determine that URL on each
platform. Xamarin.Forms exposes the DependencyService for resolving dependencies at runtime on each platform.
To use the DependencyService , first define an interface that can be implemented on each platform:
Note that until the interface is implemented on each platform, the app will not run. In the common project, make
sure that you remember to set the BaseUrl using the DependencyService :
Android
On Android, place HTML, CSS, and images in the Assets folder with build action AndroidAsset as demonstrated
below:
Visual Studio
Visual Studio for Mac
On Android, the BaseUrl should be set to "file:///android_asset/" :
On Android, files in the Assets folder can also be accessed through the current Android context, which is exposed
by the MainActivity.Instance property:
[assembly: Dependency(typeof(BaseUrl))]
namespace WorkingWithWebview.UWP
{
public class BaseUrl : IBaseUrl
{
public string Get()
{
return "ms-appx-web:///";
}
}
}
Navigation
WebView supports navigation through several methods and properties that it makes available:
GoForward() – if CanGoForward is true, calling GoForward navigates forward to the next visited page.
GoBack() – if CanGoBack is true, calling GoBack will navigate to the last visited page.
CanGoBack – true if there are pages to navigate back to, false if the browser is at the starting URL.
CanGoForward – true if the user has navigated backwards and can move forward to a page that was already
visited.
Within pages, WebView does not support multi-touch gestures. It is important to make sure that content is mobile-
optimized and appears without the need for zooming.
It is common for applications to show a link within a WebView , rather than the device's browser. In those situations,
it is useful to allow normal navigation, but when the user hits back while they are on the starting link, the app
should return to the normal app view.
Use the built-in navigation methods and properties to enable this scenario.
Start by creating the page for the browser view:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewSample.InAppBrowserXaml"
Title="Browser">
<StackLayout Margin="20">
<StackLayout Orientation="Horizontal">
<Button Text="Back" HorizontalOptions="StartAndExpand" Clicked="OnBackButtonClicked" />
<Button Text="Forward" HorizontalOptions="EndAndExpand" Clicked="OnForwardButtonClicked" />
</StackLayout>
<!-- WebView needs to be given height and width request within layouts to render. -->
<WebView x:Name="webView" WidthRequest="1000" HeightRequest="1000" />
</StackLayout>
</ContentPage>
In the code-behind:
public partial class InAppBrowserXaml : ContentPage
{
public InAppBrowserXaml(string URL)
{
InitializeComponent();
webView.Source = URL;
}
That's it!
Events
WebView raises the following events to help you respond to changes in state:
Navigating – event raised when the WebView begins loading a new page.
Navigated – event raised when the page is loaded and navigation has stopped.
ReloadRequested – event raised when a request is made to reload the current content.
The WebNavigatingEventArgs object that accompanies the Navigating event has four properties:
Cancel – indicates whether or not to cancel the navigation.
NavigationEvent – the navigation event that was raised.
Source – the element that performed the navigation.
Url – the navigation destination.
The WebNavigatedEventArgs object that accompanies the Navigated event has four properties:
– the navigation event that was raised.
NavigationEvent
Result – describes the result of the navigation, using a WebNavigationResult enumeration member. Valid
values are Cancel , Failure , Success , and Timeout .
Source – the element that performed the navigation.
Url – the navigation destination.
If you anticipate using webpages that take a long time to load, consider using the Navigating and Navigated
events to implement a status indicator. For example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewSample.LoadingLabelXaml"
Title="Loading Demo">
<StackLayout>
<!--Loading label should not render by default.-->
<Label x:Name="labelLoading" Text="Loading..." IsVisible="false" />
<WebView HeightRequest="1000" WidthRequest="1000" Source="http://www.xamarin.com"
Navigated="webviewNavigated" Navigating="webviewNavigating" />
</StackLayout>
</ContentPage>
When the Reload method is invoked the ReloadRequested event is fired, indicating that a request has been made
to reload the current content.
Performance
The popular web browsers now adopt technologies like hardware accelerated rendering and JavaScript
compilation. On iOS, by default, the Xamarin.Forms WebView is implemented by the UIWebView class, and many of
these technologies are unavailable in this implementation. However, an application can opt-in to using the iOS
WkWebView class to implement the Xamarin.Forms WebView , which supports faster browsing. This can be achieved
by adding the following code to the AssemblyInfo.cs file in the iOS platform project for the application:
Permissions
In order for WebView to work, you must make sure that permissions are set for each platform. Note that on some
platforms, WebView will work in debug mode, but not when built for release. That is because some permissions,
like those for internet access on Android, are set by default by Visual Studio for Mac when in debug mode.
UWP – requires the Internet (Client & Server) capability when displaying network content.
Android – requires INTERNET only when displaying content from the network. Local content requires no
special permissions.
iOS – requires no special permissions.
Layout
Unlike most other Xamarin.Forms views, WebView requires that HeightRequest and WidthRequest are specified
when contained in StackLayout or RelativeLayout. If you fail to specify those properties, the WebView will not
render.
The following examples demonstrate layouts that result in working, rendering WebView s:
StackLayout with WidthRequest & HeightRequest:
<StackLayout>
<Label Text="test" />
<WebView Source="http://www.xamarin.com/"
HeightRequest="1000"
WidthRequest="1000" />
</StackLayout>
RelativeLayout with WidthRequest & HeightRequest:
<RelativeLayout>
<Label Text="test"
RelativeLayout.XConstraint= "{ConstraintExpression
Type=Constant, Constant=10}"
RelativeLayout.YConstraint= "{ConstraintExpression
Type=Constant, Constant=20}" />
<WebView Source="http://www.xamarin.com/"
RelativeLayout.XConstraint="{ConstraintExpression Type=Constant,
Constant=10}"
RelativeLayout.YConstraint="{ConstraintExpression Type=Constant,
Constant=50}"
WidthRequest="1000" HeightRequest="1000" />
</RelativeLayout>
<AbsoluteLayout>
<Label Text="test" AbsoluteLayout.LayoutBounds="0,0,100,100" />
<WebView Source="http://www.xamarin.com/"
AbsoluteLayout.LayoutBounds="0,150,500,500" />
</AbsoluteLayout>
Grid without WidthRequest & HeightRequest. Grid is one of the few layouts that does not require specifying
requested heights and widths.:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="test" Grid.Row="0" />
<WebView Source="http://www.xamarin.com/" Grid.Row="1" />
</Grid>
Invoking JavaScript
WebView includes the ability to invoke a JavaScript function from C#, and return any result to the calling C# code.
This is accomplished with the WebView.EvaluateJavaScriptAsync method, which is shown in the following example
from the WebView sample:
The WebView.EvaluateJavaScriptAsync method evaluates the JavaScript that's specified as the argument, and
returns any result as a string . In this example, the factorial JavaScript function is invoked, which returns the
factorial of number as a result. This JavaScript function is defined in the local HTML file that the WebView loads,
and is shown in the following example:
<html>
<body>
<script type="text/javascript">
function factorial(num) {
if (num === 0 || num === 1)
return 1;
for (var i = num - 1; i >= 1; i--) {
num *= i;
}
return num;
}
</script>
</body>
</html>
Related Links
Working with WebView (sample)
WebView (sample)
Xamarin.Forms Platform Features
1/10/2019 • 2 minutes to read • Edit Online
Xamarin.Forms is extensible and lets you incorporate platform-specific features using effects, custom renderers, the
DependencyService, the MessagingCenter, and more.
Android
This guide describes the Android platform-specifics provided by Xamarin.Forms, and how to implement Material
Design by updating existing Xamarin.Forms Android apps.
Device class
How to use the Device class to create platform-specific behavior in shared code and the user interface (including
using XAML ). Also covers BeginInvokeOnMainThread which is essential when modifying UI controls from
background threads.
iOS
This guide describes the iOS platform-specifics provided by Xamarin.Forms, and how to perform additional iOS
styling via Info.plist and the UIAppearance API.
Native forms
Native Forms allow Xamarin.Forms ContentPage -derived pages to be consumed by native Xamarin.iOS,
Xamarin.Android, and Universal Windows Platform (UWP ) projects.
Native views
Native views from iOS, Android, and the Universal Windows Platform can be directly referenced from
Xamarin.Forms. Properties and event handlers can be set on native views, and they can interact with
Xamarin.Forms views.
Platform-specifics
Platform-specifics allow you to consume functionality that's only available on a specific platform, without requiring
custom renderers or effects. In addition, vendors can create their own platform-specifics with Effects.
Windows
This guide describes the Windows platform-specifics provided by Xamarin.Forms, and how to add a UWP project
to an existing Xamarin.Forms solution.
Android Platform Features
3/1/2019 • 2 minutes to read • Edit Online
Developing Xamarin.Forms applications for Android requires Visual Studio. The requirements page contains more
information about the pre-requisites.
Platform-specifics
Platform-specifics allow you to consume functionality that's only available on a specific platform, without
implementing custom renderers or effects.
The following platform-specific functionality is provided for Xamarin.Forms views, pages, and layouts on Android:
Controlling the Z -order of visual elements to determine drawing order. For more information, see
VisualElement Elevation on Android.
Disabling legacy color mode on a supported VisualElement . For more information, see VisualElement Legacy
Color Mode on Android.
The following platform-specific functionality is provided for Xamarin.Forms views on Android:
Using the default padding and shadow values of Android buttons. For more information, see Button Padding
and Shadows on Android.
Setting the input method editor options for the soft keyboard for an Entry . For more information, see Entry
Input Method Editor Options on Android.
Enabling a drop shadow on a ImageButton . For more information, see ImageButton Drop Shadows on
Android.
Enabling fast scrolling in a ListView For more information, see ListView Fast Scrolling on Android.
Controlling whether a WebView can display mixed content. For more information, see WebView Mixed Content
on Android.
The following platform-specific functionality is provided for Xamarin.Forms pages on Android:
Setting the height of the navigation bar on a NavigationPage . For more information, see NavigationPage Bar
Height on Android.
Disabling transition animations when navigating through pages in a TabbedPage . For more information, see
TabbedPage Page Transition Animations on Android.
Enabling swiping between pages in a TabbedPage . For more information, see TabbedPage Page Swiping on
Android.
Setting the toolbar placement and color on a TabbedPage . For more information, see TabbedPage Toolbar
Placement and Color on Android.
The following platform-specific functionality is provided for the Xamarin.Forms Application class on Android:
Setting the operating mode of a soft keyboard. For more information, see Soft Keyboard Input Mode on
Android.
Disabling the Disappearing and Appearing page lifecycle events on pause and resume respectively, for
applications that use AppCompat. For more information, see Page Lifecycle Events on Android.
Platform support
Originally, the default Xamarin.Forms Android project used an older style of control rendering that was common
prior to Android 5.0. Applications built using the template have FormsApplicationActivity as the base class of their
main activity.
And this is the same code after upgrading the project to use FormsAppCompatActivity (and adding the additional
theme information):
NOTE
When using FormsAppCompatActivity , the base classes for some Android custom renderers will be different.
Related links
Add Material Design Support
Adding AppCompat and Material Design
3/8/2019 • 2 minutes to read • Edit Online
Follow these steps to convert existing Xamarin.Forms Android apps to use AppCompat and Material Design
Overview
These instructions explain how to update your existing Xamarin.Forms Android applications to use the
AppCompat library and enable Material Design in the Android version of your Xamarin.Forms apps.
1. Update Xamarin.Forms
Ensure the solution is using Xamarin.Forms 2.0 or newer. Update the Xamarin.Forms Nuget package to 2.0 if
required.
2. Check Android version
Ensure the Android project's target framework is Android 6.0 (Marshmallow ). Check the Android project >
Options > Build > General settings to ensure the corrent framework is selected:
<resources>
<color name="primary">#2196F3</color>
<color name="primaryDark">#1976D2</color>
<color name="accent">#FFC107</color>
<color name="window_background">#F5F5F5</color>
</resources>
Resources/values/style.xml
<resources>
<style name="MyTheme" parent="MyTheme.Base">
</style>
<style name="MyTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primaryDark</item>
<item name="colorAccent">@color/accent</item>
<item name="android:windowBackground">@color/window_background</item>
<item name="windowActionModeOverlay">true</item>
</style>
</resources>
An additional style must be included in the values-v21 folder to apply specific properties when running on
Android Lollipop and newer.
Resources/values-v21/style.xml
<resources>
<style name="MyTheme" parent="MyTheme.Base">
<!--If you are using MasterDetailPage you will want to set these, else you can leave them out-->
<!--<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>-->
</style>
</resources>
4. Update AndroidManifest.xml
To ensure this new theme information is used, set theme in the AndroidManifest file by adding
android:theme="@style/MyTheme" (leave the rest of the XML as it was).
Properties/AndroidManifest.xml
...
<application android:label="AppName" android:icon="@drawable/icon"
android:theme="@style/MyTheme">
...
<android.support.design.widget.TabLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:tabIndicatorColor="@android:color/white"
app:tabGravity="fill"
app:tabMode="fixed" />
A few properties for the tabs have been set including the tab’s gravity to fill and mode to fixed . If you have a
lot of tabs you may want to switch this to scrollable - read through the Android TabLayout documentation to learn
more.
Resources/layout/Toolbar.axml
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways" />
In these files we're creating specific theme for the toolbar that may vary for your application. Refer to the Hello
Toolbar blog post to learn more.
6. Update the MainActivity
In existing Xamarin.Forms apps the MainActivity.cs class will inherit from FormsApplicationActivity . This must
be replaced with FormsAppCompatActivity to enable the new functionality.
MainActivity.cs
Finally, "wire up" the new layouts from step 5 in the OnCreate method, as shown here:
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
...
<Button ...
android:Button.UseDefaultPadding="true"
android:Button.UseDefaultShadow="true" />
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
button.On<Android>().SetUseDefaultPadding(true).SetUseDefaultShadow(true);
The Button.On<Android> method specifies that this platform-specific will only run on Android. The
Button.SetUseDefaultPadding and Button.SetUseDefaultShadow methods, in the
Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, are used to control whether Xamarin.Forms
buttons use the default padding and shadow values of Android buttons. In addition, the Button.UseDefaultPadding
and Button.UseDefaultShadow methods can be used to return whether a button uses the default padding value and
default shadow value, respectively.
The result is that Xamarin.Forms buttons can use the default padding and shadow values of Android buttons:
Note that in the screenshot above each Button has identical definitions, except that the right-hand Button uses
the default padding and shadow values of Android buttons.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
Entry Input Method Editor Options on Android
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout ...>
<Entry ... android:Entry.ImeOptions="Send" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
entry.On<Android>().SetImeOptions(ImeFlags.Send);
The method specifies that this platform-specific will only run on Android. The
Entry.On<Android>
Entry.SetImeOptions method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, is used to
set the input method action option for the soft keyboard for the Entry , with the ImeFlags enumeration providing
the following values:
Default – indicates that no specific action key is required, and that the underlying control will produce its own
if it can. This will either be Next or Done .
None – indicates that no action key will be made available.
Go – indicates that the action key will perform a "go" operation, taking the user to the target of the text they
typed.
Search – indicates that the action key performs a "search" operation, taking the user to the results of searching
for the text they have typed.
Send – indicates that the action key will perform a "send" operation, delivering the text to its target.
Next – indicates that the action key will perform a "next" operation, taking the user to the next field that will
accept text.
Done – indicates that the action key will perform a "done" operation, closing the soft keyboard.
Previous – indicates that the action key will perform a "previous" operation, taking the user to the previous
field that will accept text.
ImeMaskAction – the mask to select action options.
NoPersonalizedLearning – indicates that the spellchecker will neither learn from the user, nor suggest
corrections based on what the user has previously typed.
NoFullscreen – indicates that the UI should not go fullscreen.
NoExtractUi – indicates that no UI will be shown for extracted text.
NoAccessoryAction – indicates that no UI will be displayed for custom actions.
The result is that a specified ImeFlags value is applied to the soft keyboard for the Entry , which sets the input
method editor options:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
ImageButton Drop Shadows on Android
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ImageButton ...
Source="XamarinLogo.png"
BackgroundColor="GhostWhite"
android:ImageButton.IsShadowEnabled="true"
android:ImageButton.ShadowColor="Gray"
android:ImageButton.ShadowRadius="12">
<android:ImageButton.ShadowOffset>
<Size>
<x:Arguments>
<x:Double>10</x:Double>
<x:Double>10</x:Double>
</x:Arguments>
</Size>
</android:ImageButton.ShadowOffset>
</ImageButton>
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
IMPORTANT
A drop shadow is drawn as part of the ImageButton background, and the background is only drawn if the
BackgroundColor property is set. Therefore, a drop shadow will not be drawn if the ImageButton.BackgroundColor
property isn't set.
The ImageButton.On<Android>method specifies that this platform-specific will only run on Android. The
ImageButton.SetIsShadowEnabled method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace,
is used to control whether a drop shadow is enabled on the ImageButton . In addition, the following methods can
be invoked to control the drop shadow:
SetShadowColor – sets the color of the drop shadow. The default color is Color.Default .
SetShadowOffset – sets the offset of the drop shadow. The offset changes the direction the shadow is cast, and is
specified as a Size value. The Size structure values are expressed in device-independent units, with the first
value being the distance to the left (negative value) or right (positive value), and the second value being the
distance above (negative value) or below (positive value). The default value of this property is (0.0, 0.0), which
results in the shadow being cast around every side of the ImageButton .
SetShadowRadius – sets the blur radius used to render the drop shadow. The default radius value is 10.0.
NOTE
The state of a drop shadow can be queried by calling the GetIsShadowEnabled , GetShadowColor , GetShadowOffset , and
GetShadowRadius methods.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
ListView Fast Scrolling on Android
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
...
<ListView ItemsSource="{Binding GroupedEmployees}"
GroupDisplayBinding="{Binding Key}"
IsGroupingEnabled="true"
android:ListView.IsFastScrollEnabled="true">
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
The ListView.On<Android> method specifies that this platform-specific will only run on Android. The
ListView.SetIsFastScrollEnabled method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace,
is used to enable fast scrolling through data in a ListView . In addition, the SetIsFastScrollEnabled method can be
used to toggle fast scrolling by calling the IsFastScrollEnabled method to return whether fast scrolling is enabled:
listView.On<Android>().SetIsFastScrollEnabled(!listView.On<Android>().IsFastScrollEnabled());
The result is that fast scrolling through data in a ListView can be enabled, which changes the size of the scroll
thumb:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
NavigationPage Bar Height on Android
1/10/2019 • 2 minutes to read • Edit Online
<NavigationPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;assembly=Xamarin.Forms.Core"
android:NavigationPage.BarHeight="450">
...
</NavigationPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;
...
The NavigationPage.On<Android> method specifies that this platform-specific will only run on app compat Android.
The NavigationPage.SetBarHeight method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat
namespace, is used to set the height of the navigation bar on a NavigationPage . In addition, the
NavigationPage.GetBarHeight method can be used to return the height of the navigation bar in the NavigationPage .
The result is that the height of the navigation bar on a NavigationPage can be set:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
Page Lifecycle Events on Android
1/10/2019 • 2 minutes to read • Edit Online
NOTE
Note that these events are enabled by default to preserve existing behavior for applications that rely on the events. Disabling
these events makes the AppCompat event cycle match the pre-AppCompat event cycle.
<Application ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:androidAppCompat="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;assembly=Xamarin.Forms.Core"
android:Application.WindowSoftInputModeAdjust="Resize"
androidAppCompat:Application.SendDisappearingEventOnPause="false"
androidAppCompat:Application.SendAppearingEventOnResume="false"
androidAppCompat:Application.ShouldPreserveKeyboardOnResume="true">
...
</Application>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;
...
Xamarin.Forms.Application.Current.On<Android>()
.UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize)
.SendDisappearingEventOnPause(false)
.SendAppearingEventOnResume(false)
.ShouldPreserveKeyboardOnResume(true);
The Application.Current.On<Android> method specifies that this platform-specific will only run on Android. The
Application.SendDisappearingEventOnPause method, in the
Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat namespace, is used to enable or disable firing the
Disappearing page event, when the application enters the background. The
Application.SendAppearingEventOnResume method is used to enable or disable firing the Appearing page event,
when the application resumes from the background. The Application.ShouldPreserveKeyboardOnResume method is
used control whether the soft keyboard is displayed on resume, if it was displayed on pause, provided that the
operating mode of the soft keyboard is set to WindowSoftInputModeAdjust.Resize .
The result is that the Disappearing and Appearing page events won't be fired on application pause and resume
respectively, and that if the soft keyboard was displayed when the application was paused, it will also be displayed
when the application resumes:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
Soft Keyboard Input Mode on Android
1/10/2019 • 2 minutes to read • Edit Online
<Application ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:Application.WindowSoftInputModeAdjust="Resize">
...
</Application>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
App.Current.On<Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
The Application.On<Android> method specifies that this platform-specific will only run on Android. The
Application.UseWindowSoftInputModeAdjust method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace, is used to set the soft keyboard input area operating mode, with the WindowSoftInputModeAdjust
enumeration providing two values: Pan and Resize . The Pan value uses the AdjustPan adjustment option,
which doesn't resize the window when an input control has focus. Instead, the contents of the window are panned
so that the current focus isn't obscured by the soft keyboard. The Resize value uses the AdjustResize adjustment
option, which resizes the window when an input control has focus, to make room for the soft keyboard.
The result is that the soft keyboard input area operating mode can be set when an input control has focus:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
TabbedPage Page Swiping on Android
1/10/2019 • 2 minutes to read • Edit Online
<TabbedPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.OffscreenPageLimit="2"
android:TabbedPage.IsSwipePagingEnabled="true">
...
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
On<Android>().SetOffscreenPageLimit(2)
.SetIsSwipePagingEnabled(true);
The TabbedPage.On<Android> method specifies that this platform-specific will only run on Android. The
TabbedPage.SetIsSwipePagingEnabled method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace, is used to enable swiping between pages in a TabbedPage . In addition, the TabbedPage class in the
Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace also has a EnableSwipePaging method that
enables this platform-specific, and a DisableSwipePaging method that disables this platform-specific. The
TabbedPage.OffscreenPageLimit attached property, and SetOffscreenPageLimit method, are used to set the number
of pages that should be retained in an idle state on either side of the current page.
The result is that swipe paging through the pages displayed by a TabbedPage is enabled:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
TabbedPage Page Transition Animations on Android
1/10/2019 • 2 minutes to read • Edit Online
<TabbedPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.IsSmoothScrollEnabled="false">
...
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
On<Android>().SetIsSmoothScrollEnabled(false);
The TabbedPage.On<Android> method specifies that this platform-specific will only run on Android. The
TabbedPage.SetIsSmoothScrollEnabled method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace, is used to control whether transition animations will be displayed when navigating between pages in a
TabbedPage . In addition, the TabbedPage class in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace also has the following methods:
IsSmoothScrollEnabled, which is used to retrieve whether transition animations will be displayed when
navigating between pages in a TabbedPage .
EnableSmoothScroll , which is used to enable transition animations when navigating between pages in a
TabbedPage .
DisableSmoothScroll , which is used to disable transition animations when navigating between pages in a
TabbedPage .
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
TabbedPage Toolbar Placement and Color on
Android
1/10/2019 • 2 minutes to read • Edit Online
<TabbedPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
android:TabbedPage.BarItemColor="Black"
android:TabbedPage.BarSelectedItemColor="Red">
...
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
On<Android>().SetToolbarPlacement(ToolbarPlacement.Bottom)
.SetBarItemColor(Color.Black)
.SetBarSelectedItemColor(Color.Red);
The TabbedPage.On<Android> method specifies that these platform-specifics will only run on Android. The
TabbedPage.SetToolbarPlacement method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace,
is used to set the toolbar placement on a TabbedPage , with the ToolbarPlacement enumeration providing the
following values:
– indicates that the toolbar is placed at the default location on the page. This is the top of the page on
Default
phones, and the bottom of the page on other device idioms.
Top – indicates that the toolbar is placed at the top of the page.
Bottom – indicates that the toolbar is placed at the bottom of the page.
In addition, the TabbedPage.SetBarItemColor and TabbedPage.SetBarSelectedItemColor methods are used to set the
color of toolbar items and selected toolbar items, respectively.
NOTE
The GetToolbarPlacement , GetBarItemColor , and GetBarSelectedItemColor methods can be used to retrieve the
placement and color of the TabbedPage toolbar.
The result is that the toolbar placement, the color of toolbar items, and the color of the selected toolbar item can be
set on a TabbedPage :
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
VisualElement Elevation on Android
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
Title="Elevation">
<StackLayout>
<Grid>
<Button Text="Button Beneath BoxView" />
<BoxView Color="Red" Opacity="0.2" HeightRequest="50" />
</Grid>
<Grid Margin="0,20,0,0">
<Button Text="Button Above BoxView - Click Me" android:VisualElement.Elevation="10"/>
<BoxView Color="Red" Opacity="0.2" HeightRequest="50" />
</Grid>
</StackLayout>
</ContentPage>
The Button.On<Android> method specifies that this platform-specific will only run on Android. The
VisualElement.SetElevation method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, is
used to set the elevation of the visual element to a nullable float . In addition, the VisualElement.GetElevation
method can be used to retrieve the elevation value of a visual element.
The result is that the elevation of visual elements can be controlled so that visual elements with higher Z values
occlude visual elements with lower Z values. Therefore, in this example the second Button is rendered above the
BoxView because it has a higher elevation value:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
VisualElement Legacy Color Mode on Android
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
...
<Button Text="Button"
TextColor="Blue"
BackgroundColor="Bisque"
android:VisualElement.IsLegacyColorModeEnabled="False" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
_legacyColorModeDisabledButton.On<Android>().SetIsLegacyColorModeEnabled(false);
The VisualElement.On<Android> method specifies that this platform-specific will only run on Android. The
VisualElement.SetIsLegacyColorModeEnabled method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace, is used to control whether the legacy color mode is disabled. In addition, the
VisualElement.GetIsLegacyColorModeEnabled method can be used to return whether the legacy color mode is
disabled.
The result is that the legacy color mode can be disabled, so that colors set on a view by the user remain even when
the view is disabled:
NOTE
When setting a VisualStateGroup on a view, the legacy color mode is completely ignored. For more information about
visual states, see The Xamarin.Forms Visual State Manager.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
WebView Mixed Content on Android
3/8/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<WebView ... android:WebView.MixedContentMode="AlwaysAllow" />
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
webView.On<Android>().SetMixedContentMode(MixedContentHandling.AlwaysAllow);
The WebView.On<Android>method specifies that this platform-specific will only run on Android. The
WebView.SetMixedContentMode method, in the Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, is
used to control whether mixed content can be displayed, with the MixedContentHandling enumeration providing
three possible values:
AlwaysAllow– indicates that the WebView will allow an HTTPS origin to load content from an HTTP origin.
NeverAllow – indicates that the WebView will not allow an HTTPS origin to load content from an HTTP origin.
CompatibilityMode – indicates that the WebView will attempt to be compatible with the approach of the latest
device web browser. Some HTTP content may be allowed to be loaded by an HTTPS origin and other types of
content will be blocked. The types of content that are blocked or allowed may change with each operating
system release.
The result is that a specified MixedContentHandling value is applied to the WebView , which controls whether mixed
content can be displayed:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
AndroidSpecific API
AndroidSpecific.AppCompat API
Xamarin.Forms Device Class
12/7/2018 • 4 minutes to read • Edit Online
However, since Xamarin.Forms 2.3.4 these APIs have been deprecated and replaced. The Device class now
contains public string constants that identify platforms – Device.iOS , Device.Android , Device.WinPhone
(deprecated), Device.WinRT (deprecated), Device.UWP , and Device.macOS . Similarly, the Device.OnPlatform
overloads have been replaced with the OnPlatform and On APIs.
In C#, platform-specific values can be provided by creating a switch statement on the Device.RuntimePlatform
property, and then providing case statements for the required platforms:
double top;
switch (Device.RuntimePlatform)
{
case Device.iOS:
top = 20;
break;
case Device.Android:
case Device.UWP:
default:
top = 0;
break;
}
layout.Margin = new Thickness(5, top, 5, 0);
<StackLayout>
<StackLayout.Margin>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0,20,0,0" />
<On Platform="Android, UWP" Value="0,0,0,0" />
</OnPlatform>
</StackLayout.Margin>
...
</StackLayout>
The OnPlatform class is a generic class that 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.
IMPORTANT
Providing an incorrect Platform attribute value in the On class will not result in an error. Instead, the code will execute
without the platform-specific value being applied.
Alternatively, the OnPlatform markup extension can be used in XAML to customize UI appearance on a per-
platform basis. For more information, see OnPlatform Markup Extension.
Device.Idiom
The Device.Idiom property can be used to alter layouts or functionality depending on the device the application is
running on. The TargetIdiom enumeration contains the following values:
Phone – iPhone, iPod touch, and Android devices narrower than 600 dips^
Tablet – iPad, Windows devices, and Android devices wider than 600 dips^
Desktop – only returned in UWP apps on Windows 10 desktop computers (returns Phone on mobile
Windows devices, including in Continuum scenarios)
TV – Tizen TV devices
Watch – Tizen watch devices
Unsupported – unused
^ dips is not necessarily the physical pixel count
The Idiom property is especially useful for building layouts that take advantage of larger screens, like this:
if (Device.Idiom == TargetIdiom.Phone) {
// layout views vertically
} else {
// layout views horizontally for a larger display (tablet or desktop)
}
<StackLayout>
<StackLayout.Margin>
<OnIdiom x:TypeArguments="Thickness">
<OnIdiom.Phone>0,20,0,0</OnIdiom.Phone>
<OnIdiom.Tablet>0,40,0,0</OnIdiom.Tablet>
<OnIdiom.Desktop>0,60,0,0</OnIdiom.Desktop>
</OnIdiom>
</StackLayout.Margin>
...
</StackLayout>
The OnIdiom class is a generic class that must be instantiated with an x:TypeArguments attribute that matches the
target type.
Alternatively, the OnIdiom markup extension can be used in XAML to customize UI appearance based on the
idiom of the device the application is running on. For more information, see OnIdiom Markup Extension.
Device.FlowDirection
The Device.FlowDirection value retrieves a FlowDirection enumeration value that represents the current flow
direction being used by the device. Flow direction is the direction in which the UI elements on the page are
scanned by the eye. The enumeration values are:
LeftToRight
RightToRight
MatchParent
In XAML, the Device.FlowDirection value can be retrieved by using the x:Static markup extension:
this.FlowDirection = Device.FlowDirection;
Device.Styles
The Styles property contains built-in style definitions that can be applied to some controls' (such as Label )
Style property. The available styles are:
BodyStyle
CaptionStyle
ListItemDetailTextStyle
ListItemTextStyle
SubtitleStyle
TitleStyle
Device.GetNamedSize
GetNamedSize can be used when setting FontSize in C# code:
Device.OpenUri
The OpenUri method can be used to trigger operations on the underlying platform, such as open a URL in the
native web browser (Safari on iOS or Internet on Android).
Device.OpenUri(new Uri("https://evolve.xamarin.com/"));
The WebView sample includes an example using OpenUri to open URLs and also trigger phone calls.
The Maps sample also uses Device.OpenUri to display maps and directions using the native Maps apps on iOS
and Android.
Device.StartTimer
The Device class also has a StartTimer method which provides a simple way to trigger time-dependent tasks
that works in Xamarin.Forms common code, including a .NET Standard library. Pass a TimeSpan to set the interval
and return true to keep the timer running or false to stop it after the current invocation.
If the code inside the timer interacts with the user-interface (such as setting the text of a Label or displaying an
alert) it should be done inside a BeginInvokeOnMainThread expression (see below ).
Device.BeginInvokeOnMainThread
User interface elements should never be accessed by background threads, such as code running in a timer or a
completion handler for asynchronous operations like web requests. Any background code that needs to update
the user interface should be wrapped inside BeginInvokeOnMainThread . This is the equivalent of
InvokeOnMainThread on iOS, RunOnUiThread on Android, and Dispatcher.RunAsync on the Universal Windows
Platform.
The Xamarin.Forms code is:
Device.BeginInvokeOnMainThread ( () => {
// interact with UI elements
});
Note that methods using async/await do not need to use BeginInvokeOnMainThread if they are running from the
main UI thread.
Summary
The Xamarin.Forms Device class allows fine-grained control over functionality and layouts on a per-platform
basis - even in common code (either .NET Standard library projects or Shared Projects).
Related Links
Device Sample
Styles Sample
Device
iOS platform features in Xamarin.Forms
3/15/2019 • 3 minutes to read • Edit Online
Developing Xamarin.Forms applications for iOS requires Visual Studio. The requirements page contains more
information about the pre-requisites.
Platform-specifics
Platform-specifics allow you to consume functionality that's only available on a specific platform, without
implementing custom renderers or effects.
The following platform-specific functionality is provided for Xamarin.Forms views, pages, and layouts on iOS:
Blur support for any VisualElement . For more information, see VisualElement Blur on iOS.
Disabling legacy color mode on a supported VisualElement . For more information, see VisualElement Legacy
Color Mode on iOS.
Enabling a drop shadow on a VisualElement . For more information, see VisualElement Drop Shadows on iOS.
The following platform-specific functionality is provided for Xamarin.Forms views on iOS:
Setting the Cell background color. For more information, see Cell Background Color on iOS.
Ensuring that inputted text fits into an Entry by adjusting the font size. For more information, see Entry Font
Size on iOS.
Setting the cursor color in a Entry . For more information, see Entry Cursor Color on iOS.
Controlling whether ListView header cells float during scrolling. For more information, see ListView Group
Header Style on iOS.
Controlling whether row animations are disabled when the ListView items collection is being updated. For
more information, see ListView Row Animations on iOS.
Setting the separator style on a ListView . For more information, see ListView Separator Style on iOS.
Controlling when item selection occurs in a Picker . For more information, see Picker Item Selection on iOS.
Enabling the Slider.Value property to be set by tapping on a position on the Slider bar, rather than by
having to drag the Slider thumb. For more information, see Slider Thumb Tap on iOS.
The following platform-specific functionality is provided for Xamarin.Forms pages on iOS:
Hiding the navigation bar separator on a NavigationPage . For more information, see NavigationPage Bar
Separator on iOS.
Controlling whether the navigation bar is translucent. For more information, see Navigation Bar Translucency
on iOS.
Controlling whether the status bar text color on a NavigationPage is adjusted to match the luminosity of the
navigation bar. For more information, see NavigationPage Bar Text Color Mode on iOS.
Controlling whether the page title is displayed as a large title in the page navigation bar. For more information,
see Large Page Titles on iOS.
Setting the status bar visibility on a Page . For more information, see Page Status Bar Visibility on iOS.
Ensuring that page content is positioned on an area of the screen that is safe for all iOS devices. For more
information, see Safe Area Layout Guide on iOS.
Setting the presentation style of modal pages on an iPad. For more information, see iPad Modal Page
Presentation Style.
The following platform-specific functionality is provided for Xamarin.Forms layouts on iOS:
Controlling whether a ScrollView handles a touch gesture or passes it to its content. For more information, see
ScrollView Content Touches on iOS.
The following platform-specific functionality is provided for the Xamarin.Forms Application class on iOS:
Enabling control layout and rendering updates to be performed on the main thread. For more information, see
Main Thread Control Updates on iOS.
Enabling a PanGestureRecognizer in a scrolling view to capture and share the pan gesture with the scrolling
view. For more information, see Simultaneous Pan Gesture Recognition on iOS.
iOS-specific formatting
Xamarin.Forms enables cross-platform user interface styles and colors to be set - but there are other options for
setting the theme of your iOS using platform APIs in the iOS project.
Read more about formatting the user interface using iOS -specific APIs, such as Info.plist configuration and the
UIAppearance API.
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ItemsSource="{Binding GroupedEmployees}"
IsGroupingEnabled="true">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell ios:Cell.DefaultBackgroundColor="Teal">
<Label Margin="10,10"
Text="{Binding Key}"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
The ListView.On<iOS> method specifies that this platform-specific will only run on iOS. The
Cell.SetDefaultBackgroundColor method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, sets
the cell background color to a specified Color . In addition, the Cell.DefaultBackgroundColor method can be used
to retrieve the current cell background color.
The result is that the background color in a Cell can be set to a specific Color :
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Entry Cursor Color on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<Entry ... ios:Entry.CursorColor="LimeGreen" />
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
The Entry.On<iOS> method specifies that this platform-specific will only run on iOS. The Entry.SetCursorColor
method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, sets the cursor color to a specified
Color . In addition, the Entry.GetCursorColor method can be used to retrieve the current cursor color.
The result is that the cursor color in a Entry can be set to a specific Color :
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Entry Font Size on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
<StackLayout Margin="20">
<Entry x:Name="entry"
Placeholder="Enter text here to see the font size change"
FontSize="22"
ios:Entry.AdjustsFontSizeToFitWidth="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
entry.On<iOS>().EnableAdjustsFontSizeToFitWidth();
The Entry.On<iOS> method specifies that this platform-specific will only run on iOS. The
Entry.EnableAdjustsFontSizeToFitWidth method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, is used to scale the font size of the inputted text to ensure that it fits in the Entry . In addition, the
Entry class in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace also has a
DisableAdjustsFontSizeToFitWidth method that disables this platform -specific, and a SetAdjustsFontSizeToFitWidth
method which can be used to toggle font size scaling by calling the AdjustsFontSizeToFitWidth method:
entry.On<iOS>().SetAdjustsFontSizeToFitWidth(!entry.On<iOS>().AdjustsFontSizeToFitWidth());
The result is that the font size of the Entry is scaled to ensure that the inputted text fits in the control:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Adding iOS-specific Formatting
1/10/2019 • 2 minutes to read • Edit Online
One way to set iOS -specific formatting is to create a custom renderer for a control and set platform-specific styles
and colors for each platform.
Other options to control the way your Xamarin.Forms iOS app's appearance include:
Configuring display options in Info.plist
Setting control styles via the UIAppearance API
These alternatives are discussed below.
Customizing Info.plist
The Info.plist file lets you configure some aspects of an iOS application's renderering, such as how (and whether)
the status bar is shown.
For example, the Todo sample uses the following code to set the navigation bar color and text color on all
platforms:
The result is shown in the screen snippet below. Notice that the status bar items are black (this cannot be set within
Xamarin.Forms because it is a platform-specific feature).
Ideally the status bar would also be white - something we can accomplish directly in the iOS project. Add the
following entries to the Info.plist to force the status bar to be white:
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
Now when the app is run, the navigation bar is green and its text is white (due to Xamarin.Forms formatting) and
the status bar text is also white thanks to iOS -specific configuration:
UIAppearance API
The UIAppearance API can be used to set visual properties on many iOS controls without having to create a
custom renderer.
Adding a single line of code to the AppDelegate.cs FinishedLaunching method can style all controls of a given
type using their Appearance property. The following code contains two examples - globally styling the tab bar and
switch control:
AppDelegate.cs in the iOS Project
UITabBar
By default, the selected tab bar icon in a TabbedPage would be blue:
Using this API lets you customize the appearance of the Xamarin.Forms TabbedPage on iOS with very little code.
Refer to the Customize Tabs recipe for more details on using a custom renderer to set a specific font for the tab.
UISwitch
The Switch control is another example that can be easily styled:
These two screen captures show the default UISwitch control on the left and the customized version (setting
Appearance ) on the right in the Todo sample:
Other controls
Many iOS user interface controls can have their default colors and other attributes set using the UIAppearance API.
Related Links
UIAppearance
Customize Tabs
iPad Modal Page Presentation Style
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.ModalPresentationStyle="FormSheet">
...
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
The Page.On<iOS>method specifies that this platform-specific will only run on iOS. The
Page.SetModalPresentationStyle method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is
used to set the modal presentation style on a Page by specifying one of the following UIModalPresentationStyle
enumeration values:
FullScreen, which sets the modal presentation style to encompass the whole screen. By default, modal pages
are displayed using this presentation style.
FormSheet , which sets the modal presentation style to be centered on and smaller than the screen.
In addition, the GetModalPresentationStylemethod can be used to retrieve the current value of the
UIModalPresentationStyle enumeration that's applied to the Page .
The result is that the modal presentation style on a Page can be set:
NOTE
Pages that use this platform-specific to set the modal presentation style must use modal navigation. For more information,
see Xamarin.Forms Modal Pages.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Large Page Titles on iOS
1/10/2019 • 2 minutes to read • Edit Online
<NavigationPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
...
ios:NavigationPage.PrefersLargeTitles="true">
...
</NavigationPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
The NavigationPage.On<iOS> method specifies that this platform-specific will only run on iOS. The
NavigationPage.SetPrefersLargeTitle method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace,
controls whether large titles are enabled.
Provided that large titles are enabled on the NavigationPage , all pages in the navigation stack will display large
titles. This behavior can be overridden on pages by setting the Page.LargeTitleDisplay attached property to a
value of the LargeTitleDisplayMode enumeration:
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
Title="Large Title"
ios:Page.LargeTitleDisplay="Never">
...
</ContentPage>
Alternatively, the page behavior can be overridden from C# using the fluent API:
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
The Page.On<iOS> method specifies that this platform-specific will only run on iOS. The
Page.SetLargeTitleDisplay method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, controls
the large title behavior on the Page , with the LargeTitleDisplayMode enumeration providing three possible values:
Always – force the navigation bar and font size to use the large format.
Automatic – use the same style (large or small) as the previous item in the navigation stack.
Never – force the use of the regular, small format navigation bar.
In addition, the SetLargeTitleDisplaymethod can be used to toggle the enumeration values by calling the
LargeTitleDisplay method, which returns the current LargeTitleDisplayMode :
switch (On<iOS>().LargeTitleDisplay())
{
case LargeTitleDisplayMode.Always:
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Automatic);
break;
case LargeTitleDisplayMode.Automatic:
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Never);
break;
case LargeTitleDisplayMode.Never:
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Always);
break;
}
The result is that a specified LargeTitleDisplayMode is applied to the Page , which controls the large title behavior:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
ListView Group Header Style on iOS
3/6/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ... ios:ListView.GroupHeaderStyle="Grouped">
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
listView.On<iOS>().SetGroupHeaderStyle(GroupHeaderStyle.Grouped);
The ListView.On<iOS>method specifies that this platform-specific will only run on iOS. The
ListView.SetGroupHeaderStyle method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is used
to control whether ListView header cells float during scrolling. The GroupHeaderStyle enumeration provides two
possible values:
Plain – indicates that header cells float when the ListView is scrolled (default).
Grouped – indicates that header cells do not float when the ListView is scrolled.
In addition, the ListView.GetGroupHeaderStyle method can be used to return the GroupHeaderStyle that's applied to
the ListView .
The result is that a specified GroupHeaderStyle value is applied to the ListView , which controls whether header
cells float during scrolling:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
ListView Row Animations on iOS
3/6/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ... ios:ListView.RowAnimationsEnabled="false">
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
listView.On<iOS>().SetRowAnimationsEnabled(false);
The ListView.On<iOS> method specifies that this platform-specific will only run on iOS. The
ListView.SetRowAnimationsEnabled method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is
used to control whether row animations are disabled when the ListView items collection is being updated. In
addition, the ListView.GetRowAnimationsEnabled method can be used to return whether row animations are
disabled on the ListView .
NOTE
ListView row animations are enabled by default. Therefore, an animation occurs when a new row is inserted into a
ListView .
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
ListView Separator Style on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ... ios:ListView.SeparatorStyle="FullWidth">
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
listView.On<iOS>().SetSeparatorStyle(SeparatorStyle.FullWidth);
The ListView.On<iOS>method specifies that this platform-specific will only run on iOS. The
ListView.SetSeparatorStyle method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is used
to control whether the separator between cells in the ListView uses the full width of the ListView , with the
SeparatorStyle enumeration providing two possible values:
Default – indicates the default iOS separator behavior. This is the default behavior in Xamarin.Forms.
FullWidth – indicates that separators will be drawn from one edge of the ListView to the other.
The result is that a specified SeparatorStyle value is applied to the ListView , which controls the width of the
separator between cells:
NOTE
Once the separator style has been set to FullWidth , it cannot be changed back to Default at runtime.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Main Thread Control Updates on iOS
1/10/2019 • 2 minutes to read • Edit Online
<Application ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Application.HandleControlUpdatesOnMainThread="true">
...
</Application>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
Xamarin.Forms.Application.Current.On<iOS>().SetHandleControlUpdatesOnMainThread(true);
The Application.On<iOS> method specifies that this platform-specific will only run on iOS. The
Application.SetHandleControlUpdatesOnMainThread method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, is used to control whether control layout and rendering updates are performed on the main thread,
instead of being performed on a background thread. In addition, the
Application.GetHandleControlUpdatesOnMainThread method can be used to return whether control layout and
rendering updates are being performed on the main thread.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
NavigationPage Bar Separator on iOS
1/10/2019 • 2 minutes to read • Edit Online
<NavigationPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">
</NavigationPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
The NavigationPage.On<iOS> method specifies that this platform-specific will only run on iOS. The
NavigationPage.SetHideNavigationBarSeparator method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, is used to control whether the navigation bar separator is hidden. In addition, the
NavigationPage.HideNavigationBarSeparator method can be used to return whether the navigation bar separator is
hidden.
The result is that the navigation bar separator on a NavigationPage can be hidden:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
NavigationPage Bar Text Color Mode on iOS
1/10/2019 • 2 minutes to read • Edit Online
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
x:Class="PlatformSpecifics.iOSStatusBarTextColorModePage">
<MasterDetailPage.Master>
<ContentPage Title="Master Page Title" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage BarBackgroundColor="Blue" BarTextColor="White"
ios:NavigationPage.StatusBarTextColorMode="MatchNavigationBarTextLuminosity">
<x:Arguments>
<ContentPage>
<Label Text="Slide the master page to see the status bar text color mode change." />
</ContentPage>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
The NavigationPage.On<iOS>method specifies that this platform-specific will only run on iOS. The
NavigationPage.SetStatusBarTextColorMode method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, controls whether the status bar text color on the NavigationPage is adjusted to match the luminosity of
the navigation bar, with the StatusBarTextColorMode enumeration providing two possible values:
– indicates that the status bar text color should not be adjusted.
DoNotAdjust
MatchNavigationBarTextLuminosity – indicates that the status bar text color should match the luminosity of the
navigation bar.
In addition, the GetStatusBarTextColorMode method can be used to retrieve the current value of the
StatusBarTextColorMode enumeration that's applied to the NavigationPage .
The result is that the status bar text color on a NavigationPage can be adjusted to match the luminosity of the
navigation bar. In this example, the status bar text color changes as the user switches between the Master and
Detail pages of a MasterDetailPage :
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
NavigationPage Bar Translucency on iOS
1/10/2019 • 2 minutes to read • Edit Online
<NavigationPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
BackgroundColor="Blue"
ios:NavigationPage.IsNavigationBarTranslucent="true">
...
</NavigationPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
The NavigationPage.On<iOS> method specifies that this platform-specific will only run on iOS. The
NavigationPage.EnableTranslucentNavigationBar method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, is used to make the navigation bar translucent. In addition, the NavigationPage class in the
Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace also has a DisableTranslucentNavigationBar method
that restores the navigation bar to its default state, and a SetIsNavigationBarTranslucent method which can be
used to toggle the navigation bar transparency by calling the IsNavigationBarTranslucent method:
(App.Current.MainPage as Xamarin.Forms.NavigationPage)
.On<iOS>()
.SetIsNavigationBarTranslucent(!(App.Current.MainPage as Xamarin.Forms.NavigationPage).On<iOS>
().IsNavigationBarTranslucent());
The result is that the transparency of the navigation bar can be changed:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Page Status Bar Visibility on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.PrefersStatusBarHidden="True"
ios:Page.PreferredStatusBarUpdateAnimation="Fade">
...
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
On<iOS>().SetPrefersStatusBarHidden(StatusBarHiddenMode.True)
.SetPreferredStatusBarUpdateAnimation(UIStatusBarAnimation.Fade);
The Page.On<iOS> method specifies that this platform-specific will only run on iOS. The
Page.SetPrefersStatusBarHidden method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is
used to set the visibility of the status bar on a Page by specifying one of the StatusBarHiddenMode enumeration
values: Default , True , or False . The StatusBarHiddenMode.True and StatusBarHiddenMode.False values set the
status bar visibility regardless of device orientation, and the StatusBarHiddenMode.Default value hides the status bar
in a vertically compact environment.
The result is that the visibility of the status bar on a Page can be set:
NOTE
On a TabbedPage , the specified StatusBarHiddenMode enumeration value will also update the status bar on all child pages.
On all other Page -derived types, the specified StatusBarHiddenMode enumeration value will only update the status bar on
the current page.
The Page.SetPreferredStatusBarUpdateAnimation method is used to set how the status bar enters or leaves the
Page by specifying one of the UIStatusBarAnimation enumeration values: None , Fade , or Slide . If the Fade or
Slide enumeration value is specified, a 0.25 second animation executes as the status bar enters or leaves the
Page .
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Picker Item Selection on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<Picker ... Title="Select a monkey" ios:Picker.UpdateMode="WhenFinished">
...
</Picker>
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
picker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
The Picker.On<iOS> method specifies that this platform-specific will only run on iOS. The Picker.SetUpdateMode
method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is used to control when item
selection occurs, with the UpdateMode enumeration providing two possible values:
Immediately – item selection occurs as the user browses items in the Picker . This is the default behavior in
Xamarin.Forms.
WhenFinished – item selection only occurs once the user has pressed the Done button in the Picker .
In addition, the SetUpdateMode method can be used to toggle the enumeration values by calling the UpdateMode
method, which returns the current UpdateMode :
switch (picker.On<iOS>().UpdateMode())
{
case UpdateMode.Immediately:
picker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
break;
case UpdateMode.WhenFinished:
picker.On<iOS>().SetUpdateMode(UpdateMode.Immediately);
break;
}
The result is that a specified UpdateMode is applied to the Picker , which controls when item selection occurs:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Safe Area Layout Guide on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
Title="Safe Area"
ios:Page.UseSafeArea="true">
<StackLayout>
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
On<iOS>().SetUseSafeArea(true);
The Page.On<iOS> method specifies that this platform-specific will only run on iOS. The Page.SetUseSafeArea
method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, controls whether the safe area layout
guide is enabled.
The result is that page content can be positioned on an area of the screen that is safe for all iPhones:
NOTE
The safe area defined by Apple is used in Xamarin.Forms to set the Page.Padding property, and will override any previous
values of this property that have been set.
The safe area can be customized by retrieving its value with the Page.SafeAreaInsets method from the
Thickness
Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace. It can then be modified as required and re-assigned
to the Padding property in the page constructor or OnAppearing override:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
ScrollView Content Touches on iOS
1/10/2019 • 2 minutes to read • Edit Online
<MasterDetailPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<MasterDetailPage.Master>
<ContentPage Title="Menu" BackgroundColor="Blue" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<ContentPage>
<ScrollView x:Name="scrollView" ios:ScrollView.ShouldDelayContentTouches="false">
<StackLayout Margin="0,20">
<Slider />
<Button Text="Toggle ScrollView DelayContentTouches" Clicked="OnButtonClicked" />
</StackLayout>
</ScrollView>
</ContentPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
scrollView.On<iOS>().SetShouldDelayContentTouches(false);
The ScrollView.On<iOS> method specifies that this platform-specific will only run on iOS. The
ScrollView.SetShouldDelayContentTouches method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, is used to control whether a ScrollView handles a touch gesture or passes it to its content. In addition,
the SetShouldDelayContentTouches method can be used to toggle delaying content touches by calling the
ShouldDelayContentTouches method to return whether content touches are delayed:
scrollView.On<iOS>().SetShouldDelayContentTouches(!scrollView.On<iOS>().ShouldDelayContentTouches());
The result is that a ScrollView can disable delaying receiving content touches, so that in this scenario the Slider
receives the gesture rather than the Detail page of the MasterDetailPage :
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Simultaneous Pan Gesture Recognition on iOS
1/10/2019 • 2 minutes to read • Edit Online
<Application ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Application.PanGestureRecognizerShouldRecognizeSimultaneously="true">
...
</Application>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
Xamarin.Forms.Application.Current.On<iOS>().SetPanGestureRecognizerShouldRecognizeSimultaneously(true);
The Application.On<iOS> method specifies that this platform-specific will only run on iOS. The
Application.SetPanGestureRecognizerShouldRecognizeSimultaneously method, in the
Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is used to control whether a pan gesture recognizer
in a scrolling view will capture the pan gesture, or capture and share the pan gesture with the scrolling view. In
addition, the Application.GetPanGestureRecognizerShouldRecognizeSimultaneously method can be used to return
whether the pan gesture is shared with the scrolling view that contains the PanGestureRecognizer .
Therefore, with this platform-specific enabled, when a ListView contains a PanGestureRecognizer , both the
ListView and the PanGestureRecognizer will receive the pan gesture and process it. However, with this platform -
specific disabled, when a ListView contains a PanGestureRecognizer , the PanGestureRecognizer will capture the
pan gesture and process it, and the ListView won't receive the pan gesture.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Slider Thumb Tap on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout ...>
<Slider ... ios:Slider.UpdateOnTap="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
The Slider.On<iOS> method specifies that this platform-specific will only run on iOS. The Slider.SetUpdateOnTap
method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is used to control whether a tap on
the Slider bar will set the Slider.Value property. In addition, the Slider.GetUpdateOnTap method can be used to
return whether a tap on the Slider bar will set the Slider.Value property.
The result is that a tap on the Slider bar can move the Slider thumb and set the Slider.Value property:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
VisualElement Blur on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
...
<AbsoluteLayout HorizontalOptions="Center">
<Image Source="monkeyface.png" />
<BoxView x:Name="boxView" ios:VisualElement.BlurEffect="ExtraLight" HeightRequest="300"
WidthRequest="300" />
</AbsoluteLayout>
...
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
boxView.On<iOS>().UseBlurEffect(BlurEffectStyle.ExtraLight);
The BoxView.On<iOS> method specifies that this platform-specific will only run on iOS. The
VisualElement.UseBlurEffect method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is used
to apply the blur effect, with the BlurEffectStyle enumeration providing four values: None , ExtraLight , Light ,
and Dark .
The result is that a specified BlurEffectStyle is applied to the BoxView instance, which blurs the Image layered
beneath it:
NOTE
When adding a blur effect to a VisualElement , touch events will still be received by the VisualElement .
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
VisualElement Drop Shadows on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<BoxView ...
ios:VisualElement.IsShadowEnabled="true"
ios:VisualElement.ShadowColor="Purple"
ios:VisualElement.ShadowOpacity="0.7"
ios:VisualElement.ShadowRadius="12">
<ios:VisualElement.ShadowOffset>
<Size>
<x:Arguments>
<x:Double>10</x:Double>
<x:Double>10</x:Double>
</x:Arguments>
</Size>
</ios:VisualElement.ShadowOffset>
</BoxView>
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
var boxView = new BoxView { Color = Color.Aqua, WidthRequest = 100, HeightRequest = 100 };
boxView.On<iOS>()
.SetIsShadowEnabled(true)
.SetShadowColor(Color.Purple)
.SetShadowOffset(new Size(10,10))
.SetShadowOpacity(0.7)
.SetShadowRadius(12);
The VisualElement.On<iOS>method specifies that this platform-specific will only run on iOS. The
VisualElement.SetIsShadowEnabled method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, is
used to control whether a drop shadow is enabled on the VisualElement . In addition, the following methods can be
invoked to control the drop shadow:
SetShadowColor– sets the color of the drop shadow. The default color is Color.Default .
SetShadowOffset – sets the offset of the drop shadow. The offset changes the direction the shadow is cast, and is
specified as a Size value. The Size structure values are expressed in device-independent units, with the first
value being the distance to the left (negative value) or right (positive value), and the second value being the
distance above (negative value) or below (positive value). The default value of this property is (0.0, 0.0), which
results in the shadow being cast around every side of the VisualElement .
SetShadowOpacity – sets the opacity of the drop shadow, with the value being in the range 0.0 (transparent) to
1.0 (opaque). The default opacity value is 0.5.
SetShadowRadius – sets the blur radius used to render the drop shadow. The default radius value is 10.0.
NOTE
The state of a drop shadow can be queried by calling the GetIsShadowEnabled , GetShadowColor , GetShadowOffset ,
GetShadowOpacity , and GetShadowRadius methods.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
VisualElement Legacy Color Mode on iOS
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
...
<Button Text="Button"
TextColor="Blue"
BackgroundColor="Bisque"
ios:VisualElement.IsLegacyColorModeEnabled="False" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
_legacyColorModeDisabledButton.On<iOS>().SetIsLegacyColorModeEnabled(false);
The VisualElement.On<iOS> method specifies that this platform-specific will only run on iOS. The
VisualElement.SetIsLegacyColorModeEnabled method, in the Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, is used to control whether the legacy color mode is disabled. In addition, the
VisualElement.GetIsLegacyColorModeEnabled method can be used to return whether the legacy color mode is
disabled.
The result is that the legacy color mode can be disabled, so that colors set on a view by the user remain even when
the view is disabled:
NOTE
When setting a VisualStateGroup on a view, the legacy color mode is completely ignored. For more information about
visual states, see The Xamarin.Forms Visual State Manager.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
iOSSpecific API
Xamarin.Forms in Xamarin Native Projects
12/7/2018 • 11 minutes to read • Edit Online
NOTE
The NativeForms sample application solution does not contain any Xamarin.Forms projects. Instead, it consists of a
Xamarin.iOS project, a Xamarin.Android project, and a UWP project. Each project is a native project that uses Native Forms
to consume ContentPage -derived pages. However, there's no reason why the native projects couldn't consume
ContentPage -derived pages from a .NET Standard library project or Shared Project.
When using Native Forms, Xamarin.Forms features such as DependencyService , MessagingCenter , and the data
binding engine, all still work. However, page navigation must be performed using the native navigation API.
iOS
On iOS, the FinishedLaunching override in the AppDelegate class is typically the place to perform application
startup related tasks. It's called after the application has launched, and is usually overridden to configure the main
window and view controller. The following code example shows the AppDelegate class in the sample application:
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public static AppDelegate Instance;
UIWindow _window;
UINavigationController _navigation;
Instance = this;
_window = new UIWindow(UIScreen.MainScreen.Bounds);
UINavigationBar.Appearance.SetTitleTextAttributes(new UITextAttributes
{
TextColor = UIColor.Black
});
return true;
}
...
}
Once the FinishedLaunching method has executed, the UI defined in the Xamarin.Forms PhonewordPage class will
be displayed, as shown in the following screenshot:
Interacting with the UI, for example by tapping on a Button , will result in event handlers in the PhonewordPage
code-behind executing. For example, when a user taps the Call History button, the following event handler is
executed:
Android
On Android, the OnCreate override in the MainActivity class is typically the place to perform application startup
related tasks. The following code example shows the MainActivity class in the sample application:
public class MainActivity : AppCompatActivity
{
public static MainActivity Instance;
Forms.Init(this, bundle);
Instance = this;
SetContentView(Resource.Layout.Main);
var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
SupportActionBar.Title = "Phoneword";
The NavigateToCallHistoryPage method converts the Xamarin.Forms ContentPage -derived page to a Fragment
with the CreateSupportFragment extension method, and adds the Fragment to the fragment back stack. Therefore,
the UI defined in the Xamarin.Forms CallHistoryPage will be displayed, as shown in the following screenshot:
When the CallHistoryPage is displayed, tapping the back arrow will pop the Fragment for the CallHistoryPage
from the fragment back stack, returning the user to the Fragment for the PhonewordPage class.
Enabling Back Navigation Support
The SupportFragmentManager class has a BackStackChanged event that fires whenever the content of the fragment
back stack changes. The OnCreate method in the MainActivity class contains an anonymous event handler for
this event:
This event handler displays a back button on the action bar provided that there's one or more Fragment instances
on the fragment back stack. The response to tapping the back button is handled by the OnOptionsItemSelected
override:
The value of Xamarin.Forms.Color.Accentwill be taken from the Activity that called the Forms.Init method.
The value of Xamarin.Forms.Application.Current will be associated with the Activity that called the
Forms.Init method.
Choosing a File
When embedding a ContentPage -derived page that uses a WebView that needs to support an HTML "Choose File"
button, the Activity will need to override the OnActivityResult method:
UWP
On UWP, the native App class is typically the place to perform application startup related tasks. Xamarin.Forms is
usually initialized, in Xamarin.Forms UWP applications, in the OnLaunched override in the native App class, to
pass the LaunchActivatedEventArgs argument to the Forms.Init method. For this reason, native UWP applications
that consume a Xamarin.Forms ContentPage -derived page can most easily call the Forms.Init method from the
App.OnLaunched method.
By default, the native App class launches the MainPage class as the first page of the application. The following
code example shows the MainPage class in the sample application:
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Enabled;
Instance = this;
this.Content = new Phoneword.UWP.Views.PhonewordPage().CreateFrameworkElement();
}
...
}
Once the MainPage constructor has executed, the UI defined in the Xamarin.Forms PhonewordPage class will be
displayed, as shown in the following screenshot:
Interacting with the UI, for example by tapping on a Button , will result in event handlers in the PhonewordPage
code-behind executing. For example, when a user taps the Call History button, the following event handler is
executed:
The static MainPage.Instance field allows the MainPage.NavigateToCallHistoryPage method to be invoked, which
is shown in the following code example:
Navigation in UWP is typically performed with the Frame.Navigate method, which takes a Page argument.
Xamarin.Forms defines a Frame.Navigate extension method that takes a ContentPage -derived page instance.
Therefore, when the NavigateToCallHistoryPage method executes, the UI defined in the Xamarin.Forms
CallHistoryPage will be displayed, as shown in the following screenshot:
When the CallHistoryPage is displayed, tapping the back arrow will pop the FrameworkElement for the
CallHistoryPage from the in-app back stack, returning the user to the FrameworkElement for the PhonewordPage
class.
Enabling Back Navigation Support
On UWP, applications must enable back navigation for all hardware and software back buttons, across different
device form factors. This can be accomplished by registering an event handler for the BackRequested event, which
can be performed in the OnLaunched method in the native App class:
if (rootFrame == null)
{
...
// Place the frame in the current Window
Window.Current.Content = rootFrame;
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}
...
}
When the application is launched, the GetForCurrentView method retrieves the SystemNavigationManager object
associated with the current view, then registers an event handler for the BackRequested event. The application only
receives this event if it's the foreground application, and in response, calls the OnBackRequested event handler:
void OnBackRequested(object sender, BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
e.Handled = true;
rootFrame.GoBack();
}
}
The OnBackRequested event handler calls the GoBack method on the root frame of the application and sets the
BackRequestedEventArgs.Handled property to true to mark the event as handled. Failure to mark the event as
handled could result in the system navigating away from the application (on the mobile device family) or ignoring
the event (on the desktop device family).
The application relies on a system provided back button on a phone, but chooses whether to show a back button
on the title bar on desktop devices. This is achieved by setting the AppViewBackButtonVisibility property to one of
the AppViewBackButtonVisibility enumeration values:
The OnNavigated event handler, which is executed in response to the Navigated event firing, updates the visibility
of the title bar back button when page navigation occurs. This ensures that the title bar back button is visible if the
in-app back stack is not empty, or removed from the title bar if the in-app back stack is empty.
For more information about back navigation support on UWP, see Navigation history and backwards navigation
for UWP apps.
Summary
Native Forms allow Xamarin.Forms ContentPage -derived pages to be consumed by native Xamarin.iOS,
Xamarin.Android, and Universal Windows Platform (UWP ) projects. Native projects can consume ContentPage -
derived pages that are directly added to the project, or from a .NET Standard library project or Shared Project.
This article explained how to consume ContentPage -derived pages that are directly added to native projects, and
how to navigate between them.
Related Links
NativeForms (sample)
Native Views
Native Views in Xamarin.Forms
6/8/2018 • 2 minutes to read • Edit Online
Native views from iOS, Android, and the Universal Windows Platform (UWP ) can be directly referenced from
Xamarin.Forms. Properties and event handlers can be set on native views, and they can interact with
Xamarin.Forms views.
Native Views in C#
Native views from iOS, Android, and UWP can be directly referenced from Xamarin.Forms pages created using
C#.
Related Links
Native Forms
Native Views in XAML
3/14/2019 • 13 minutes to read • Edit Online
Overview
To embed a native view into a Xamarin.Forms XAML file:
1. Add an xmlns namespace declaration in the XAML file for the namespace that contains the native view.
2. Create an instance of the native view in the XAML file.
NOTE
XAMLC must be turned off for any XAML pages that use native views.
To reference a native view from a code-behind file, you must use a Shared Asset Project (SAP ) and wrap the
platform-specific code with conditional compilation directives. For more information see Referring to Native Views
from Code.
As well as specifying the clr-namespace and assembly for a native view namespace, a targetPlatform must also
be specified. This should be set to one of values of the TargetPlatform enumeration, and will typically be set to
iOS , Android , or Windows . At runtime, the XAML parser will ignore any XML namespace prefixes that have a
targetPlatform that doesn't match the platform on which the application is running.
Each namespace declaration can be used to reference any class or structure from the specified namespace. For
example, the ios namespace declaration can be used to reference any class or structure from the iOS UIKit
namespace. Properties of the native view can be set through XAML, but the property and object types must match.
For example, the UILabel.TextColor property is set to UIColor.Red using the x:Static markup extension and the
ios namespace.
Bindable properties and attached bindable properties can also be set on native views by using the
Class.BindableProperty="value" syntax. Each native view is wrapped in a platform -specific NativeViewWrapper
instance, which derives from the Xamarin.Forms.View class. Setting a bindable property or attached bindable
property on a native view transfers the property value to the wrapper. For example, a centered horizontal layout
can be specified by setting View.HorizontalOptions="Center" on the native view.
NOTE
Note that styles can't be used with native views, because styles can only target properties that are backed by
BindableProperty objects.
Android widget constructors generally require the Android Context object as an argument, and this can be made
available through a static property in the MainActivity class. Therefore, when creating an Android widget in
XAML, the Context object must generally be passed to the widget's constructor using the x:Arguments attribute
with a x:Static markup extension. For more information, see Passing Arguments to Native Views.
NOTE
Note that naming a native view with x:Name is not possible in either a .NET Standard library project or a Shared Asset
Project (SAP). Doing so will generate a variable of the native type, which will cause a compilation error. However, native views
can be wrapped in ContentView instances and retrieved in the code-behind file, provided that a SAP is being used. For
more information, see Referring to a Native View from Code.
Native Bindings
Data binding is used to synchronize a UI with its data source, and simplifies how a Xamarin.Forms application
displays and interacts with its data. Provided that the source object implements the INotifyPropertyChanged
interface, changes in the source object are automatically pushed to the target object by the binding framework, and
changes in the target object can optionally be pushed to the source object.
Properties of native views can also use data binding. The following code example demonstrates data binding using
properties of native views:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:NativeSwitch"
x:Class="NativeSwitch.NativeSwitchPage">
<StackLayout Margin="20">
<Label Text="Native Views Demo" FontAttributes="Bold" HorizontalOptions="Center" />
<Entry Placeholder="This Entry is bound to the native switch" IsEnabled="{Binding IsSwitchOn}" />
<ios:UISwitch On="{Binding Path=IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=ValueChanged}"
OnTintColor="{x:Static ios:UIColor.Red}"
ThumbTintColor="{x:Static ios:UIColor.Blue}" />
<androidWidget:Switch x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Checked="{Binding Path=IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=CheckedChange}"
Text="Enable Entry?" />
<win:ToggleSwitch Header="Enable Entry?"
OffContent="No"
OnContent="Yes"
IsOn="{Binding IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=Toggled}" />
</StackLayout>
</ContentPage>
The page contains an Entry whose IsEnabled property binds to the NativeSwitchPageViewModel.IsSwitchOn
property. The BindingContext of the page is set to a new instance of the NativeSwitchPageViewModel class in the
code-behind file, with the ViewModel class implementing the INotifyPropertyChanged interface.
The page also contains a native switch for each platform. Each native switch uses a TwoWay binding to update the
value of the NativeSwitchPageViewModel.IsSwitchOn property. Therefore, when the switch is off, the Entry is
disabled, and when the switch is on, the Entry is enabled. The following screenshots show this functionality on
each platform:
Two-way bindings are automatically supported provided that the native property implements
INotifyPropertyChanged , or supports Key-Value Observing ( KVO ) on iOS, or is a DependencyProperty on UWP.
However, many native views don't support property change notification. For these views, you can specify an
UpdateSourceEventName property value as part of the binding expression. This property should be set to the name
of an event in the native view that signals when the target property has changed. Then, when the value of the
native switch changes, the Binding class is notified that the user has changed the switch value, and the
NativeSwitchPageViewModel.IsSwitchOn property value is updated.
The UIFont.FromNamefactory method is used to set the UILabel.Font property to a new UIFont on iOS. The
UIFont name and size are specified by the method arguments that are children of the x:Arguments attribute.
The Typeface.Create factory method is used to set the TextView.Typeface property to a new Typeface on
Android. The Typeface family name and style are specified by the method arguments that are children of the
x:Arguments attribute.
The FontFamily constructor is used to set the TextBlock.FontFamily property to a new FontFamily on the
Universal Windows Platform (UWP ). The FontFamily name is specified by the method argument that is a child of
the x:Arguments attribute.
NOTE
Arguments must match the types required by the constructor or factory method.
The following screenshots show the result of specifying factory method and constructor arguments to set the font
on different native views:
For more information about passing arguments in XAML, see Passing Arguments in XAML.
The native API can then be invoked on the native view to perform the desired operations. This approach also offers
the benefit that multiple XAML native views for different platforms can be children of the same ContentView . The
following code example demonstrates this technique:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:NativeViewInsideContentView"
x:Class="NativeViewInsideContentView.NativeViewInsideContentViewPage">
<StackLayout Margin="20">
<ContentView x:Name="contentViewTextParent" HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<ios:UILabel Text="Text in a UILabel" TextColor="{x:Static ios:UIColor.Red}" />
<androidWidget:TextView x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Text in a TextView" />
<winControls:TextBlock Text="Text in a TextBlock" />
</ContentView>
<ContentView x:Name="contentViewButtonParent" HorizontalOptions="Center"
VerticalOptions="EndAndExpand">
<ios:UIButton TouchUpInside="OnButtonTap" View.HorizontalOptions="Center"
View.VerticalOptions="Center" />
<androidWidget:Button x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Scale and Rotate Text"
Click="OnButtonTap" />
<winControls:Button Content="Scale and Rotate Text" />
</ContentView>
</StackLayout>
</ContentPage>
In the example above, the native views for each platform are children of ContentView controls, with the x:Name
attribute value being used to retrieve the ContentView in the code-behind:
#if __IOS__
var wrapper = (Xamarin.Forms.Platform.iOS.NativeViewWrapper)contentViewButtonParent.Content;
var button = (UIKit.UIButton)wrapper.NativeView;
button.SetTitle("Scale and Rotate Text", UIKit.UIControlState.Normal);
button.SetTitleColor(UIKit.UIColor.Black, UIKit.UIControlState.Normal);
#endif
#if __ANDROID__
var wrapper = (Xamarin.Forms.Platform.Android.NativeViewWrapper)contentViewTextParent.Content;
var textView = (Android.Widget.TextView)wrapper.NativeView;
textView.SetTextColor(Android.Graphics.Color.Red);
#endif
#if WINDOWS_UWP
var textWrapper = (Xamarin.Forms.Platform.UWP.NativeViewWrapper)contentViewTextParent.Content;
var textBlock = (Windows.UI.Xaml.Controls.TextBlock)textWrapper.NativeElement;
textBlock.Foreground = new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.Red);
var buttonWrapper = (Xamarin.Forms.Platform.UWP.NativeViewWrapper)contentViewButtonParent.Content;
var button = (Windows.UI.Xaml.Controls.Button)buttonWrapper.NativeElement;
button.Click += (sender, args) => OnButtonTap(sender, EventArgs.Empty);
#endif
}
The ContentView.Content property is accessed to retrieve the wrapped native view as a platform-specific
NativeViewWrapper instance. The NativeViewWrapper.NativeElement property is then accessed to retrieve the native
view as its native type. The native view's API is then invoked to perform the desired operations.
The iOS and Android native buttons share the same OnButtonTap event handler, because each native button
consumes an EventHandler delegate in response to a touch event. However, the Universal Windows Platform
(UWP ) uses a separate RoutedEventHandler , which in turn consumes the OnButtonTap event handler in this
example. Therefore, when a native button is clicked, the OnButtonTap event handler executes, which scales and
rotates the native control contained within the ContentView named contentViewTextParent . The following
screenshots demonstrate this occurring on each platform:
Subclassing Native Views
Many iOS and Android native views are not suitable for instantiating in XAML because they use methods, rather
than properties, to set up the control. The solution to this issue is to subclass native views in wrappers that define a
more XAML -friendly API that uses properties to setup the control, and that uses platform-independent events. The
wrapped native views can then be placed in a Shared Asset Project (SAP ) and surrounded with conditional
compilation directives, or placed in platform-specific projects and referenced from XAML in a .NET Standard
library project.
The following code example demonstrates a Xamarin.Forms page that consumes subclassed native views:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:iosLocal="clr-
namespace:SubclassedNativeControls.iOS;assembly=SubclassedNativeControls.iOS;targetPlatform=iOS"
xmlns:android="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SubclassedNativeControls.Droid;assembly=SubclassedNativeControls.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:SubclassedNativeControls"
x:Class="SubclassedNativeControls.SubclassedNativeControlsPage">
<StackLayout Margin="20">
<Label Text="Subclassed Native Views Demo" FontAttributes="Bold" HorizontalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="You have chosen:" />
<Label Text="{Binding SelectedFruit}" />
</StackLayout>
<iosLocal:MyUIPickerView ItemsSource="{Binding Fruits}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=SelectedItemChanged}" />
<androidLocal:MySpinner x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
ItemsSource="{Binding Fruits}"
SelectedObject="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=ItemSelected}" />
<winControls:ComboBox ItemsSource="{Binding Fruits}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=SelectionChanged}" />
</StackLayout>
</ContentPage>
The page contains a Label that displays the fruit chosen by the user from a native control. The Label binds to the
SubclassedNativeControlsPageViewModel.SelectedFruit property. The BindingContext of the page is set to a new
instance of the SubclassedNativeControlsPageViewModel class in the code-behind file, with the ViewModel class
implementing the INotifyPropertyChanged interface.
The page also contains a native picker view for each platform. Each native view displays the collection of fruits by
binding its ItemSource property to the SubclassedNativeControlsPageViewModel.Fruits collection. This allows the
user to pick a fruit, as shown in the following screenshots:
On iOS and Android the native pickers use methods to setup the controls. Therefore, these pickers must be
subclassed to expose properties to make them XAML -friendly. On the Universal Windows Platform (UWP ), the
ComboBox is already XAML -friendly, and so doesn't require subclassing.
iOS
The iOS implementation subclasses the UIPickerView view, and exposes properties and an event that can be easily
consumed from XAML:
public class MyUIPickerView : UIPickerView
{
public event EventHandler<EventArgs> SelectedItemChanged;
public MyUIPickerView()
{
var model = new PickerModel();
model.ItemChanged += (sender, e) =>
{
if (SelectedItemChanged != null)
{
SelectedItemChanged.Invoke(this, e);
}
};
Model = model;
}
The class exposes ItemsSource and SelectedItem properties, and a SelectedItemChanged event. A
MyUIPickerView
UIPickerView requires an underlying UIPickerViewModel data model, which is accessed by the MyUIPickerView
properties and event. The UIPickerViewModel data model is provided by the PickerModel class:
class PickerModel : UIPickerViewModel
{
int selectedIndex = 0;
public event EventHandler<EventArgs> ItemChanged;
public IList<string> Items { get; set; }
The PickerModel class provides the underlying storage for the MyUIPickerView class, via the Items property.
Whenever the selected item in the MyUIPickerView changes, the Selected method is executed, which updates the
selected index and fires the ItemChanged event. This ensures that the SelectedItem property will always return the
last item picked by the user. In addition, the PickerModel class overrides methods that are used to setup the
MyUIPickerView instance.
Android
The Android implementation subclasses the Spinner view, and exposes properties and an event that can be easily
consumed from XAML:
class MySpinner : Spinner
{
ArrayAdapter adapter;
IList<string> items;
The MySpinner class exposes ItemsSource and SelectedObject properties, and a ItemSelected event. The items
displayed by the MySpinner class are provided by the Adapter associated with the view, and items are populated
into the Adapter when the ItemsSource property is first set. Whenever the selected item in the MySpinner class
changes, the OnBindableSpinnerItemSelected event handler updates the SelectedObject property.
Summary
This article demonstrated how to consume native views from Xamarin.Forms XAML files. Properties and event
handlers can be set on native views, and they can interact with Xamarin.Forms views.
Related Links
NativeSwitch (sample)
Forms2Native (sample)
NativeViewInsideContentView (sample)
SubclassedNativeControls (sample)
Native Forms
Passing Arguments in XAML
Native Views in C#
12/7/2018 • 7 minutes to read • Edit Online
Overview
Any Xamarin.Forms control that allows Content to be set, or that has a Children collection, can add platform-
specific views. For example, an iOS UILabel can be directly added to the ContentView.Content property, or to the
StackLayout.Children collection. However, note that this functionality requires the use of #if defines in
Xamarin.Forms Shared Project solutions, and isn't available from Xamarin.Forms .NET Standard library solutions.
The following screenshots demonstrate platform-specific views having been added to a Xamarin.Forms
StackLayout :
The ability to add platform-specific views to a Xamarin.Forms layout is enabled by two extension methods on each
platform:
Add – adds a platform-specific view to the Children collection of a layout.
ToView – takes a platform -specific view and wraps it as a Xamarin.Forms View that can be set as the Content
property of a control.
Using these methods in a Xamarin.Forms shared project requires importing the appropriate platform-specific
Xamarin.Forms namespace:
iOS – Xamarin.Forms.Platform.iOS
Android – Xamarin.Forms.Platform.Android
Universal Windows Platform (UWP ) – Xamarin.Forms.Platform.UWP
The example assumes that the stackLayout and contentView instances have previously been created in XAML or
C#.
Android
The following code example demonstrates how to add a TextView to a StackLayout and a ContentView :
The example assumes that the stackLayout and contentView instances have previously been created in XAML or
C#.
Universal Windows Platform
The following code example demonstrates how to add a TextBlock to a StackLayout and a ContentView :
The example assumes that the stackLayout and contentView instances have previously been created in XAML or
C#.
An instance of this view is added to a StackLayout , as demonstrated in the following code example:
However, because the CustomControl.SizeThatFits override always returns a height of 150, the view will be
displayed with empty space above and below it, as shown in the following screenshot:
if (uiView == null) {
return null;
}
This method uses the width provided by the CustomControl.SizeThatFits method, but substitutes the height of 150
for a height of 70. When the CustomControl instance is added to the StackLayout , the FixSize method can be
specified as the GetDesiredSizeDelegate to fix the bad measurement provided by the CustomControl class:
This results in the custom view being displayed correctly, without empty space above and below it, as shown in the
following screenshot:
Android
The following code example shows the CustomControl class, which inherits from TextView :
An instance of this view is added to a StackLayout , as demonstrated in the following code example:
var customControl = new CustomControl (MainActivity.Instance) {
Text = "This control has incorrect sizing - it doesn't occupy the available width of the device.",
TextSize = 14
};
stackLayout.Children.Add (customControl);
However, because the CustomControl.OnMeasure override always returns half of the requested width, the view will
be displayed occupying only half the available width of the device, as shown in the following screenshot:
This method uses the width provided by the CustomControl.OnMeasure method, but multiplies it by two. When the
CustomControl instance is added to the StackLayout , the FixSize method can be specified as the
GetDesiredSizeDelegate to fix the bad measurement provided by the CustomControl class:
This results in the custom view being displayed correctly, occupying the width of the device, as shown in the
following screenshot:
public CustomControl()
{
textBlock = new TextBlock
{
MinHeight = 0,
MaxHeight = double.PositiveInfinity,
MinWidth = 0,
MaxWidth = double.PositiveInfinity,
FontSize = 14,
TextWrapping = TextWrapping.Wrap,
VerticalAlignment = VerticalAlignment.Center
};
Children.Add(textBlock);
}
An instance of this view is added to a StackLayout , as demonstrated in the following code example:
However, because the CustomControl.ArrangeOverride override always returns half of the requested width, the view
will be clipped to half the available width of the device, as shown in the following screenshot:
A solution to this problem is to provide an ArrangeOverrideDelegate implementation, when adding the view to the
StackLayout , as demonstrated in the following code example:
This method uses the width provided by the CustomControl.ArrangeOverride method, but multiplies it by two. This
results in the custom view being displayed correctly, occupying the width of the device, as shown in the following
screenshot:
Summary
This article explained how to add native views to a Xamarin.Forms layout created using C#, and how to override
the layout of custom views to correct their measurement API usage.
Related Links
NativeEmbedding (sample)
Native Forms
Xamarin.Forms Other Platforms
1/10/2019 • 2 minutes to read • Edit Online
GTK
Xamarin.Forms now has preview support for GTK# apps.
Mac
Xamarin.Forms now has preview support for macOS apps.
Tizen
Tizen .NET enables you to build .NET applications with Xamarin.Forms and the Tizen .NET Framework.
WPF
Xamarin.Forms now has preview support for Windows Presentation Foundation (WPF ) apps.
GTK# Platform Setup
4/2/2019 • 5 minutes to read • Edit Online
Xamarin.Forms now has preview support for GTK# apps. GTK# is a graphical user interface toolkit that links the
GTK+ toolkit and a variety of GNOME libraries, allowing the development of fully native GNOME graphics apps
using Mono and .NET. This article demonstrates how to add a GTK# project to a Xamarin.Forms solution.
Before you start, create a new Xamarin.Forms solution, or use an existing Xamarin.Forms solution, for example,
GameOfLife.
NOTE
While this article focuses on adding a GTK# app to a Xamarin.Forms solution in VS2017 and Visual Studio for Mac, it can also
be performed in MonoDevelop for Linux.
namespace GameOfLife.GTK
{
class MainClass
{
[STAThread]
public static void Main(string[] args)
{
Gtk.Application.Init();
Forms.Init();
Gtk.Application.Run();
}
}
}
This code initializes GTK# and Xamarin.Forms, creates an application window, and runs the app.
11. In the Solution Explorer, right click the GTK project and select Properties.
12. In the Properties window, select the Application tab and change the Output type drop-down to
Windows Application.
13. In the Solution Explorer, right-click the GTK project and select Set as Startup Project. Press F5 to run the
program with the Visual Studio debugger on the Windows desktop:
Next Steps
Platform Specifics
You can determine what platform your Xamarin.Forms application is running on from either XAML or code. This
allows you to change program characteristics when it's running on GTK#. In code, compare the value of
Device.RuntimePlatform with the Device.GTK constant (which equals the string "GTK"). If there's a match, the
application is running on GTK#.
In XAML, you can use the OnPlatform tag to select a property value specific to the platform:
<Button.TextColor>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="White" />
<On Platform="macOS" Value="White" />
<On Platform="Android" Value="Black" />
<On Platform="GTK" Value="Blue" />
</OnPlatform>
</Button.TextColor>
Application Icon
You can set the app icon at startup:
window.SetApplicationIcon("icon.png");
Themes
There are a wide variety of themes available for GTK#, and they can be used from a Xamarin.Forms app:
GtkThemes.Init ();
GtkThemes.LoadCustomTheme ("Themes/gtkrc");
Native Forms
Native Forms allows Xamarin.Forms ContentPage -derived pages to be consumed by native projects, including
GTK# projects. This can be accomplished by creating an instance of the ContentPage -derived page and converting
it to the native GTK# type using the CreateContainer extension method:
Issues
This is a Preview, so you should expect that not everything is production ready. For the current implementation
status, see Status, and for the current known issues, see Pending & Known Issues.
Mac Platform Setup
5/1/2019 • 2 minutes to read • Edit Online
Before you start, create (or use an existing) Xamarin.Forms project. You can only add Mac apps using Visual Studio
for Mac.
5. In the Mac project, right-click on Packages > Add Packages... to add the Xamarin.Forms NuGet. You
should also update the other projects to use the same version of the Xamarin.Forms NuGet package.
6. In the Mac project, right-click on References and add a reference to the Xamarin.Forms project (either
Shared Project or .NET Standard library project).
7. Update Main.cs to initialize the AppDelegate :
8. Update AppDelegate to initialize Xamarin.Forms, create a window, and load the Xamarin.Forms application
(remembering to set an appropriate Title ). If you have other dependencies that need to be initialized, do
that here as well.
using Xamarin.Forms;
using Xamarin.Forms.Platform.MacOS;
// also add a using for the Xamarin.Forms project, if the namespace is different to this file
...
[Register("AppDelegate")]
public class AppDelegate : FormsApplicationDelegate
{
NSWindow window;
public AppDelegate()
{
var style = NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Titled;
9. Double-click Main.storyboard to edit in Xcode. Select the Window and uncheck the Is Initial Controller
checkbox (this is because the code above creates a window ):
You can edit the menu system in the storyboard to remove unwanted items.
10. Finally, add any local resources (eg. image files) from the existing platform projects that are required.
11. The Mac project should now run your Xamarin.Forms code on macOS!
Next Steps
Styling
With recent changes made to OnPlatform you can now target any number of platforms. That includes macOS.
<Button.TextColor>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="White"/>
<On Platform="macOS" Value="White"/>
<On Platform="Android" Value="Black"/>
</OnPlatform>
</Button.TextColor>
Note you may also double up on platforms like this: <On Platform="iOS, macOS" ...> .
Window Size and Position
You can adjust the initial size and location of the window in the AppDelegate :
Known Issues
This is a Preview, so you should expect that not everything is production ready. Below are a few things you may
encounter as you add macOS to your projects:
Not all NuGets are ready for macOS
You may find that some of the libraries you use do not yet support macOS. In this case, you'll need to send a
request to the project's maintainer to add it. Until they have support, you may need to look for alternatives.
Missing Xamarin.Forms Features
Not all Xamarin.Forms features are complete in this preview. For more information, see Platform Support macOS
Status in the Xamarin.Forms GitHub repository.
Related Links
Xamarin.Mac
Tizen .NET
1/10/2019 • 2 minutes to read • Edit Online
Tizen .NET allows you to develop Tizen applications to run on Samsung devices, including TVs, wearables, mobile
devices, and other IoT devices.
Tizen .NET enables you to build .NET applications with Xamarin.Forms and the Tizen .NET framework.
Xamarin.Forms allows you to easily create user interfaces, while the TizenFX API provides interfaces to the
hardware that's found in modern TV, mobile, wearable, and IoT devices. For more information about Tizen .NET,
see Introduction to Tizen .NET Application.
Get started
Before you can start developing Tizen .NET applications, you must first set up your development environment. For
more information, see Installing Visual Studio Tools for Tizen.
For information about how to add Tizen .NET project to an existing Xamarin.Forms solution, see Creating your
First Tizen .NET Application.
Documentation
Xamarin.Forms documentation – how to build cross-platform applications with C# and Xamarin.Forms.
developer.tizen.org – documentation and videos to help you build and deploy Tizen applications.
Samples
Samsung maintains a fork of the Xamarin.Forms samples with Tizen projects added, and there is a separate
repository Tizen-Csharp-Samples that contains additional projects, including Wearable and TV -specific demos.
WPF Platform Setup
5/1/2019 • 3 minutes to read • Edit Online
Xamarin.Forms now has preview support for the Windows Presentation Foundation (WPF ). This article
demonstrates how to add a WPF project to a Xamarin.Forms solution.
Before you start, create a new Xamarin.Forms solution in Visual Studio 2019, or use an existing Xamarin.Forms
solution, for example, BoxViewClock. You can only add WPF apps to a Xamarin.Forms solution in Windows.
7. In the WPF project, right-click on References. In the Reference Manager dialog, select Projects at the left,
and check the checkbox adjacent to the BoxViewClock project:
8. Edit the MainWindow.xaml file of the WPF project. In the Window tag, add an XML namespace
declaration for the Xamarin.Forms.Platform.WPF assembly and namespace:
xmlns:wpf="clr-namespace:Xamarin.Forms.Platform.WPF;assembly=Xamarin.Forms.Platform.WPF"
Now change the Window tag to wpf:FormsApplicationPage . Change the Title setting to the name of your
application, for example, BoxViewClock. The completed XAML file should look like this:
<wpf:FormsApplicationPage x:Class="BoxViewClock.WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpf="clr-namespace:Xamarin.Forms.Platform.WPF;assembly=Xamarin.Forms.Platform.WPF"
xmlns:local="clr-namespace:BoxViewClock.WPF"
mc:Ignorable="d"
Title="BoxViewClock" Height="450" Width="800">
<Grid>
</Grid>
</wpf:FormsApplicationPage>
9. Edit the MainWindow.xaml.cs file of the WPF project. Add two new using directives:
using Xamarin.Forms;
using Xamarin.Forms.Platform.WPF;
Change the base class of MainWindow from Window to FormsApplicationPage . Following the
InitializeComponent call, add the following two statements:
Forms.Init();
LoadApplication(new BoxViewClock.App());
Except for comments and unused using directives, the complete MainWindows.xaml.cs file should look
like this:
using Xamarin.Forms;
using Xamarin.Forms.Platform.WPF;
namespace BoxViewClock.WPF
{
public partial class MainWindow : FormsApplicationPage
{
public MainWindow()
{
InitializeComponent();
Forms.Init();
LoadApplication(new BoxViewClock.App());
}
}
}
10. Right-click the WPF project in the Solution Explorer and select Set as Startup Project. Press F5 to run
the program with the Visual Studio debugger on the Windows desktop:
Next Steps
Platform Specifics
You can determine what platform your Xamarin.Forms application is running on from either code or XAML. This
allows you to change program characteristics when it's running on WPF. In code, compare the value of
Device.RuntimePlatform with the Device.WPF constant (which equals the string "WPF"). If there's a match, the
application is running on WPF.
In XAML, you can use the OnPlatform tag to select a property value specific to the platform:
<Button.TextColor>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="White" />
<On Platform="macOS" Value="White" />
<On Platform="Android" Value="Black" />
<On Platform="WPF" Value="Blue" />
</OnPlatform>
</Button.TextColor>
Window Size
You can adjust the initial size of the window in the WPF MainWindow.xaml file:
Issues
This is a Preview, so you should expect that not everything is production ready. Not all NuGet packages for
Xamarin.Forms are ready for WPF, and some features might not be fully working.
Platform-Specifics
3/27/2019 • 6 minutes to read • Edit Online
NOTE
Note that attempting to consume a platform-specific on a platform where it is unavailable will not result in an error. Instead,
the code will execute without the platform-specific being applied.
Platform-specifics consumed through the On<T> fluent code API return IPlatformElementConfiguration objects.
This allows multiple platform-specifics to be invoked on the same object with method cascading.
For more information about the platform-specifics provided by Xamarin.Forms, see iOS Platform-Specifics,
Android Platform-Specifics, and Windows Platform-Specifics.
Creating platform-specifics
Vendors can create their own platform-specifics with Effects. An Effect provides the specific functionality, which is
then exposed through a platform-specific. The result is an Effect that can be more easily consumed through XAML,
and through a fluent code API.
The process for creating a platform-specific is as follows:
1. Implement the specific functionality as an Effect. For more information, see Creating an Effect.
2. Create a platform-specific class that will expose the Effect. For more information, see Creating a Platform-
Specific Class.
3. In the platform-specific class, implement an attached property to allow the platform-specific to be consumed
through XAML. For more information, see Adding an Attached Property.
4. In the platform-specific class, implement extension methods to allow the platform-specific to be consumed
through a fluent code API. For more information, see Adding Extension Methods.
5. Modify the Effect implementation so that the Effect is only applied if the platform-specific has been invoked on
the same platform as the Effect. For more information, see Creating the Effect.
The result of exposing an Effect as a platform-specific is that the Effect can be more easily consumed through
XAML and through a fluent code API.
NOTE
It's envisaged that vendors will use this technique to create their own platform-specifics, for ease of consumption by users.
While users may choose to create their own platform-specifics, it should be noted that it requires more code than creating
and consuming an Effect.
The sample application demonstrates a Shadow platform-specific that adds a shadow to the text displayed by a
Label control:
The sample application implements the Shadow platform-specific on each platform, for ease of understanding.
However, aside from each platform-specific Effect implementation, the implementation of the Shadow class is
largely identical for each platform. Therefore, this guide focusses on the implementation of the Shadow class and
associated Effect on a single platform.
For more information about Effects, see Customizing Controls with Effects.
Creating a platform-specific class
A platform-specific is created as a public static class:
namespace MyCompany.Forms.PlatformConfiguration.iOS
{
public static Shadow
{
...
}
}
The following sections discuss the implementation of the Shadow platform-specific and associated Effect.
Adding an attached property
An attached property must be added to the Shadow platform-specific to allow consumption through XAML:
namespace MyCompany.Forms.PlatformConfiguration.iOS
{
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using FormsElement = Xamarin.Forms.Label;
...
The IsShadowed attached property is used to add the MyCompany.LabelShadowEffect Effect to, and remove it from,
the control that the Shadow class is attached to. This attached property registers the OnIsShadowedPropertyChanged
method that will be executed when the value of the property changes. In turn, this method calls the AttachEffect
or DetachEffect method to add or remove the effect based on the value of the IsShadowed attached property. The
Effect is added to or removed from the control by modifying the control's Effects collection.
NOTE
Note that the Effect is resolved by specifying a value that's a concatenation of the resolution group name and unique
identifier that's specified on the Effect implementation. For more information, see Creating an Effect.
namespace MyCompany.Forms.PlatformConfiguration.iOS
{
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using FormsElement = Xamarin.Forms.Label;
The IsShadowed and SetIsShadowed extension methods invoke the get and set accessors for the IsShadowed
attached property, respectively. Each extension method operates on the
IPlatformElementConfiguration<iOS, FormsElement> type, which specifies that the platform -specific can be invoked
on Label instances from iOS.
Creating the effect
The Shadow platform-specific adds the MyCompany.LabelShadowEffect to a Label , and removes it. The following
code example shows the LabelShadowEffect implementation for the iOS project:
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace ShadowPlatformSpecific.iOS
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached()
{
UpdateShadow();
}
if (args.PropertyName == Shadow.IsShadowedProperty.PropertyName)
{
UpdateShadow();
}
}
void UpdateShadow()
{
try
{
if (((Label)Element).OnThisPlatform().IsShadowed())
{
Control.Layer.CornerRadius = 5;
Control.Layer.ShadowColor = UIColor.Black.CGColor;
Control.Layer.ShadowOffset = new CGSize(5, 5);
Control.Layer.ShadowOpacity = 1.0f;
}
else if (!((Label)Element).OnThisPlatform().IsShadowed())
{
Control.Layer.ShadowOpacity = 0;
}
}
catch (Exception ex)
{
Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}
}
}
The UpdateShadow method sets Control.Layer properties to create the shadow, provided that the IsShadowed
attached property is set to true , and provided that the Shadow platform-specific has been invoked on the same
platform that the Effect is implemented for. This check is performed with the OnThisPlatform method.
If the Shadow.IsShadowed attached property value changes at runtime, the Effect needs to respond by removing the
shadow. Therefore, an overridden version of the OnElementPropertyChanged method is used to respond to the
bindable property change by calling the UpdateShadow method.
For more information about creating an effect, see Creating an Effect and Passing Effect Parameters as Attached
Properties.
Consuming the platform-specific
The Shadow platform-specific is consumed in XAML by setting the Shadow.IsShadowed attached property to a
boolean value:
<ContentPage xmlns:ios="clr-namespace:MyCompany.Forms.PlatformConfiguration.iOS" ...>
...
<Label Text="Label Shadow Effect" ios:Shadow.IsShadowed="true" ... />
...
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using MyCompany.Forms.PlatformConfiguration.iOS;
...
shadowLabel.On<iOS>().SetIsShadowed(true);
Related links
PlatformSpecifics (sample)
ShadowPlatformSpecific (sample)
iOS Platform-Specifics
Android Platform-Specifics
Windows Platform-Specifics
Customizing Controls with Effects
Attached Properties
PlatformConfiguration API
Windows Platform Features
3/27/2019 • 2 minutes to read • Edit Online
Developing Xamarin.Forms applications for Windows platforms requires Visual Studio. The requirements page
contains more information about the pre-requisites.
Platform-specifics
Platform-specifics allow you to consume functionality that's only available on a specific platform, without
implementing custom renderers or effects.
The following platform-specific functionality is provided for Xamarin.Forms views, pages, and layouts on the
Universal Windows Platform (UWP ):
Setting an access key for a VisualElement . For more information, see VisualElement Access Keys on Windows.
Disabling legacy color mode on a supported VisualElement . For more information, see VisualElement Legacy
Color Mode on Windows.
The following platform-specific functionality is provided for Xamarin.Forms views on UWP:
Detecting reading order from text content in Entry , Editor , and Label instances. For more information, see
InputView Reading Order on Windows.
Enabling tap gesture support in a ListView . For more information, see ListView SelectionMode on Windows.
Enabling a SearchBar to interact with the spell check engine. For more information, see SearchBar Spell Check
on Windows.
Enabling a WebView to display JavaScript alerts in a UWP message dialog. For more information, see
WebView JavaScript Alerts on Windows.
The following platform-specific functionality is provided for Xamarin.Forms pages on UWP:
Collapsing the MasterDetailPage navigation bar. For more information, see MasterDetailPage Navigation Bar
on Windows.
Setting toolbar placement options. For more information, see Page Toolbar Placement on Windows.
Enabling page icons to be displayed on a TabbedPage toolbar. For more information, see TabbedPage Icons on
Windows.
Platform support
The Xamarin.Forms templates available in Visual Studio contain a Universal Windows Platform (UWP ) project.
NOTE
Xamarin.Forms 1.x and 2.x support Windows Phone 8 Silverlight, Windows Phone 8.1, and Windows 8.1 application
development. However, these project types have been deprecated.
Getting started
Go to File > New > Project in Visual Studio and choose one of the Cross-Platform > Blank App
(Xamarin.Forms) templates to get started.
Older Xamarin.Forms solutions, or those created on macOS, will not have all the Windows projects listed above
(but they need to be manually added). If the Windows platform you wish to target isn't already in your solution,
vist the setup instructions to add the desired Windows project type/s.
Samples
All the samples for Charles Petzold's book Creating Mobile Apps with Xamarin.Forms include Universal Windows
Platform (for Windows 10) projects.
The "Scott Hanselman" demo app is available separately, and also includes Apple Watch and Android Wear
projects (using Xamarin.iOS and Xamarin.Android respectively, Xamarin.Forms does not run on those platforms).
Related links
Setup Windows Projects
InputView Reading Order on Windows
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<Editor ... windows:InputView.DetectReadingOrderFromContent="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
editor.On<Windows>().SetDetectReadingOrderFromContent(true);
The Editor.On<Windows> method specifies that this platform-specific will only run on the Universal Windows
Platform. The InputView.SetDetectReadingOrderFromContent method, in the
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, is used to control whether the reading order is
detected from the content in the InputView . In addition, the InputView.SetDetectReadingOrderFromContent method
can be used to toggle whether the reading order is detected from the content by calling the
InputView.GetDetectReadingOrderFromContent method to return the current value:
editor.On<Windows>().SetDetectReadingOrderFromContent(!editor.On<Windows>
().GetDetectReadingOrderFromContent());
The result is that Entry , Editor , and Label instances can have the reading order of their content detected
dynamically:
NOTE
Unlike setting the FlowDirection property, the logic for views that detect the reading order from their text content will not
affect the alignment of text within the view. Instead, it adjusts the order in which blocks of bidirectional text are laid out.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
ListView SelectionMode on Windows
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<ListView ... windows:ListView.SelectionMode="Inaccessible">
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
listView.On<Windows>().SetSelectionMode(ListViewSelectionMode.Inaccessible);
The ListView.On<Windows> method specifies that this platform-specific will only run on the Universal Windows
Platform. The ListView.SetSelectionMode method, in the Xamarin.Forms.PlatformConfiguration.WindowsSpecific
namespace, is used to control whether items in a ListView can respond to tap gestures, with the
ListViewSelectionMode enumeration providing two possible values:
Accessible – indicates that the ListView will fire the native ItemClick event to handle interaction, and hence
provide accessibility functionality. Therefore, the Windows Narrator and the keyboard can interact with the
ListView . However, items in the ListView can't respond to tap gestures. This is the default behavior for
ListView instances on the Universal Windows Platform.
Inaccessible – indicates that the ListView will fire the native Tapped event to handle interaction. Therefore,
items in the ListView can respond to tap gestures. However, there's no accessibility functionality and hence the
Windows Narrator and the keyboard can't interact with the ListView .
NOTE
The Accessible and Inaccessible selection modes are mutually exclusive, and you will need to choose between an
accessible ListView or a ListView that can respond to tap gestures.
In addition, the GetSelectionMode method can be used to return the current ListViewSelectionMode .
The result is that a specified ListViewSelectionMode is applied to the ListView , which controls whether items in the
ListView can respond to tap gestures, and hence whether the native ListView fires the ItemClick or Tapped
event.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
MasterDetailPage Navigation Bar on Windows
1/10/2019 • 2 minutes to read • Edit Online
<MasterDetailPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:MasterDetailPage.CollapseStyle="Partial"
windows:MasterDetailPage.CollapsedPaneWidth="48">
...
</MasterDetailPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
page.On<Windows>().SetCollapseStyle(CollapseStyle.Partial).CollapsedPaneWidth(148);
The MasterDetailPage.On<Windows> method specifies that this platform-specific will only run on Windows. The
Page.SetCollapseStyle method, in the Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, is used to
specify the collapse style, with the CollapseStyle enumeration providing two values: Full and Partial . The
MasterDetailPage.CollapsedPaneWidth method is used to specify the width of a partially collapsed navigation bar.
The result is that a specified CollapseStyle is applied to the MasterDetailPage instance, with the width also being
specified:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
Page Toolbar Placement on Windows
1/10/2019 • 2 minutes to read • Edit Online
<TabbedPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:Page.ToolbarPlacement="Bottom">
...
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
page.On<Windows>().SetToolbarPlacement(ToolbarPlacement.Bottom);
The Page.On<Windows> method specifies that this platform-specific will only run on Windows. The
Page.SetToolbarPlacement method, in the Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, is used
to set the toolbar placement, with the ToolbarPlacement enumeration providing three values: Default , Top , and
Bottom .
The result is that the specified toolbar placement is applied to the Page instance:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
Setup Windows Projects
4/2/2019 • 3 minutes to read • Edit Online
2 . In the New Universal Windows Platform Project dialog, select the minimum and target versions of
Windows 10 that the app will run on:
3 . Right-click on the UWP project and select Manage NuGet Packages... and add the Xamarin.Forms package.
Ensure the other projects in the solution are also updated to the same version of the Xamarin.Forms package.
4 . Make sure the new UWP project will be built in the Build > Configuration Manager window (this probably
won't have happened by default). Tick the Build and Deploy boxes for the Universal project:
5 . Right-click on the project and select Add > Reference and create a reference to the Xamarin.Forms
application project (.NET Standard or Shared Project).
6 . In the UWP project, edit App.xaml.cs to include the Init method call inside the OnLaunched method around
line 52:
7 . In the UWP project, edit MainPage.xaml by removing the Grid contained within the Page element.
8 . In MainPage.xaml, add a new xmlns entry for Xamarin.Forms.Platform.UWP :
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
<forms:WindowsPage
...
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
...
</forms:WindowsPage>
10 . In the UWP project, edit MainPage.xaml.cs to remove the : Page inheritance specifier for the class name
(since it will now inherit from WindowsPage due to the change made in the previous step):
11 . In MainPage.xaml.cs, add the LoadApplication call in the MainPage constructor to start the Xamarin.Forms
app:
12 . Add any local resources (eg. image files) from the existing platform projects that are required.
Troubleshooting
"Target Invocation Exception" when using "Compile with .NET Native tool chain"
If your UWP app is referencing multiple assemblies (for example third party control libraries, or your app itself is
split into multiple libraries), Xamarin.Forms may be unable to load objects from those assemblies (such as custom
renderers).
This might occur when using the Compile with .NET Native tool chain which is an option for UWP apps in the
Properties > Build > General window for the project.
You can fix this by using a UWP -specific overload of the Forms.Init call in App.xaml.cs as shown in the code
below (you should replace ClassInOtherAssembly with an actual class your code references):
Add an entry for each assembly that you have added as a reference in the Solution Explorer, either via a direct
reference or a NuGet.
Dependency Services and .NET Native Compilation
Release builds using .NET Native compilation can fail to resolve dependency services that are defined outside the
main app executable (such as in a separate project or library).
Use the DependencyService.Register<T>() method to manually register dependency service classes. Based on the
example above, add the register method like this:
Xamarin.Forms.Forms.Init(e, assembliesToInclude);
Xamarin.Forms.DependencyService.Register<ClassInOtherAssembly>(); // add this
SearchBar Spell Check on Windows
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<SearchBar ... windows:SearchBar.IsSpellCheckEnabled="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
searchBar.On<Windows>().SetIsSpellCheckEnabled(true);
The SearchBar.On<Windows> method specifies that this platform-specific will only run on the Universal Windows
Platform. The SearchBar.SetIsSpellCheckEnabled method, in the
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, turns the spell checker on and off. In addition,
the SearchBar.SetIsSpellCheckEnabled method can be used to toggle the spell checker by calling the
SearchBar.GetIsSpellCheckEnabled method to return whether the spell checker is enabled:
searchBar.On<Windows>().SetIsSpellCheckEnabled(!searchBar.On<Windows>().GetIsSpellCheckEnabled());
The result is that text entered into the SearchBar can be spell checked, with incorrect spellings being indicated to
the user:
NOTE
The SearchBar class in the Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace also has
EnableSpellCheck and DisableSpellCheck methods that can be used to enable and disable the spell checker on the
SearchBar , respectively.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
TabbedPage Icons on Windows
1/10/2019 • 2 minutes to read • Edit Online
<TabbedPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:TabbedPage.HeaderIconsEnabled="true">
<windows:TabbedPage.HeaderIconsSize>
<Size>
<x:Arguments>
<x:Double>24</x:Double>
<x:Double>24</x:Double>
</x:Arguments>
</Size>
</windows:TabbedPage.HeaderIconsSize>
<ContentPage Title="Todo" Icon="todo.png">
...
</ContentPage>
<ContentPage Title="Reminders" Icon="reminders.png">
...
</ContentPage>
<ContentPage Title="Contacts" Icon="contacts.png">
...
</ContentPage>
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
The TabbedPage.On<Windows> method specifies that this platform-specific will only run on the Universal Windows
Platform. The TabbedPage.SetHeaderIconsEnabled method, in the
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, is used to turn header icons on or off. The
TabbedPage.SetHeaderIconsSize method optionally specifies the header icon size with a Size value.
In addition, the TabbedPage class in the Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace also has
a EnableHeaderIcons method that enables header icons, a DisableHeaderIcons method that disables header icons,
and a IsHeaderIconsEnabled method that returns a boolean value that indicates whether header icons are enabled.
The result is that page icons can be displayed on a TabbedPage toolbar, with the icon size being optionally set to a
desired size:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
VisualElement Access Keys on Windows
1/10/2019 • 3 minutes to read • Edit Online
<TabbedPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<ContentPage Title="Page 1"
windows:VisualElement.AccessKey="1">
<StackLayout Margin="20">
...
<Switch windows:VisualElement.AccessKey="A" />
<Entry Placeholder="Enter text here"
windows:VisualElement.AccessKey="B" />
...
<Button Text="Access key F, placement top with offsets"
Margin="20"
Clicked="OnButtonClicked"
windows:VisualElement.AccessKey="F"
windows:VisualElement.AccessKeyPlacement="Top"
windows:VisualElement.AccessKeyHorizontalOffset="20"
windows:VisualElement.AccessKeyVerticalOffset="20" />
...
</StackLayout>
</ContentPage>
...
</TabbedPage>
var button4 = new Button { Text = "Access key F, placement top with offsets", Margin = new Thickness(20) };
button4.Clicked += OnButtonClicked;
button4.On<Windows>()
.SetAccessKey("F")
.SetAccessKeyPlacement(AccessKeyPlacement.Top)
.SetAccessKeyHorizontalOffset(20)
.SetAccessKeyVerticalOffset(20);
...
The VisualElement.On<Windows> method specifies that this platform-specific will only run on the Universal
Windows Platform. The VisualElement.SetAccessKey method, in the
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, is used to set the access key value for the
VisualElement . The VisualElement.SetAccessKeyPlacement method, optionally specifies the position to use for
displaying the access key tip, with the AccessKeyPlacement enumeration providing the following possible values:
Auto – indicates that the access key tip placement will be determined by the operating system.
Top – indicates that the access key tip will appear above the top edge of the VisualElement .
Bottom – indicates that the access key tip will appear below the lower edge of the VisualElement .
Right – indicates that the access key tip will appear to the right of the right edge of the VisualElement .
Left – indicates that the access key tip will appear to the left of the left edge of the VisualElement .
Center – indicates that the access key tip will appear overlaid on the center of the VisualElement .
NOTE
Typically, the Auto key tip placement is sufficient, which includes support for adaptive user interfaces.
NOTE
Access key tip offsets can't be set when the access key placement is set Auto .
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
VisualElement Legacy Color Mode on Windows
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
...
<Editor Text="Enter text here"
TextColor="Blue"
BackgroundColor="Bisque"
windows:VisualElement.IsLegacyColorModeEnabled="False" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
_legacyColorModeDisabledEditor.On<Windows>().SetIsLegacyColorModeEnabled(false);
The VisualElement.On<Windows> method specifies that this platform-specific will only run on Windows. The
VisualElement.SetIsLegacyColorModeEnabled method, in the Xamarin.Forms.PlatformConfiguration.WindowsSpecific
namespace, is used to control whether the legacy color mode is disabled. In addition, the
VisualElement.GetIsLegacyColorModeEnabled method can be used to return whether the legacy color mode is
disabled.
The result is that the legacy color mode can be disabled, so that colors set on a view by the user remain even when
the view is disabled:
NOTE
When setting a VisualStateGroup on a view, the legacy color mode is completely ignored. For more information about
visual states, see The Xamarin.Forms Visual State Manager.
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
WebView JavaScript Alerts on Windows
1/10/2019 • 2 minutes to read • Edit Online
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<WebView ... windows:WebView.IsJavaScriptAlertEnabled="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
The WebView.On<Windows> method specifies that this platform-specific will only run on the Universal Windows
Platform. The WebView.SetIsJavaScriptAlertEnabled method, in the
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, is used to control whether JavaScript alerts are
enabled. In addition, the WebView.SetIsJavaScriptAlertEnabled method can be used to toggle JavaScript alerts by
calling the IsJavaScriptAlertEnabled method to return whether they are enabled:
_webView.On<Windows>().SetIsJavaScriptAlertEnabled(!_webView.On<Windows>().IsJavaScriptAlertEnabled());
The result is that JavaScript alerts can be displayed in a UWP message dialog:
Related links
PlatformSpecifics (sample)
Creating Platform-Specifics
WindowsSpecific API
Xamarin.Essentials
4/22/2019 • 2 minutes to read • Edit Online
Xamarin.Essentials provides developers with cross-platform APIs for their mobile applications.
Android, iOS, and UWP offer unique operating system and platform APIs that developers have access to all in C#
leveraging Xamarin. Xamarin.Essentials provides a single cross-platform API that works with any Xamarin.Forms,
Android, iOS, or UWP application that can be accessed from shared code no matter how the user interface is
created.
Feature Guides
Follow the guides to integrate these Xamarin.Essentials features into your applications:
Accelerometer – Retrieve acceleration data of the device in three dimensional space.
App Information – Find out information about the application.
Barometer – Monitor the barometer for pressure changes.
Battery – Easily detect battery level, source, and state.
Clipboard – Quickly and easily set or read text on the clipboard.
Color Converters – Helper methods for System.Drawing.Color.
Compass – Monitor compass for changes.
Connectivity – Check connectivity state and detect changes.
Detect Shake – Detect a shake movement of the device.
Device Display Information – Get the device's screen metrics and orientation.
Device Information – Find out about the device with ease.
Email – Easily send email messages.
File System Helpers – Easily save files to app data.
Flashlight – A simple way to turn the flashlight on/off.
Geocoding – Geocode and reverse geocode addresses and coordinates.
Geolocation – Retrieve the device's GPS location.
Gyroscope – Track rotation around the device's three primary axes.
Launcher – Enables an application to open a URI by the system.
Magnetometer – Detect device's orientation relative to Earth's magnetic field.
MainThread – Run code on the application's main thread.
Maps – Open the maps application to a specific location.
Open Browser – Quickly and easily open a browser to a specific website.
Orientation Sensor – Retrieve the orientation of the device in three dimensional space.
Phone Dialer – Open the phone dialer.
Platform Extensions – Helper methods for converting Rect, Size, and Point.
Preferences – Quickly and easily add persistent preferences.
Secure Storage – Securely store data.
Share – Send text and website uris to other apps.
SMS – Create an SMS message for sending.
Text-to-Speech – Vocalize text on the device.
Unit Converters – Helper methods to convert units.
Version Tracking – Track the applications version and build numbers.
Vibrate – Make the device vibrate.
Troubleshooting
Find help if you are running into issues.
API Documentation
Browse the API documentation for every feature of Xamarin.Essentials.
Get Started with Xamarin.Essentials
4/2/2019 • 2 minutes to read • Edit Online
Xamarin.Essentials provides a single cross-platform API that works with any iOS, Android, or UWP
application that can be accessed from shared code no matter how the user interface is created.
Platform Support
Xamarin.Essentials supports the following platforms and operating systems:
PLATFORM VERSION
Installation
Xamarin.Essentials is available as a NuGet package that can be added to any existing or new project using
Visual Studio.
1. Download and install Visual Studio with the Visual Studio tools for Xamarin.
2. Open an existing project, or create a new project using the Blank App template under Visual Studio
C# (Android, iPhone & iPad, or Cross-Platform). Important: If adding to a UWP project ensure Build
16299 or higher is set in the project properties.
3. Add the Xamarin.Essentials NuGet package to each project:
Visual Studio
Visual Studio for Mac
In the Solution Explorer panel, right click on the solution name and select Manage NuGet Packages.
Search for Xamarin.Essentials and install the package into ALL projects including Android, iOS,
UWP, and .NET Standard libraries.
4. Add a reference to Xamarin.Essentials in any C# class to reference the APIs.
using Xamarin.Essentials;
6. Follow the Xamarin.Essentials guides that enable you to copy and paste code snippets for each feature.
Other Resources
We recommend developers new to Xamarin visit getting started with Xamarin development.
Visit the Xamarin.Essentials GitHub Repository to see the current source code, what is coming next, run
samples, and clone the repository. Community contributions are welcome!
Browse through the API documentation for every feature of Xamarin.Essentials.
Xamarin.Essentials: Accelerometer
4/2/2019 • 2 minutes to read • Edit Online
The Accelerometer class lets you monitor the device's accelerometer sensor, which indicates the acceleration of
the device in three-dimensional space.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Accelerometer
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Accelerometer functionality works by calling the Start and Stop methods to listen for changes to the
acceleration. Any changes are sent back through the ReadingChanged event. Here is sample usage:
public class AccelerometerTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;
public AccelerometerTest()
{
// Register for reading changes, be sure to unsubscribe when finished
Accelerometer.ReadingChanged += Accelerometer_ReadingChanged;
}
Accelerometer readings are reported back in G. A G is a unit of gravitation force equal to that exerted by the
earth's gravitational field (9.81 m/s^2).
The coordinate-system is defined relative to the screen of the phone in its default orientation. The axes are not
swapped when the device's screen orientation changes.
The X axis is horizontal and points to the right, the Y axis is vertical and points up and the Z axis points towards the
outside of the front face of the screen. In this system, coordinates behind the screen have negative Z values.
Examples:
When the device lies flat on a table and is pushed on its left side toward the right, the x acceleration value is
positive.
When the device lies flat on a table, the acceleration value is +1.00 G or (+9.81 m/s^2), which correspond
to the acceleration of the device (0 m/s^2) minus the force of gravity (-9.81 m/s^2) and normalized as in G.
When the device lies flat on a table and is pushed toward the sky with an acceleration of A m/s^2, the
acceleration value is equal to A+9.81 which corresponds to the acceleration of the device (+A m/s^2)
minus the force of gravity (-9.81 m/s^2) and normalized in G.
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Default – Default rate suitable for screen orientation changes.
UI – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
API
Accelerometer source code
Accelerometer API documentation
Related Video
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using AppInfo
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
// Application Name
var appName = AppInfo.Name;
This settings page allows the user to change application permissions and perform other platform-specific tasks.
API
AppInfo source code
AppInfo API documentation
Related Video
Find more of The Xamarin Show on Channel 9 and YouTube.
Xamarin.Essentials: Barometer
12/4/2018 • 2 minutes to read • Edit Online
The Barometer class lets you monitor the device's barometer sensor, which measures pressure.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Barometer
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Barometer functionality works by calling the Start and Stop methods to listen for changes to the
barometer's pressure reading in hectopascals. Any changes are sent back through the ReadingChanged event. Here
is sample usage:
public class BarometerTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;
public BarometerTest()
{
// Register for reading changes.
Barometer.ReadingChanged += Barometer_ReadingChanged;
}
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Default – Default rate suitable for screen orientation changes.
UI – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
API
Barometer source code
Barometer API documentation
Xamarin.Essentials: Battery
1/23/2019 • 3 minutes to read • Edit Online
The Battery class lets you check the device's battery information and monitor for changes and provides
information about the device's energy-saver status, which indicates if the device is running in a low -power mode.
Applications should avoid background processing if the device's energy-saver status is on.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
To access the Battery functionality the following platform specific setup is required.
Android
iOS
UWP
The Battery permission is required and must be configured in the Android project. This can be added in the
following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.BatteryStats)]
Or right click on the Android project and open the project's properties. Under Android Manifest find the
Required permissions: area and check the Battery permission. This will automatically update the
AndroidManifest.xml file.
Using Battery
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
switch (state)
{
case BatteryState.Charging:
// Currently charging
break;
case BatteryState.Full:
// Battery is full
break;
case BatteryState.Discharging:
case BatteryState.NotCharging:
// Currently discharging battery or not being charged
break;
case BatteryState.NotPresent:
// Battery doesn't exist in device (desktop computer)
case BatteryState.Unknown:
// Unable to detect battery state
break;
}
switch (source)
{
case BatteryPowerSource.Battery:
// Being powered by the battery
break;
case BatteryPowerSource.AC:
// Being powered by A/C unit
break;
case BatteryPowerSource.Usb:
// Being powered by USB cable
break;
case BatteryPowerSource.Wireless:
// Powered via wireless charging
break;
case BatteryPowerSource.Unknown:
// Unable to detect power source
break;
}
Devices that run on batteries can be put into a low -power energy-saver mode. Sometimes devices are switched
into this mode automatically, for example, when the battery drops below 20% capacity. The operating system
responds to energy-saver mode by reducing activities that tend to deplete the battery. Applications can help by
avoiding background processing or other high-power activities when energy-saver mode is on.
You can also obtain the current energy-saver status of the device using the static Battery.EnergySaverStatus
property:
This property returns a member of the EnergySaverStatus enumeration, which is either On , Off , or Unknown . If
the property returns On , the application should avoid background processing or other activities that might
consume a lot of power.
The application should also install an event handler. The Battery class exposes an event that is triggered when the
energy-saver status changes:
If the energy-saver status changes to On , the application should stop performing background processing. If the
status changes to Unknown or Off , the application can resume background processing.
Platform Differences
Android
iOS
UWP
No platform differences.
API
Battery source code
Battery API documentation
Related Video
Find more of The Xamarin Show on Channel 9 and YouTube.
Xamarin.Essentials: Clipboard
2/13/2019 • 2 minutes to read • Edit Online
The Clipboard class lets you copy and paste text to the system clipboard between applications.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Clipboard
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
API
Clipboard source code
Clipboard API documentation
Related Video
The ColorConverters class in Xamarin.Essentials provides several helper methods for System.Drawing.Color.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
using Xamarin.Essentials;
When working with System.Drawing.Color you can use the built in converters of Xamarin.Forms to create a color
from Hsl, Hex, or UInt.
// Back to System.Drawing.Color
var system = platform.ToSystemColor();
API
Color Converters source code
Color Converters API documentation
Color Extensions source code
Color Extensions API documentation
Xamarin.Essentials: Compass
12/4/2018 • 2 minutes to read • Edit Online
The Compass class lets you monitor the device's magnetic north heading.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Compass
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Compass functionality works by calling the Start and Stop methods to listen for changes to the compass.
Any changes are sent back through the ReadingChanged event. Here is an example:
public CompassTest()
{
// Register for reading changes, be sure to unsubscribe when finished
Compass.ReadingChanged += Compass_ReadingChanged;
}
This is only applied on the Android platform, and the parameter is ignored on iOS and UWP. More information
can be read here.
API
Compass source code
Compass API documentation
Xamarin.Essentials: Connectivity
1/8/2019 • 2 minutes to read • Edit Online
The Connectivity class lets you monitor for changes in the device's network conditions, check the current network
access, and how it is currently connected.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
To access the Connectivity functionality the following platform specific setup is required.
Android
iOS
UWP
The AccessNetworkState permission is required and must be configured in the Android project. This can be added
in the following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.AccessNetworkState)]
Or right click on the Android project and open the project's properties. Under Android Manifest find the
Required permissions: area and check the Access Network State permission. This will automatically update the
AndroidManifest.xml file.
Using Connectivity
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
if (current == NetworkAccess.Internet)
{
// Connection to internet is available
}
Network access falls into the following categories:
Internet – Local and internet access.
ConstrainedInternet – Limited internet access. Indicates captive portal connectivity, where local access to a
web portal is provided, but access to the Internet requires that specific credentials are provided via a portal.
Local – Local network access only.
None – No connectivity is available.
Unknown – Unable to determine internet connectivity.
You can check what type of connection profile the device is actively using:
Whenever the connection profile or network access changes you can receive an event when triggered:
Limitations
It is important to note that it is possible that Internet is reported by NetworkAccess but full access to the web is
not available. Due to how connectivity works on each platform it can only guarantee that a connection is available.
For instance the device may be connected to a Wi-Fi network, but the router is disconnected from the internet. In
this instance Internet may be reported, but an active connection is not available.
API
Connectivity source code
Connectivity API documentation
Related Video
Find more of The Xamarin Show on Channel 9 and YouTube.
Xamarin.Essentials: Detect Shake
4/4/2019 • 2 minutes to read • Edit Online
The Accelerometer class lets you monitor the device's accelerometer sensor, which indicates the acceleration of
the device in three-dimensional space. Additionally, it enables you to register for events when the user shakes the
device.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
using Xamarin.Essentials;
To detect a shake of the device you must use the Accelerometer functionality by calling the Start and Stop
methods to listen for changes to the acceleration and to detect a shake. Any time a shake is detected a
ShakeDetected event will fire. It is recommended to use Game or faster for the SensorSpeed . Here is sample usage:
public class DetectShakeTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.Game;
public DetectShakeTest()
{
// Register for reading changes, be sure to unsubscribe when finished
Accelerometer.ShakeDetected += Accelerometer_ShakeDetected ;
}
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Default – Default rate suitable for screen orientation changes.
UI – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
Implementation Details
The detect shake API uses raw readings from the accelerometer to calculate acceleration. It uses a simple queue
mechanism to detect if 3/4ths of the recent accelerometer events occurred in the last half second. Acceleration is
calculated by adding the square of the X, Y, and Z readings from the accelerometer and comparing it to a specific
threashold.
API
Accelerometer source code
Accelerometer API documentation
Xamarin.Essentials: Device Display Information
2/11/2019 • 2 minutes to read • Edit Online
The DeviceDisplay class provides information about the device's screen metrics the application is running on and
can request to keep the screen from falling asleep when the application is running.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using DeviceDisplay
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
// Get Metrics
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
// Screen density
var density = mainDisplayInfo.Density;
The DeviceDisplay class also exposes an event that can be subscribed to that is triggered whenever any screen
metric changes:
public class DisplayInfoTest
{
public DisplayInfoTest()
{
// Subscribe to changes of screen metrics
DeviceDisplay.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
}
The DeviceDisplay class exposes a bool property called KeepScreenOn that can be set to attempt to keep the
device's display from turning off or locking.
Platform Differences
Android
iOS
UWP
No differences.
API
DeviceDisplay source code
DeviceDisplay API documentation
Xamarin.Essentials: Device Information
3/21/2019 • 2 minutes to read • Edit Online
The DeviceInfo class provides information about the device the application is running on.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using DeviceInfo
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
// Manufacturer (Samsung)
var manufacturer = DeviceInfo.Manufacturer;
// Platform (Android)
var platform = DeviceInfo.Platform;
// Idiom (Phone)
var idiom = DeviceInfo.Idiom;
Platforms
DeviceInfo.Platform correlates to a constant string that maps to the operating system. The values can be checked
with the DevicePlatform struct:
DevicePlatform.iOS – iOS
DevicePlatform.Android – Android
DevicePlatform.UWP – UWP
DevicePlatform.Unknown – Unknown
Idioms
DeviceInfo.Idiom correlates a constant string that maps to the type of device the application is running on. The
values can be checked with the DeviceIdiom struct:
DeviceIdiom.Phone – Phone
DeviceIdiom.Tablet – Tablet
DeviceIdiom.Desktop – Desktop
DeviceIdiom.TV – TV
DeviceIdiom.Watch – Watch
DeviceIdiom.Unknown – Unknown
Device Type
DeviceInfo.DeviceType correlates an enumeration to determine if the application is running on a physical or virtual
device. A virtual device is a simulator or emulator.
API
DeviceInfo source code
DeviceInfo API documentation
Xamarin.Essentials: Email
4/2/2019 • 2 minutes to read • Edit Online
The Email class enables an application to open the default email application with a specified information including
subject, body, and recipients (TO, CC, BCC ).
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Email
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Email functionality works by calling the ComposeAsync method an EmailMessage that contains information
about the email:
Platform Differences
Android
iOS
UWP
Not all email clients for Android support Html , since there is no way to detect this we recommend using
PlainText when sending emails.
File Attachments
Emailing files is available as an experimental preview in Xamarin.Essentials version 1.1.0. This features enables an
app to emails files in email clients on the device. To enable this feature set the following property in your app's
startup code:
ExperimentalFeatures.Enable(ExperimentalFeatures.EmailAttachments);
After the feature enabled any file can be emailed. Xamarin.Essentials will automatically detect the file type (MIME )
and request the file to be added as an attachment. Every email client is different a may only support specific file
extensions or none at all.
Here is a sample of writing text to disk and adding it as an email attachment:
var fn = "Attachment.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
message.Attachments.Add(new EmailAttachment(file));
await Email.ComposeAsync(message);
API
Email source code
Email API documentation
Xamarin.Essentials: File System Helpers
12/4/2018 • 2 minutes to read • Edit Online
The FileSystem class contains a series of helpers to find the application's cache and data directories and open files
inside of the app package.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
using Xamarin.Essentials;
To get the application's directory to store cache data. Cache data can be used for any data that needs to persist
longer than temporary data, but should not be data that is required to properly operate.
To get the application's top-level directory for any files that are not user data files. These files are backed up with
the operating system syncing framework. See Platform Implementation Specifics below.
The Flashlight class has the ability to turn on or off the device's camera flash to turn it into a flashlight.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
To access the Flashlight functionality the following platform specific setup is required.
Android
iOS
UWP
The Flashlight and Camera permissions are required and must be configured in the Android project. This can be
added in the following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.Flashlight)]
[assembly: UsesPermission(Android.Manifest.Permission.Camera)]
Or right click on the Android project and open the project's properties. Under Android Manifest find the
Required permissions: area and check the FLASHLIGHT and CAMERA permissions. This will automatically
update the AndroidManifest.xml file.
By adding these permissions Google Play will automatically filter out devices without specific hardware. You can
get around this by adding the following to your AssemblyInfo.cs file in your Android project:
Using Flashlight
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The flashlight can be turned on and off through the TurnOnAsync and TurnOffAsync methods:
try
{
// Turn On
await Flashlight.TurnOnAsync();
// Turn Off
await Flashlight.TurnOffAsync();
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to turn on/off flashlight
}
API
Flashlight source code
Flashlight API documentation
Xamarin.Essentials: Geocoding
3/14/2019 • 2 minutes to read • Edit Online
The Geocoding class provides APIs to geocode a placemark to a positional coordinates and reverse geocode
coordinates to a placemark.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
To access the Geocoding functionality the following platform specific setup is required.
Android
iOS
UWP
No additional setup required.
Using Geocoding
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
try
{
var address = "Microsoft Building 25 Redmond WA USA";
var locations = await Geocoding.GetLocationsAsync(address);
The altitude isn't always available. If it is not available, the Altitude property might be null or the value might be
zero. If the altitude is available, the value is in meters above sea level.
Console.WriteLine(geocodeAddress);
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Handle exception that may have occurred in geocoding
}
API
Geocoding source code
Geocoding API documentation
Xamarin.Essentials: Geolocation
4/19/2019 • 4 minutes to read • Edit Online
The Geolocation class provides APIs to retrieve the device's current geolocation coordinates.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
To access the Geolocation functionality, the following platform-specific setup is required:
Android
iOS
UWP
Coarse and Fine Location permissions are required and must be configured in the Android project. Additionally, if
your app targets Android 5.0 (API level 21) or higher, you must declare that your app uses the hardware features in
the manifest file. This can be added in the following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)]
[assembly: UsesFeature("android.hardware.location", Required = false)]
[assembly: UsesFeature("android.hardware.location.gps", Required = false)]
[assembly: UsesFeature("android.hardware.location.network", Required = false)]
Or right-click on the Android project and open the project's properties. Under Android Manifest find the
Required permissions: area and check the ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION
permissions. This will automatically update the AndroidManifest.xml file.
Using Geolocation
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Geolocation API will also prompt the user for permissions when necessary.
You can get the last known location of the device by calling the GetLastKnownLocationAsync method. This is often
faster then doing a full query, but can be less accurate.
try
{
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude:
{location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (FeatureNotEnabledException fneEx)
{
// Handle not enabled on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get location
}
The altitude isn't always available. If it is not available, the Altitude property might be null or the value might be
zero. If the altitude is available, the value is in meters above sea level.
To query the current device's location coordinates, the GetLocationAsync can be used. It is best to pass in a full
GeolocationRequest and CancellationToken since it may take some time to get the device's location.
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude:
{location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (FeatureNotEnabledException fneEx)
{
// Handle not enabled on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get location
}
Geolocation Accuracy
The following table outlines accuracy per platform:
Lowest
PLATFORM DISTANCE (IN METERS)
Android 500
iOS 3000
Low
PLATFORM DISTANCE (IN METERS)
Android 500
iOS 1000
Medium (Default)
PLATFORM DISTANCE (IN METERS)
iOS 100
UWP 30-500
High
PLATFORM DISTANCE (IN METERS)
Android 0 - 100
iOS 10
UWP <= 10
Best
PLATFORM DISTANCE (IN METERS)
Android 0 - 100
iOS ~0
UWP <= 10
Detecting Mock Locations
Some devices may return a mock location from the provider or by an application that provides mock locations. You
can detect this by using the IsFromMockProvider on any Location .
if (location != null)
{
if(location.IsFromMockProvider)
{
// location is from a mock provider
}
}
The Location constructor has latitude and longitude arguments in that order. Positive latitude values are north of
the equator, and positive longitude values are east of the Prime Meridian. Use the final argument to
CalculateDistance to specify miles or kilometers. The UnitConverters class also defines KilometersToMiles and
MilesToKilometers methods for converting between the two units.
API
Geolocation source code
Geolocation API documentation
Xamarin.Essentials: Gyroscope
12/4/2018 • 2 minutes to read • Edit Online
The Gyroscope class lets you monitor the device's gyroscope sensor which is the rotation around the device's
three primary axes.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Gyroscope
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Gyroscope functionality works by calling the Start and Stop methods to listen for changes to the gyroscope.
Any changes are sent back through the ReadingChanged event in rad/s. Here is sample usage:
public class GyroscopeTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;
public GyroscopeTest()
{
// Register for reading changes.
Gyroscope.ReadingChanged += Gyroscope_ReadingChanged;
}
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Default – Default rate suitable for screen orientation changes.
UI – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
API
Gyroscope source code
Gyroscope API documentation
Xamarin.Essentials: Launcher
4/2/2019 • 2 minutes to read • Edit Online
The Launcher class enables an application to open a URI by the system. This is often used when deep linking into
another application's custom URI schemes. If you are looking to open the browser to a website then you should
refer to the Browser API.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Launcher
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
To use the Launcher functionality call the OpenAsync method and pass in a string or Uri to open. Optionally, the
CanOpenAsync method can be used to check if the URI schema can be handled by an application on the device.
Platform Differences
Android
iOS
UWP
The Task returned from CanOpenAsync completes immediately.
API
Launcher source code
Launcher API documentation
Xamarin.Essentials: Magnetometer
12/4/2018 • 2 minutes to read • Edit Online
The Magnetometer class lets you monitor the device's magnetometer sensor which indicates the device's
orientation relative to Earth's magnetic field.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Magnetometer
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Magnetometer functionality works by calling the Start and Stop methods to listen for changes to the
magnetometer. Any changes are sent back through the ReadingChanged event. Here is sample usage:
public class MagnetometerTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;
public MagnetometerTest()
{
// Register for reading changes.
Magnetometer.ReadingChanged += Magnetometer_ReadingChanged;
}
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Default – Default rate suitable for screen orientation changes.
UI – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
API
Magnetometer source code
Magnetometer API documentation
Xamarin.Essentials: MainThread
12/4/2018 • 2 minutes to read • Edit Online
The MainThread class allows applications to run code on the main thread of execution, and to determine if a
particular block of code is currently running on the main thread.
Background
Most operating systems — including iOS, Android, and the Universal Windows Platform — use a single-
threading model for code involving the user interface. This model is necessary to properly serialize user-interface
events, including keystrokes and touch input. This thread is often called the main thread or the user-interface
thread or the UI thread. The disadvantage of this model is that all code that accesses user interface elements
must run on the application's main thread.
Applications sometimes need to use events that call the event handler on a secondary thread of execution. (The
Xamarin.Essentials classes Accelerometer , Compass , Gyroscope , Magnetometer , and OrientationSensor all might
return information on a secondary thread when used with faster speeds.) If the event handler needs to access
user-interface elements, it must run that code on the main thread. The MainThread class allows the application
to run this code on the main thread.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
using Xamarin.Essentials;
To run code on the main thread, call the static MainThread.BeginInvokeOnMainThread method. The argument is an
Action object, which is simply a method with no arguments and no return value:
MainThread.BeginInvokeOnMainThread(() =>
{
// Code to run on the main thread
});
It is also possible to define a separate method for the code that must run on the main thread:
void MyMainThreadCode()
{
// Code to run on the main thread
}
You can then run this method on the main thread by referencing it in the BeginInvokeOnMainThread method:
MainThread.BeginInvokeOnMainThread(MyMainThreadCode);
NOTE
Xamarin.Forms has a method called Device.BeginInvokeOnMainThread(Action) that does the same thing as
MainThread.BeginInvokeOnMainThread(Action) . While you can use either method in a Xamarin.Forms app, consider
whether or not the calling code has any other need for a dependency on Xamarin.Forms. If not,
MainThread.BeginInvokeOnMainThread(Action) is likely a better option.
if (MainThread.IsMainThread)
{
// Code to run if this is the main thread
}
else
{
// Code to run if this is a secondary thread
}
You might wonder if you should check if code is running on a secondary thread before calling
BeginInvokeOnMainThread , for example, like this:
if (MainThread.IsMainThread)
{
MyMainThreadCode();
}
else
{
MainThread.BeginInvokeOnMainThread(MyMainThreadCode);
}
You might suspect that this check might improve performance if the block of code is already running on the main
thread.
However, this check is not necessary. The platform implementations of BeginInvokeOnMainThread themselves
check if the call is made on the main thread. There is very little performance penalty if you call
BeginInvokeOnMainThread when it's not really necessary.
API
MainThread source code
MainThread API documentation
Xamarin.Essentials: Map
4/2/2019 • 2 minutes to read • Edit Online
The Map class enables an application to open the installed map application to a specific location or placemark.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Map
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Map functionality works by calling the OpenAsync method with the Location or Placemark to open with
optional MapLaunchOptions .
Extension Methods
If you already have a reference to a Location or Placemark , you can use the built-in extension method
OpenMapAsync with optional MapLaunchOptions :
Directions Mode
If you call OpenMapAsync without any MapLaunchOptions , the map will launch to the location specified. Optionally,
you can have a navigation route calculated from the device's current position. This is accomplished by setting the
NavigationMode on the MapLaunchOptions :
Platform Differences
Android
iOS
UWP
NavigationMode supports Bicycling, Driving, and Walking.
API
Map source code
Map API documentation
Related Video
Find more of The Xamarin Show on Channel 9 and YouTube.
Xamarin.Essentials: Browser
4/2/2019 • 2 minutes to read • Edit Online
The Browser class enables an application to open a web link in the optimized system preferred browser or the
external browser.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Browser
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Browser functionality works by calling the OpenAsync method with the Uri and BrowserLaunchMode .
This method returns after the browser was launched and not necessarily closed by the user. The bool result
indicates whether the launching was successful or not.
Customization
When using the system preferred browser there are several customization options available for iOS and Android.
This includes a TitleMode (Android only), and preferred color options for the Toolbar (iOS and Android) and
Controls (iOS only) that appear.
System Preferred
Chrome Custom Tabs will attempted to be used load the Uri and keep navigation awareness.
External
An Intent will be used to request the Uri be opened through the systems normal browser.
API
Browser source code
Browser API documentation
Related Video
The OrientationSensor class lets you monitor the orientation of a device in three dimensional space.
NOTE
This class is for determining the orientation of a device in 3D space. If you need to determine if the device's video display is in
portrait or landscape mode, use the Orientation property of the ScreenMetrics object available from the
DeviceDisplay class.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using OrientationSensor
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The OrientationSensor is enabled by calling the Start method to monitor changes to the device's orientation, and
disabled by calling the Stop method. Any changes are sent back through the ReadingChanged event. Here is a
sample usage:
public class OrientationSensorTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;
public OrientationSensorTest()
{
// Register for reading changes, be sure to unsubscribe when finished
OrientationSensor.ReadingChanged += OrientationSensor_ReadingChanged;
}
OrientationSensor readings are reported back in the form of a Quaternion that describes the orientation of the
device based on two 3D coordinate systems:
The device (generally a phone or tablet) has a 3D coordinate system with the following axes:
The positive X axis points to the right of the display in portrait mode.
The positive Y axis points to the top of the device in portrait mode.
The positive Z axis points out of the screen.
The 3D coordinate system of the Earth has the following axes:
The positive X axis is tangent to the surface of the Earth and points east.
The positive Y axis is also tangent to the surface of the Earth and points north.
The positive Z axis is perpendicular to the surface of the Earth and points up.
The Quaternion describes the rotation of the device's coordinate system relative to the Earth's coordinate system.
A Quaternion value is very closely related to rotation around an axis. If an axis of rotation is the normalized vector
(ax, ay, az), and the rotation angle is Θ, then the (X, Y, Z, W ) components of the quaternion are:
(ax·sin(Θ/2), ay·sin(Θ/2), az·sin(Θ/2), cos(Θ/2))
These are right-hand coordinate systems, so with the thumb of the right hand pointed in the positive direction of
the rotation axis, the curve of the fingers indicate the direction of rotation for positive angles.
Examples:
When the device lies flat on a table with its screen facing up, with the top of the device (in portrait mode)
pointing north, the two coordinate systems are aligned. The Quaternion value represents the identity
quaternion (0, 0, 0, 1). All rotations can be analyzed relative to this position.
When the device lies flat on a table with its screen facing up, and the top of the device (in portrait mode)
pointing west, the Quaternion value is (0, 0, 0.707, 0.707). The device has been rotated 90 degrees around
the Z axis of the Earth.
When the device is held upright so that the top (in portrait mode) points towards the sky, and the back of
the device faces north, the device has been rotated 90 degrees around the X axis. The Quaternion value is
(0.707, 0, 0, 0.707).
If the device is positioned so its left edge is on a table, and the top points north, the device has been rotated
–90 degrees around the Y axis (or 90 degrees around the negative Y axis). The Quaternion value is (0, -
0.707, 0, 0.707).
Sensor Speed
Fastest – Get the sensor data as fast as possible (not guaranteed to return on UI thread).
Game – Rate suitable for games (not guaranteed to return on UI thread).
Default – Default rate suitable for screen orientation changes.
UI – Rate suitable for general user interface.
If your event handler is not guaranteed to run on the UI thread, and if the event handler needs to access user-
interface elements, use the MainThread.BeginInvokeOnMainThread method to run that code on the UI thread.
API
OrientationSensor source code
OrientationSensor API documentation
Xamarin.Essentials: Phone Dialer
12/4/2018 • 2 minutes to read • Edit Online
The PhoneDialer class enables an application to open a phone number in the dialer.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
using Xamarin.Essentials;
The Phone Dialer functionality works by calling the Open method with a phone number to open the dialer with.
When Open is requested the API will automatically attempt to format the number based on the country code if
specified.
API
Phone Dialer source code
Phone Dialer API documentation
Xamarin.Essentials: Platform Extensions
3/21/2019 • 2 minutes to read • Edit Online
Xamarin.Essentials provides several platform extension methods when having to work with platform types such as
Rect, Size, and Point. This means that you can convert between the System version of these types for their iOS,
Android, and UWP specific types.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
using Xamarin.Essentials;
All platform extensions can only be called from the iOS, Android, or UWP project.
Point
// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();
Size
// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();
Rectangle
// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();
API
Converters source code
Point Converters API documentation
Rectangle Converters API documentation
Size Converters API documentation
Xamarin.Essentials: Preferences
1/15/2019 • 2 minutes to read • Edit Online
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Preferences
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
Preferences.Set("my_key", "my_value");
Preferences.Remove("my_key");
Preferences.Clear();
In addition to these methods each take in an optional sharedName that can be used to create additional containers
for preference. Read the platform implementation specifics below.
Persistence
Uninstalling the application will cause all Preferences to be removed. There is one exception to this, which for apps
that target and run on Android 6.0 (API level 23) or later that are using Auto Backup. This feature is on by default
and preserves app data including Shared Preferences, which is what the Preferences API utilizes. You can
disable this by following Google's documentation.
Limitations
When storing a string, this API is intended to store small amounts of text. Performance may be subpar if you try to
use it to store large amounts of text.
API
Preferences source code
Preferences API documentation
Related Video
Find more of The Xamarin Show on Channel 9 and YouTube.
Xamarin.Essentials: Secure Storage
4/19/2019 • 3 minutes to read • Edit Online
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
To access the SecureStorage functionality, the following platform-specific setup is required:
Android
iOS
UWP
TIP
Auto Backup for Apps is a feature of Android 6.0 (API level 23) and later that backs up user's app data (shared preferences,
files in the app's internal storage, and other specific files). Data is restored when an app is re-installed or installed on a new
device. This can impact SecureStorage which utilizes share preferences that are backed up and can not be decrypted when
the restore occurs. Xamarin.Essentials automatically handles this case by removing the key so it can be reset, but you can
take an additional step by disabling Auto Backup.
Selective Backup
Auto Backup can be configured to disable specific content from backing up. You can create a custom rule set to
exclude SecureStore items from being backed up.
1. Set the android:fullBackupContent attribute in your AndroidManifest.xml:
<application ...
android:fullBackupContent="@xml/auto_backup_rules">
</application>
2. Create a new XML file named auto_backup_rules.xml in the Resources/xml directory with the build
action of AndroidResource. Then set the following content that includes all shared preferences except for
SecureStorage :
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="${applicationId}.xamarinessentials.xml"/>
</full-backup-content>
using Xamarin.Essentials;
try
{
await SecureStorage.SetAsync("oauth_token", "secret-oauth-token-value");
}
catch (Exception ex)
{
// Possible that device doesn't support secure storage on device.
}
try
{
var oauthToken = await SecureStorage.GetAsync("oauth_token");
}
catch (Exception ex)
{
// Possible that device doesn't support secure storage on device.
}
NOTE
If there is no value associated with the requested key, GetAsync will return null .
SecureStorage.Remove("oauth_token");
SecureStorage.RemoveAll();
Limitations
This API is intended to store small amounts of text. Performance may be slow if you try to use it to store large
amounts of text.
API
SecureStorage source code
SecureStorage API documentation
Related Video
The Share class enables an application to share data such as text and web links to other applications on the device.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Share
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Share functionality works by calling the RequestAsync method with a data request payload that includes
information to share to other applications. Text and Uri can be mixed and each platform will handle filtering based
on content.
User interface to share to external application that appears when request is made:
Platform Differences
Android
iOS
UWP
Subject property is used for desired subject of a message.
Files
Sharing files is available as an experimental preview in Xamarin.Essentials version 1.1.0. This features enables an
app to share files to other applications on the device. To enable this feature set the following property in your app's
startup code:
ExperimentalFeatures.Enable(ExperimentalFeatures.ShareFileRequest);
After the feature enabled any file can be shared. Xamarin.Essentials will automatically detect the file type (MIME )
and request a share. Each platform may only support specific file extensions.
Here is a sample of writing text to disk and sharing it to other apps:
var fn = "Attachment.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
API
Share source code
Share API documentation
Related Video
Find more of The Xamarin Show on Channel 9 and YouTube.
Xamarin.Essentials: SMS
12/31/2018 • 2 minutes to read • Edit Online
The Sms class enables an application to open the default SMS application with a specified message to send to a
recipient.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Sms
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The SMS functionality works by calling the ComposeAsync method an SmsMessage that contains the message's
recipient and the body of the message, both of which are optional.
API
Sms source code
Sms API documentation
Xamarin.Essentials: Text-to-Speech
4/5/2019 • 2 minutes to read • Edit Online
The TextToSpeech class enables an application to utilize the built-in text-to-speech engines to speak back text
from the device and also to query available languages that the engine can support.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
Using Text-to-Speech
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
Text-to-Speech works by calling the SpeakAsync method with text and optional parameters, and returns after the
utterance has finished.
}, TaskScheduler.FromCurrentSynchronizationContext());
}
This method takes in an optional CancellationToken to stop the utterance once it starts.
CancellationTokenSource cts;
public async Task SpeakNowDefaultSettings()
{
cts = new CancellationTokenSource();
await TextToSpeech.SpeakAsync("Hello World", cancelToken: cts.Token);
cts.Cancel();
}
Text-to-Speech will automatically queue speech requests from the same thread.
Speech Settings
For more control over how the audio is spoken back with SpeechOptions that allows setting the volume, pitch, and
locale.
Pitch 0 2.0
Volume 0 1.0
Speech Locales
Each platform supports different locales, to speak back text in different languages and accents. Platforms have
different codes and ways of specifying the locale, which is why Xamarin.Essentials provides a cross-platform
Locale class and a way to query them with GetLocalesAsync .
public async Task SpeakNow()
{
var locales = await TextToSpeech.GetLocalesAsync();
Limitations
Utterance queue is not guaranteed if called across multiple threads.
Background audio playback is not officially supported.
API
TextToSpeech source code
TextToSpeech API documentation
Xamarin.Essentials: Unit Converters
3/18/2019 • 2 minutes to read • Edit Online
The UnitConverters class provides several unit converters to help developers when using Xamarin.Essentials.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
using Xamarin.Essentials;
All unit converters are available by using the static UnitConverters class in Xamarin.Essentials. For instance you
can easily convert Fahrenheit to Celsius.
The VersionTracking class lets you check the applications version and build numbers along with seeing additional
information such as if it is the first time the application launched ever or for the current version, get the previous
build information, and more.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
using Xamarin.Essentials;
The first time you use the VersionTracking class it will start tracking the current version. You must call Track
early only in your application each time it is loaded to ensure the current version information is tracked:
VersionTracking.Track();
API
Version Tracking source code
Version Tracking API documentation
Xamarin.Essentials: Vibration
12/4/2018 • 2 minutes to read • Edit Online
The Vibration class lets you start and stop the vibrate functionality for a desired amount of time.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly
installed and set up in your projects.
To access the Vibration functionality the following platform specific setup is required.
Android
iOS
UWP
The Vibrate permission is required and must be configured in the Android project. This can be added in the
following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]
Or right click on the Android project and open the project's properties. Under Android Manifest find the
Required permissions: area and check the VIBRATE permission. This will automatically update the
AndroidManifest.xml file.
Using Vibration
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Vibration functionality can be requested for a set amount of time or the default of 500 milliseconds.
try
{
// Use default vibration length
Vibration.Vibrate();
try
{
Vibration.Cancel();
}
catch (FeatureNotSupportedException ex)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
Platform Differences
Android
iOS
UWP
No platform differences.
API
Vibration source code
Vibration API documentation
Xamarin.Essentials: Troubleshooting
4/2/2019 • 2 minutes to read • Edit Online
NU1107: Version conflict detected for Xamarin.Android.Support.Compat. Reference the package directly from the
project to resolve this issue.
MyApp -> Xamarin.Essentials 1.1.0 -> Xamarin.Android.Support.CustomTabs 28.0.0.1 ->
Xamarin.Android.Support.Compat (= 28.0.0.1)
MyApp -> Xamarin.Forms 3.1.0.583944 -> Xamarin.Android.Support.v4 25.4.0.2 -> Xamarin.Android.Support.Compat
(= 25.4.0.2).
The problem is mismatched dependencies for the two NuGets. This can be resolved by manually adding a specific
version of the dependency (in this case Xamarin.Android.Support.Compat) that can support both.
To do this, add the NuGet that is the source of the conflict manually, and use the Version list to select a specific
version. Currently version 28.0.0.1 of the Xamarin.Android.Support.Compat & Xamarin.Android.Support.Core.Util
NuGet will resolve this error.
Refer to this blog post for more information and a video on how to resolve the issue.
If run into any issues or find a bug please report it on the Xamarin.Essentials GitHub repository.
Data & Cloud Services
4/12/2018 • 2 minutes to read • Edit Online
Xamarin.Forms applications can consume web services implemented using a wide variety of technologies, and this
guide will examine how to do this.
For an introduction to cross-platform web service consumption on the Xamarin platform, see Introduction to Web
Services.
FOLDER PURPOSE
Views Contains the pages for the application. This usually consists of
the TodoListPage and TodoItemPage classes, and any
additional classes used for authentication purposes.
The PCL project for each application also consists of a number of important files:
FILE PURPOSE
Todo.cs The App class that is responsible for instantiating both the
first page that will be displayed by the application on each
platform, and the TodoItemManager class that is used to
invoke web service operations.
Viewing Pages
The majority of the sample applications contain at least two pages:
TodoListPage – this page displays a list of TodoItem instances, and a tick icon if the TodoItem.Done property is
true . Clicking on an item navigates to the TodoItemPage . In addition, new items can be created by clicking on
the + symbol.
TodoItemPage – this page displays the details for the selected TodoItem , and allows it to be edited, saved,
deleted, and spoken.
In addition, some sample applications contain additional pages that are used to manage the user authentication
process.
Modeling the Data
Each sample application uses the TodoItem class to model the data that is displayed and sent to the web service
for storage. The following code example shows the TodoItem class:
The ID property is used to uniquely identify each TodoItem instance, and is used by each web service to identify
data to be updated or deleted.
Invoking Web Service Operations
Web service operations are accessed through the TodoItemManager class, and an instance of the class can be
accessed through the App.TodoManager property. The TodoItemManager class provides the following methods to
invoke web service operations:
GetTasksAsync – this method is used to populate the ListView control on the TodoListPage with the
TodoItem instances retrieved from the web service.
SaveTaskAsync – this method is used to create or update a TodoItem instance on the web service.
DeleteTaskAsync – this method is used to delete a TodoItem instance on the web service.
In addition, some sample applications contain additional methods in the TodoItemManager class, which are used to
manage the user authentication process.
Rather than invoke the web service operations directly, the TodoItemManager methods invoke methods on a
dependent class that is injected into the TodoItemManager constructor. For example, one sample application injects
the RestService class into the TodoItemManager constructor to provide the implementation that uses REST APIs to
access data.
Translating Text to Speech
The majority of the sample applications contain text-to-speech (TTS ) functionality to speak the values of the
TodoItem.Name and TodoItem.Notes properties. This is accomplished by the OnSpeakActivated event handler in the
TodoItemPage class, as shown in the following code example:
This method simply invokes the Speak method that is implemented by a platform-specific Speech class. Each
Speech class implements the ITextToSpeech interface, and platform -specific startup code creates an instance of
the Speech class that can be accessed through the App.Speech property.
Summary
This topic provided a walkthrough of the Xamarin.Forms sample application that's used to demonstrate how to
communicate with different web services. While each web service uses a separate sample application, they are all
based on the same user-interface and business logic as described above - only the web service data storage
mechanism is different.
Related Links
ASMX version (sample)
WCF version (sample)
REST version (sample)
Azure version (sample)
Consuming Web Services
4/12/2018 • 2 minutes to read • Edit Online
_This guide demonstrates how to communicate with different web services to provide create, read, update, and
delete (CRUD ) functionality to a Xamarin.Forms application. Topics covered include communicating with ASMX
services, WCF services, REST services, and Azure Mobile Apps.
Related Links
Introduction to Web Services
Async Support Overview
Consuming an ASP.NET Web Service (ASMX)
4/17/2019 • 6 minutes to read • Edit Online
For more information about the data model used in the application, see Modeling the data.
public SoapService ()
{
todoService = new ASMXService.TodoService ();
todoService.Url = Constants.SoapUrl;
...
}
}
This method creates a new ASMService.TodoItem instance, and sets each property to the identical property from
the TodoItem instance.
Similarly, when data is retrieved from the web service, it must be converted from the proxy generated TodoItem
type to a TodoItem instance. This is accomplished with the FromASMXServiceTodoItem method, as shown in the
following code example:
This method retrieves the data from the proxy generated TodoItem type and sets it in the newly created TodoItem
instance.
Retrieve data
The ISoapService interface expects the RefreshDataAsync method to return a Task with the item collection.
However, the TodoService.GetTodoItemsAsync method returns void. To satisfy the interface pattern, you must call
GetTodoItemsAsync , wait for the GetTodoItemsCompleted event to fire, and populate the collection. This allows you to
return a valid collection to the UI.
The example below creates a new TaskCompletionSource , begins the async call in the RefreshDataAsync method,
and awaits the Task provided by the TaskCompletionSource . When the TodoService_GetTodoItemsCompleted event
handler is invoked it populates the Items collection and updates the TaskCompletionSource :
public class SoapService : ISoapService
{
TaskCompletionSource<bool> getRequestComplete = null;
...
public SoapService()
{
...
todoService.GetTodoItemsCompleted += TodoService_GetTodoItemsCompleted;
}
...
}
For more information, see Asynchronous Programming Model and TPL and Traditional .NET Framework
Asynchronous Programming.
Create or edit data
When you create or edit data, you must implement the ISoapService.SaveTodoItemAsync method. This method
detects whether the TodoItem is a new or updated item and calls the appropriate method on the todoService
object. The CreateTodoItemCompleted and EditTodoItemCompleted event handlers should also be implemented so
you know when the todoService has received a response from the ASMX service (these can be combined into a
single handler because they perform the same operation). The following example demonstrates the interface and
event handler implementations, as well as the TaskCompletionSource object used to operate asynchronously:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> saveRequestComplete = null;
...
public SoapService()
{
...
todoService.CreateTodoItemCompleted += TodoService_SaveTodoItemCompleted;
todoService.EditTodoItemCompleted += TodoService_SaveTodoItemCompleted;
}
...
}
Delete data
Deleting data requires a similar implementation. Define a TaskCompletionSource , implement an event handler, and
the ISoapService.DeleteTodoItemAsync method:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> deleteRequestComplete = null;
...
public SoapService()
{
...
todoService.DeleteTodoItemCompleted += TodoService_DeleteTodoItemCompleted;
}
...
}
Related links
TodoASMX (sample)
IAsyncResult
Consume a Windows Communication Foundation
(WCF) Web Service
4/5/2019 • 12 minutes to read • Edit Online
IMPORTANT
The Xamarin platform support for WCF is limited to text-encoded SOAP messages over HTTP/HTTPS using the
BasicHttpBinding class.
WCF support requires the use of tools only available in a Windows environment to generate the proxy and host the
TodoWCFService. Building and testing the iOS app will require deploying the TodoWCFService on a Windows computer, or as
an Azure web service.
Xamarin Forms native apps typically share code with a .NET Standard Class Library. However, .NET Core does not currently
support WCF so the shared project must be a legacy Portable Class Library. For information about WCF support in .NET
Core, see Choosing between .NET Core and .NET Framework for server apps.
The sample application solution includes a WCF service which can be run locally, and is shown in the following
screenshot:
NOTE
In iOS 9 and greater, App Transport Security (ATS) enforces secure connections between internet resources (such as the app's
back-end server) and the app, thereby preventing accidental disclosure of sensitive information. Since ATS is enabled by
default in apps built for iOS 9, all connections will be subject to ATS security requirements. If connections do not meet these
requirements, they will fail with an exception.
ATS can be opted out of if it is not possible to use the HTTPS protocol and secure communication for internet resources.
This can be achieved by updating the app's Info.plist file. For more information see App Transport Security.
For more information about the data model used in the application, see Modeling the data.
A proxy must be generated to consume a WCF service, which allows the application to connect to the service. The
proxy is constructed by consuming service metadata that define the methods and associated service configuration.
This metadata is exposed in the form of a Web Services Description Language (WSDL ) document that is generated
by the web service. The proxy can be built by using the Microsoft WCF Web Service Reference Provider in Visual
Studio 2017 to add a service reference for the web service to a .NET Standard library. An alternative to creating the
proxy using the Microsoft WCF Web Service Reference Provider in Visual Studio 2017 is to use the ServiceModel
Metadata Utility Tool (svcutil.exe). For more information, see ServiceModel Metadata Utility Tool (Svcutil.exe).
The generated proxy classes provide methods for consuming the web services that use the Asynchronous
Programming Model (APM ) design pattern. In this pattern, an asynchronous operation is implemented as two
methods named BeginOperationName and EndOperationName, which begin and end the asynchronous
operation.
The BeginOperationName method begins the asynchronous operation and returns an object that implements the
IAsyncResult interface. After calling BeginOperationName, an application can continue executing instructions on
the calling thread, while the asynchronous operation takes place on a thread pool thread.
For each call to BeginOperationName, the application should also call EndOperationName to get the results of the
operation. The return value of EndOperationName is the same type returned by the synchronous web service
method. For example, the EndGetTodoItems method returns a collection of TodoItem instances. The
EndOperationName method also includes an IAsyncResult parameter that should be set to the instance returned
by the corresponding call to the BeginOperationName method.
The Task Parallel Library (TPL ) can simplify the process of consuming an APM begin/end method pair by
encapsulating the asynchronous operations in the same Task object. This encapsulation is provided by multiple
overloads of the TaskFactory.FromAsync method.
For more information about APM see Asynchronous Programming Model and TPL and Traditional .NET
Framework Asynchronous Programming on MSDN.
Create the TodoServiceClient object
The generated proxy class provides the TodoServiceClient class, which is used to communicate with the WCF
service over HTTP. It provides functionality for invoking web service methods as asynchronous operations from a
URI identified service instance. For more information about asynchronous operations, see Async Support
Overview.
The TodoServiceClient instance is declared at the class-level so that the object lives for as long as the application
needs to consume the WCF service, as shown in the following code example:
public SoapService ()
{
todoService = new TodoServiceClient (
new BasicHttpBinding (),
new EndpointAddress (Constants.SoapUrl));
}
...
}
The TodoServiceClient instance is configured with binding information and an endpoint address. A binding is used
to specify the transport, encoding, and protocol details required for applications and services to communicate with
each other. The BasicHttpBinding specifies that text-encoded SOAP messages will be sent over the HTTP transport
protocol. Specifying an endpoint address enables the application to connect to different instances of the WCF
service, provided that there are multiple published instances.
For more information about configuring the service reference, see Configuring the Service Reference.
Create data transfer objects
The sample application uses the TodoItem class to model data. To store a TodoItem item in the web service it must
first be converted to the proxy generated TodoItem type. This is accomplished by the ToWCFServiceTodoItem
method, as shown in the following code example:
This method simply creates a new TodoWCFService.TodoItem instance, and sets each property to the identical
property from the TodoItem instance.
Similarly, when data is retrieved from the web service, it must be converted from the proxy generated TodoItem
type to a TodoItem instance. This is accomplished with the FromWCFServiceTodoItem method, as shown in the
following code example:
This method simply retrieves the data from the proxy generated TodoItem type and sets it in the newly created
TodoItem instance.
Retrieve data
The TodoServiceClient.BeginGetTodoItems and TodoServiceClient.EndGetTodoItems methods are used to call the
GetTodoItems operation provided by the web service. These asynchronous methods are encapsulated in a Task
object, as shown in the following code example:
public async Task<List<TodoItem>> RefreshDataAsync ()
{
...
var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
todoService.BeginGetTodoItems,
todoService.EndGetTodoItems,
null,
TaskCreationOptions.None);
The Task.Factory.FromAsync method creates a Task that executes the TodoServiceClient.EndGetTodoItems method
once the TodoServiceClient.BeginGetTodoItems method completes, with the null parameter indicating that no data
is being passed into the BeginGetTodoItems delegate. Finally, the value of the TaskCreationOptions enumeration
specifies that the default behavior for the creation and execution of tasks should be used.
The TodoServiceClient.EndGetTodoItems method returns an ObservableCollection of TodoWCFService.TodoItem
instances, which is then converted to a List of TodoItem instances for display.
Create data
The TodoServiceClient.BeginCreateTodoItem and TodoServiceClient.EndCreateTodoItem methods are used to call the
CreateTodoItem operation provided by the web service. These asynchronous methods are encapsulated in a Task
object, as shown in the following code example:
The Task.Factory.FromAsync method creates a Task that executes the TodoServiceClient.EndEditTodoItem method
once the TodoServiceClient.BeginCreateTodoItem method completes, with the todoItem parameter being the data
that's passed into the BeginEditTodoItem delegate to specify the TodoItem to be updated by the web service.
Finally, the value of the TaskCreationOptions enumeration specifies that the default behavior for the creation and
execution of tasks should be used.
The web service throws a FaultException if it fails to locate or update the TodoItem , which is handled by the
application.
Delete data
The TodoServiceClient.BeginDeleteTodoItem and TodoServiceClient.EndDeleteTodoItem methods are used to call the
DeleteTodoItem operation provided by the web service. These asynchronous methods are encapsulated in a Task
object, as shown in the following code example:
2. Configure IIS Express to Accept Remote connections. You can configure IIS Express by editing the
configuration file for IIS Express at [solution directory].vs\config\applicationhost.config. Find the
site element with the name TodoWCFService . It should look similar to the following XML:
You will need to add two binding elements to open up port 49393 to outside traffic and the Android
emulator. The binding uses a [IP address]:[port]:[hostname] format that specifies how IIS Express will
respond to requests. External requests will have hostnames that must be specified as a binding . Add the
following XML to the bindings element, replacing the IP address with your own IP address:
After your changes the bindings element should look like the following:
IMPORTANT
By default, IIS Express will not accept connections from external sources for security reasons. To enable connections
from remote devices you must run IIS Express with Administrative permissions. The easiest way to do this is to run
Visual Studio 2017 with Administrative permissions. This will launch IIS Express with Administrative permissions when
running the TodoWCFService.
With these steps complete, you should be able to run the TodoWCFService and connect from other devices
on your subnet. You can test this by running your application and visiting
http://localhost:49393/TodoService.svc . If you get a Bad Request error when visiting that URL, your
bindings may be incorrect in the IIS Express configuration (the request is reaching IIS Express but is being
rejected). If you get a different error it may be that your application is not running or your firewall is
incorrectly configured.
To allow IIS Express to keep running and serving the service, turn off the Edit and Continue option in
Project Properties > Web > Debuggers.
3. Customize the endpoint devices use to access the service. This step involves configuring the client
application, running on a physical or emulated device, to access the WCF service.
The Android emulator utilizes an internal proxy that prevents the emulator from directly accessing the host
machine's localhost address. Instead, the address 10.0.2.2 on the emulator is routed to localhost on the
host machine through an internal proxy. These proxied requests will have 127.0.0.1 as the hostname in the
request header, which is why you created the IIS Express binding for this hostname in the steps above.
The iOS Simulator runs on a Mac build host, even if you are using the Remoted iOS Simulator for
Windows. Network requests from the simulator will have your workstation IP on the local network as the
hostname (in this example it's 192.168.1.143 , but your actual IP address will likely be different). This is why
you created the IIS Express binding for this hostname in the steps above.
Ensure the SoapUrl property in the Constants.cs file in the TodoWCF (Portable) project have values that
are correct for your network:
if (Device.RuntimePlatform == Device.Android)
{
defaultUrl = "http://10.0.2.2:49393/TodoService.svc";
}
else if (Device.RuntimePlatform == Device.iOS)
{
defaultUrl = "http://192.168.1.143:49393/TodoService.svc";
}
return defaultUrl;
}
}
Once you have configured the Constants.cs with the appropriate endpoints, you should be able to connect
to the TodoWCFService running on your Windows 10 workstation from physical or virtual devices.
Related links
TodoWCF (sample)
How to: Create a Windows Communication Foundation Client
ServiceModel Metadata Utility Tool (svcutil.exe)
Consuming a RESTful Web Service
3/26/2019 • 7 minutes to read • Edit Online
The majority of the URIs include the ID in the path. For example, to delete the TodoItem whose ID is
TodoItem
6bb8a868-dba1-4f1a-93b7-24ebce87e243 , the client sends a DELETE request to
http://hostname/api/todoitems/6bb8a868-dba1-4f1a-93b7-24ebce87e243 . For more information about the data model
used in the sample application, see Modeling the data.
When the Web API framework receives a request it routes the request to an action. These actions are simply
public methods in the TodoItemsController class. The framework uses a routing table to determine which action to
invoke in response to a request, which is shown in the following code example:
config.Routes.MapHttpRoute(
name: "TodoItemsApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { controller="todoitems", id = RouteParameter.Optional }
);
The routing table contains a route template, and when the Web API framework receives an HTTP request, it tries
to match the URI against the route template in the routing table. If a matching route cannot be found the client
receives a 404 (not found) error. If a matching route is found, Web API selects the controller and the action as
follows:
To find the controller, Web API adds "controller" to the value of the {controller } variable.
To find the action, Web API looks at the HTTP method and looks at controller actions that are decorated with
the same HTTP method as an attribute.
The {id } placeholder variable is mapped to an action parameter.
The REST service uses basic authentication. For more information see Authenticating a RESTful web service. For
more information about ASP.NET Web API routing, see Routing in ASP.NET Web API on the ASP.NET website.
For more information about building the REST service using ASP.NET Core, see Creating Backend Services for
Native Mobile Applications.
The HttpClient class is used to send and receive requests over HTTP. It provides functionality for sending HTTP
requests and receiving HTTP responses from a URI identified resource. Each request is sent as an asynchronous
operation. For more information about asynchronous operations, see Async Support Overview.
The HttpResponseMessage class represents an HTTP response message received from the web service after an
HTTP request has been made. It contains information about the response, including the status code, headers, and
any body. The HttpContent class represents the HTTP body and content headers, such as Content-Type and
Content-Encoding . The content can be read using any of the ReadAs methods, such as ReadAsStringAsync and
ReadAsByteArrayAsync , depending upon the format of the data.
public RestService ()
{
_client = new HttpClient ();
}
...
}
Retrieving Data
The HttpClient.GetAsync method is used to send the GET request to the web service specified by the URI, and
then receive the response from the web service, as shown in the following code example:
public async Task<List<TodoItem>> RefreshDataAsync ()
{
...
var uri = new Uri (string.Format (Constants.TodoItemsUrl, string.Empty));
...
var response = await _client.GetAsync (uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync ();
Items = JsonConvert.DeserializeObject <List<TodoItem>> (content);
}
...
}
The REST service sends an HTTP status code in the HttpResponseMessage.IsSuccessStatusCode property, to indicate
whether the HTTP request succeeded or failed. For this operation the REST service sends HTTP status code 200
(OK) in the response, which indicates that the request succeeded and that the requested information is in the
response.
If the HTTP operation was successful, the content of the response is read, for display. The
HttpResponseMessage.Content property represents the content of the HTTP response, and the
HttpContent.ReadAsStringAsync method asynchronously writes the HTTP content to a string. This content is then
converted from JSON to a List of TodoItem instances.
Creating Data
The HttpClient.PostAsync method is used to send the POST request to the web service specified by the URI, and
then to receive the response from the web service, as shown in the following code example:
...
var json = JsonConvert.SerializeObject (item);
var content = new StringContent (json, Encoding.UTF8, "application/json");
if (response.IsSuccessStatusCode)
{
Debug.WriteLine (@"\tTodoItem successfully saved.");
}
...
}
The TodoItem instance is converted to a JSON payload for sending to the web service. This payload is then
embedded in the body of the HTTP content that will be sent to the web service before the request is made with
the PostAsync method.
The REST service sends an HTTP status code in the HttpResponseMessage.IsSuccessStatusCode property, to indicate
whether the HTTP request succeeded or failed. The common responses for this operation are:
201 (CREATED ) – the request resulted in a new resource being created before the response was sent.
400 (BAD REQUEST) – the request is not understood by the server.
409 (CONFLICT) – the request could not be carried out because of a conflict on the server.
Updating Data
The HttpClient.PutAsync method is used to send the PUT request to the web service specified by the URI, and
then receive the response from the web service, as shown in the following code example:
The operation of the PutAsync method is identical to the PostAsync method that's used for creating data in the
web service. However, the possible responses sent from the web service differ.
The REST service sends an HTTP status code in the HttpResponseMessage.IsSuccessStatusCode property, to indicate
whether the HTTP request succeeded or failed. The common responses for this operation are:
204 (NO CONTENT) – the request has been successfully processed and the response is intentionally blank.
400 (BAD REQUEST) – the request is not understood by the server.
404 (NOT FOUND ) – the requested resource does not exist on the server.
Deleting Data
The HttpClient.DeleteAsync method is used to send the DELETE request to the web service specified by the URI,
and then receive the response from the web service, as shown in the following code example:
The REST service sends an HTTP status code in the HttpResponseMessage.IsSuccessStatusCode property, to indicate
whether the HTTP request succeeded or failed. The common responses for this operation are:
204 (NO CONTENT) – the request has been successfully processed and the response is intentionally blank.
400 (BAD REQUEST) – the request is not understood by the server.
404 (NOT FOUND ) – the requested resource does not exist on the server.
Related Links
Creating Backend Services for Native Mobile Applications
TodoREST (sample)
HttpClient
Consuming an Azure Mobile App
3/8/2019 • 4 minutes to read • Edit Online
NOTE
Starting on June 30, all new Azure Mobile Apps will be created with TLS 1.2 by default. In addition, it's also recommended
that existing Azure Mobile Apps be reconfigured to use TLS 1.2. For information on how to enforce TLS 1.2 in an Azure
Mobile App, see Enforce TLS versions. For information on how to configure Xamarin projects to use TLS 1.2, see Transport
Layer Security (TLS) 1.2.
For information on how to create an Azure Mobile Apps instance that can be consumed by Xamarin.Forms, see
Create a Xamarin.Forms app. After following these instructions, the downloadable sample application can be
configured to consume the Azure Mobile Apps instance by setting the Constants.ApplicationURL to the URL of
the Azure Mobile Apps instance. Then, when the sample application is run it will connect to the Azure Mobile
Apps instance, as shown in the following screenshot:
Access to Azure Mobile Apps is through the Azure Mobile Client SDK, and all connections from the
Xamarin.Forms sample application to Azure are made over HTTPS.
NOTE
In iOS 9 and greater, App Transport Security (ATS) enforces secure connections between internet resources (such as the
app's back-end server) and the app, thereby preventing accidental disclosure of sensitive information. Since ATS is enabled
by default in apps built for iOS 9, all connections will be subject to ATS security requirements. If connections do not meet
these requirements, they will fail with an exception. ATS can be opted out of if it is not possible to use the HTTPS protocol
and secure communication for internet resources. This can be achieved by updating the app's Info.plist file. For more
information see App Transport Security.
IMobileServiceTable<TodoItem> todoTable;
MobileServiceClient client;
public TodoItemManager ()
{
client = new MobileServiceClient (Constants.ApplicationURL);
todoTable = client.GetTable<TodoItem> ();
}
When the MobileServiceClient instance is created, an application URL must be specified to identify the Azure
Mobile Apps instance. This value can be obtained from the dashboard for the mobile app in the Microsoft Azure
Portal.
A reference to the TodoItem table stored in the Azure Mobile Apps instance must be obtained before operations
can be performed on that table. This is achieved by calling the GetTable method on the MobileServiceClient
instance, which returns a IMobileServiceTable<TodoItem> reference.
Querying Data
The contents of a table can be retrieved by calling the IMobileServiceTable.ToEnumerableAsync method that
asynchronously evaluates the query and returns the results. Data can also be filtered server side by including a
Where clause in the query. The Where clause applies a row filtering predicate to the query against the table, as
shown in the following code example:
This query returns all the items from the TodoItem table whose Done property is equal to false . The query
results are then placed in an ObservableCollection for display.
Inserting Data
When inserting data in the Azure Mobile Apps instance, new columns will automatically be generated in the table
as required, provided that dynamic schema is enabled in the Azure Mobile Apps instance. The
IMobileServiceTable.InsertAsync method is used to insert a new row of data into the specified table, as shown in
the following code example:
public async Task SaveTaskAsync (TodoItem item)
{
...
await todoTable.InsertAsync (item);
...
}
When making an insert request, an ID must not be specified in the data being passed to the Azure Mobile Apps
instance. If the insert request contains an ID a MobileServiceInvalidOperationException will be thrown.
After the InsertAsync method completes, the ID of the data in the Azure Mobile Apps instance will be populated
in the TodoItem instance in the Xamarin.Forms application.
Updating Data
When updating data in the Azure Mobile Apps instance, new columns will automatically be generated in the table
as required, provided that dynamic schema is enabled in the Azure Mobile Apps instance. The
IMobileServiceTable.UpdateAsync method is used to update existing data with new information, as shown in the
following code example:
When making an update request, an ID must be specified so that the Azure Mobile Apps instance can identify the
data to be updated. This ID value is stored in the TodoItem.ID property. If the update request doesn't contain an
ID there is no way for the Azure Mobile Apps instance to determine the data to be updated, and so a
MobileServiceInvalidOperationException will be thrown.
Deleting Data
The IMobileServiceTable.DeleteAsync method is used to delete data from an Azure Mobile Apps table, as shown
in the following code example:
When making a delete request, an ID must be specified so that the Azure Mobile App sinstance can identify the
data to be deleted. This ID value is stored in the TodoItem.ID property. If the delete request doesn't contain an ID,
there is no way for the Azure Mobile Apps instance to determine the data to be deleted, and so a
MobileServiceInvalidOperationException will be thrown.
Summary
This article explained how to use the Azure Mobile Client SDK to query, insert, update, and delete data stored in a
table in an Azure Mobile apps instance. The SDK provides the MobileServiceClient class that is used by a
Xamarin.Forms application to access the Azure Mobile Apps instance.
Related Links
TodoAzure (sample)
Create a Xamarin.Forms app
Azure Mobile Client SDK
MobileServiceClient
Authenticating Access to Web Services
6/8/2018 • 2 minutes to read • Edit Online
This guide explains how to integrate authentication services into a Xamarin.Forms application to enable users to
share a backend while only having access to their own data. Topics covered include using basic authentication with
a REST service, using the Xamarin.Auth component to authenticate against OAuth identity providers, and using the
built-in authentication mechanisms offered by different providers.
Related Links
Introduction to Web Services
Async Support Overview
Authenticating a RESTful Web Service
3/26/2019 • 3 minutes to read • Edit Online
HTTP supports the use of several authentication mechanisms to control access to resources. Basic authentication
provides access to resources to only those clients that have the correct credentials. This article demonstrates how to
use basic authentication to protect access to RESTful web service resources.
NOTE
In iOS 9 and greater, App Transport Security (ATS) enforces secure connections between internet resources (such as the app's
back-end server) and the app, thereby preventing accidental disclosure of sensitive information. Since ATS is enabled by
default in apps built for iOS 9, all connections will be subject to ATS security requirements. If connections do not meet these
requirements, they will fail with an exception. ATS can be opted out of if it is not possible to use the HTTPS protocol and
secure communication for internet resources. This can be achieved by updating the app's Info.plist file. For more information
see App Transport Security.
If a web service receives a request for a protected resource, with the Authorization header correctly set, the
web service responds with an HTTP status code 200, which indicates that the request succeeded and that the
requested information is in the response. This scenario is shown in the following diagram:
NOTE
Basic authentication should only be used over an HTTPS connection. When used over an HTTP connection, the
Authorization header can easily be decoded if the HTTP traffic is captured by an attacker.
public RestService ()
{
var authData = string.Format ("{0}:{1}", Constants.Username, Constants.Password);
var authHeaderValue = Convert.ToBase64String (Encoding.UTF8.GetBytes (authData));
Then when a request is made to a web service operation the request is signed with the Authorization header,
indicating whether or not the user has permission to invoke the operation.
NOTE
While this code stores credentials as constants, they should not be stored in an insecure format in a published application.
The Xamarith.Auth NuGet provides functionality for securely storing credentials. For more information see Storing and
retrieving account information on devices.
Related Links
Consuming a RESTful web service
HttpClient
Authenticating Users with an Identity Provider
12/7/2018 • 12 minutes to read • Edit Online
NOTE
In iOS 9 and greater, App Transport Security (ATS) enforces secure connections between internet resources (such as the app's
back-end server) and the app, thereby preventing accidental disclosure of sensitive information. Since ATS is enabled by
default in apps built for iOS 9, all connections will be subject to ATS security requirements. If connections do not meet these
requirements, they will fail with an exception. ATS can be opted out of if it is not possible to use the HTTPS protocol and
secure communication for internet resources. This can be achieved by updating the app's Info.plist file. For more information
see App Transport Security.
The application makes an authentication request to Google using the OAuth2Authenticator class. An authentication
response is returned, once the user has successfully authenticated with Google through their sign-in page, which
includes an access token. The application then makes a request to Google for basic user data, using the
OAuth2Request class, with the access token being included in the request.
Setup
A Google API Console project must be created to integrate Google sign-in with a Xamarin.Forms application. This
can be accomplished as follows:
1. Go to the Google API Console website, and sign in with Google account credentials.
2. From the project drop-down, select an existing project, or create a new one.
3. In the sidebar under "API Manager", select Credentials, then select the OAuth consent screen tab. Choose
an Email address, specify a Product name shown to users, and press Save.
4. In the Credentials tab, select the Create credentials drop-down list, and choose OAuth client ID.
5. Under Application type, select the platform that the mobile application will be running on (iOS or Android).
6. Fill in the required details and select the Create button.
NOTE
A Client ID lets an application access enabled Google APIs, and for mobile applications is unique to a single platform.
Therefore, a OAuth client ID should be created for each platform that will use Google sign-in.
After performing these steps, Xamarin.Auth can be used to initiate an OAuth2 authentication flow with Google.
Creating and Configuring an Authenticator
Xamarin.Auth's OAuth2Authenticator class is responsible for handling the OAuth authentication flow. The
following code example shows the instantiation of the OAuth2Authenticator class when performing authentication
using the device's web browser:
var authenticator = new OAuth2Authenticator(
clientId,
null,
Constants.Scope,
new Uri(Constants.AuthorizeUrl),
new Uri(redirectUri),
new Uri(Constants.AccessTokenUrl),
null,
true);
authenticator.Completed += OnAuthCompleted;
This event will fire when the user successfully authenticates or cancels the sign-in.
Optionally, an event handler for the OAuth2Authenticator.Error event can also be registered.
Presenting the Sign-In User Interface
The sign-in user interface can be presented to the user by using a Xamarin.Auth login presenter, which must be
initialized in each platform project. The following code example shows how to initialize a login presenter in the
AppDelegate class in the iOS project:
global::Xamarin.Auth.Presenters.XamarinIOS.AuthenticationConfiguration.Init();
The following code example shows how to initialize a login presenter in the MainActivity class in the Android
project:
global::Xamarin.Auth.Presenters.XamarinAndroid.AuthenticationConfiguration.Init(this, bundle);
The .NET Standard library project can then invoke the login presenter as follows:
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
The Identifier value can be anything, and the Role value must be set to Viewer. The Url Schemes value, which
begins with com.googleusercontent.apps , can be obtained from the iOS client id for the project on Google API
Console.
When the identity provider completes the authorization request, it redirects to the application's redirect URL.
Because the URL uses a custom scheme it results in iOS launching the application, passing in the URL as a launch
parameter, where it's processed by the OpenUrl override of the application's AppDelegate class, which is shown in
the following code example:
return true;
}
The OpenUrl method converts the received URL from an NSUrl to a .NET Uri , before processing the redirect
URL with the OnPageLoading method of a public OAuth2Authenticator object. This causes Xamarin.Auth to close
the web browser tab, and to parse the received OAuth data.
Android
On Android, a custom URL scheme is registered by specifying an IntentFilter attribute on the Activity that
will handle the scheme. When the identity provider completes the authorization request, it redirects to the
application's redirect URL. As the URL uses a custom scheme it results in Android launching the application,
passing in the URL as a launch parameter, where it's processed by the OnCreate method of the Activity
registered to handle the custom URL scheme. The following code example shows the class from the sample
application that handles the custom URL scheme:
[Activity(Label = "CustomUrlSchemeInterceptorActivity", NoHistory = true, LaunchMode = LaunchMode.SingleTop )]
[IntentFilter(
new[] { Intent.ActionView },
Categories = new [] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataSchemes = new [] { "<insert custom URL here>" },
DataPath = "/oauth2redirect")]
public class CustomUrlSchemeInterceptorActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Finish();
}
}
The DataSchemes property of the IntentFilter must be set to the reversed client identifier that's obtained from
the Android client id for the project on Google API Console.
The OnCreate method converts the received URL from an Android.Net.Url to a .NET Uri , before processing the
redirect URL with the OnPageLoading method of a public OAuth2Authenticator object. This causes Xamarin.Auth to
close the web browser tab, and parse the received OAuth data.
IMPORTANT
On Android, Xamarin.Auth uses the CustomTabs API to communicate with the web browser and operating system.
However, it's not guaranteed that a CustomTabs compatible browser will be installed on the user's device.
As well as the HTTP method and the API URL, the OAuth2Request instance also specifies an Account instance that
contains the access token that signs the request to the URL specified by the Constants.UserInfoUrl property. The
identity provider then returns basic user data as a JSON response, including the users' name and email address,
provided that it recognizes the access token as being valid. The JSON response is then read and deserialized into
the user variable.
For more information, see Calling a Google API on the Google Developers portal.
Storing and Retrieving Account Information on Devices
Xamarin.Auth securely stores Account objects in an account store so that applications do not always have to re-
authenticate users. The AccountStore class is responsible for storing account information, and is backed by
Keychain services in iOS, and the KeyStore class in Android.
The following code example shows how an Account object is securely saved:
Saved accounts are uniquely identified using a key composed of the account's Username property and a service
ID, which is a string that is used when fetching accounts from the account store. If an Account was previously
saved, calling the Save method again will overwrite it.
Account objects for a service can be retrieved by calling the FindAccountsForService method, as shown in the
following code example:
The FindAccountsForService method returns an IEnumerable collection of Account objects, with the first item in
the collection being set as the matched account.
Summary
This article explained how to use Xamarin.Auth to manage the authentication process in a Xamarin.Forms
application. Xamarin.Auth provides the OAuth2Authenticator and OAuth2Request classes that are used by
Xamarin.Forms applications to consume identity providers such as Google, Microsoft, Facebook, and Twitter.
Related Links
OAuthNativeFlow (sample)
OAuth 2.0 for Native Apps
Using OAuth2.0 to Access Google APIs
Xamarin.Auth (NuGet)
Xamarin.Auth (GitHub)
Authenticating Users with Azure Mobile Apps
12/7/2018 • 6 minutes to read • Edit Online
Overview
The process for having Azure Mobile Apps manage the authentication process in a Xamarin.Forms application is
as follows:
1. Register your Azure Mobile App at an identity provider's site, and then set the provider-generated credentials
in the Mobile Apps back end. For more information, see Register your app for authentication and configure
App Services.
2. Define a new URL scheme for your Xamarin.Forms application, which allows the authentication system to
redirect back to Xamarin.Forms application once the authentication process is complete. For more information,
see Add your app to the Allowed External Redirect URLs.
3. Restrict access to the Azure Mobile Apps back end to only authenticated clients. For more information, see
Restrict permissions to authenticated users.
4. Invoke authentication from the Xamarin.Forms application. For more information, see Add authentication to
the portable class library, Add authentication to the iOS app, Add authentication to the Android app, and Add
authentication to Windows 10 app projects.
NOTE
In iOS 9 and greater, App Transport Security (ATS) enforces secure connections between internet resources (such as the app's
back-end server) and the app, thereby preventing accidental disclosure of sensitive information. Since ATS is enabled by
default in apps built for iOS 9, all connections will be subject to ATS security requirements. If connections do not meet these
requirements, they will fail with an exception. ATS can be opted out of if it is not possible to use the HTTPS protocol and
secure communication for internet resources. This can be achieved by updating the app's Info.plist file. For more
information see App Transport Security.
Historically, mobile applications have used embedded web views to perform authentication with identity
provider's. This is no longer recommended for the following reasons:
The application that hosts the web view can access the user's full authentication credential, not just the
authorization grant that was intended for the application. This violates the principle of least privilege, as the
application has access to more powerful credentials than it requires, potentially increasing the attack surface of
the application.
The host application could capture usernames and passwords, automatically submit forms and bypass user-
consent, and copy session cookies and use them to perform authenticated actions as the user.
Embedded web views don't share the authentication state with other applications, or the device's web browser,
requiring the user to sign-in for every authorization request which is considered an inferior user experience.
Some authorization endpoints take steps to detect and block authorization requests that come from web views.
The alternative is to use the device's web browser to perform authentication, which is the approach taken by the
latest version of the Azure Mobile Client SDK. Using the device browser for authentication requests improves the
usability of an application, as users only need to sign-in to the identity provider once per device, improving
conversion rates of sign-in and authorization flows in the application. The device browser also provides improved
security as applications are able to inspect and modify content in a web view, but not content shown in the
browser.
While Google is used as the identity provider, a variety of other identity providers can be used, including Facebook,
Microsoft, Twitter, and Azure Active Directory.
The following code example shows how the login process is invoked:
The App.Authenticator property is an IAuthenticate instance that's set by each platform-specific project. The
IAuthenticate interface specifies an AuthenticateAsync operation that must be provided by each platform project.
Therefore, invoking the App.Authenticator.AuthenticateAsync method executes the
IAuthenticate.AuthenticateAsync method in a platform project.
All of the platform IAuthenticate.AuthenticateAsync methods call the MobileServiceClient.LoginAsync method to
display a login interface and cache data. The following code example shows the LoginAsync method for the iOS
platform:
The following code example shows the LoginAsync method for the Android platform:
The following code example shows the LoginAsync method for the Universal Windows Platform:
On all platforms, the MobileServiceAuthenticationProvider enumeration is used to specify the identity provider
that will be used in the authentication process. When the MobileServiceClient.LoginAsync method is invoked,
Azure Mobile Apps initiates an authentication flow by displaying the login page of the selected provider, and by
generating an authentication token after successful login with the identity provider. The
MobileServiceClient.LoginAsync method returns a MobileServiceUser instance that will be stored in the
MobileServiceClient.CurrentUser property. This property provides UserId and MobileServiceAuthenticationToken
properties. These represent the authenticated user and an authentication token for the user. The authentication
token will be included in all requests made to the Azure Mobile Apps instance, allowing the Xamarin.Forms
application to perform actions on the Azure Mobile App instance that require authenticated user permissions.
Logging Out Users
The following code example shows how the logout process is invoked:
async void OnLogoutButtonClicked(object sender, EventArgs e)
{
bool loggedOut = false;
if (App.Authenticator != null)
{
loggedOut = await App.Authenticator.LogoutAsync ();
}
...
}
The following code example shows the LogoutAsync method for the Android platform:
The following code example shows the LogoutAsync method for the Universal Windows Platform:
When the IAuthenticate.LogoutAsync method is invoked, any cookies set by the identity provider are cleared,
before the MobileServiceClient.LogoutAsync method is invoked to de-authenticate the logged-in user with the
identity provider.
Summary
This article explained how to use Azure Mobile Apps to manage the authentication process in a Xamarin.Forms
application. Azure Mobile Apps use a variety of external identity providers to support authenticating and
authorizing application users, including Facebook, Google, Microsoft, Twitter, and Azure Active Directory. The
MobileServiceClient class is used by the Xamarin.Forms application to control access to the Azure Mobile Apps
instance.
Related Links
TodoAzureAuth (sample)
Consuming an Azure Mobile App
Add authentication to your Xamarin.Forms app
Azure Mobile Client SDK
MobileServiceClient
Authenticate Users with Azure Active Directory B2C
4/24/2019 • 8 minutes to read • Edit Online
Overview
Azure Active Directory B2C (ADB2C ) is an identity management service for consumer-facing applications. It
allows users to sign in to your application using their existing social accounts or custom credentials such as email
or username, and password. Custom credential accounts are referred to as local accounts.
The process for integrating the Azure Active Directory B2C identity management service into a mobile application
is as follows:
1. Create an Azure Active Directory B2C tenant
2. Register your mobile application with the Azure Active Directory B2C tenant
3. Create policies for sign-up and sign-in, and forgot password user flows
4. Use the Microsoft Authentication Library (MSAL ) to start an authentication workflow with your Azure Active
Directory B2C tenant.
NOTE
Azure Active Directory B2C supports multiple identity providers including Microsoft, GitHub, Facebook, Twitter and more.
For more information on Azure Active Directory B2C capabilities, see Azure Active Directory B2C Documentation.
Microsoft Authentication Library supports multiple application architectures and platforms. For information about MSAL
capabilities, see Microsoft Authentication Library on GitHub.
Microsoft Authentication Library expects the Redirect URL for your application to be your Application ID
prefixed with the text "msal", and followed by an endpoint called "auth". If your Application ID is "1234abcd", the
full URL should be msal1234abcd://auth . Make sure that your application has enabled the Native client setting
and create a Custom Redirect URI using your Application ID as shown in the following screenshot:
The URL will be used later in both the Android ApplicationManifest.xml and the iOS Info.plist.
In the sample project, edit the Constants.cs file to set the clientId field to your Application ID. The following
code shows how this value should be set if your Application ID is 1234abcd :
public App()
{
InitializeComponent();
AuthenticationClient = new PublicClientApplication(Constants.ClientId, Constants.AuthoritySignin);
MainPage = new NavigationPage(new LoginPage());
}
...
The OnAppearing event handler in the LoginPage.xaml.cs code behind calls AcquireTokenSilentAsync to refresh
the authentication token for users that have logged in before. The authentication process redirects to the
LogoutPage if successful and does nothing on failure. The following example shows the silent reauthentication
process in OnAppearing :
public partial class LoginPage : ContentPage
{
...
...
}
The OnLoginButtonClicked event handler (fired when the Login button is clicked) calls AcquireTokenAsync . The
MSAL library automatically opens the mobile device browser and navigates to the login page. The sign-in URL,
called an Authority, is a combination of the tenant name and policies defined in the Constants.cs file. If the user
chooses the forgot password option, they are returned to the app with an exception, which launches the forgot
password experience. The following example shows the authentication process:
public partial class LoginPage : ContentPage
{
...
...
}
The OnForgotPassword method is similar to the sign-in process but implements a custom policy. OnForgotPassword
uses a different overload of AcquireTokenAsync , which allows you to provide a specific Authority. The following
example shows how to supply a custom Authority when acquiring a token:
The final piece of authentication is the sign out process. The OnLogoutButtonClicked method is called when the
user presses the sign out button. It loops through all accounts and ensures their tokens have been invalidated. The
sample below demonstrates the sign out implementation:
while (accounts.Any())
{
await App.AuthenticationClient.RemoveAsync(accounts.First());
accounts = await App.AuthenticationClient.GetAccountsAsync();
}
await Navigation.PopAsync();
}
}
iOS
On iOS, the custom URL scheme that was registered with Azure Active Directory B2C must be registered in
Info.plist. MSAL expects the URL scheme to adhere to a specific pattern, described previously in Register your
mobile application with Azure Active Directory B2C. The following screenshot shows the custom URL scheme in
Info.plist.
MSAL also requires Keychain Entitlements on iOS, registered in the Entitilements.plist, as shown in the
following screenshot:
When Azure Active Directory B2C completes the authorization request, it redirects to the registered redirect URL.
The custom URL scheme results in iOS launching the mobile application and passing in the URL as a launch
parameter, where it's processed by the OpenUrl override of the application's AppDelegate class, and returns
control of the experience to MSAL. The OpenUrl implementation is shown in the following code example:
using Microsoft.Identity.Client;
namespace TodoAzure.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
...
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
return base.OpenUrl(app, url, options);
}
}
}
Android
On Android, the custom URL scheme that was registered with Azure Active Directory B2C must be registered in
the AndroidManifest.xml. MSAL expects the URL scheme to adhere to a specific pattern, described previously
in Register your mobile application with Azure Active Directory B2C. The following example shows the custom
URL scheme in the AndroidManifest.xml.
The MainActivity class must be modified to provide the UiParent to the application during the OnCreate call.
When Azure Active Directory B2C completes the authorization request, it redirects to the registered URL scheme
from the AndroidManifest.xml. The registered URI scheme results in Android calling OnActivityResult with the
URL as a launch parameter, where it's processed by the SetAuthenticationContinuationEventArgs .
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
Forms.Init(this, bundle);
LoadApplication(new App());
App.UiParent = new UIParent(this);
}
Related Links
AzureADB2CAuth (sample)
Azure Active Directory B2C
Microsoft Authentication Library
Microsoft Authentication Library Documentation
Integrating Azure Active Directory B2C with Azure
Mobile Apps
12/7/2018 • 8 minutes to read • Edit Online
NOTE
The Microsoft Authentication Library is still in preview, but is suitable for use in a production environment. However, there
may be breaking changes to the API, internal cache format, and other mechanisms of the library, which may impact your
application.
Overview
Azure Mobile Apps allow you to develop applications with scalable backends hosted in Azure App Service, with
support for mobile authentication, offline sync, and push notifications. For more information about Azure Mobile
Apps, see Consuming an Azure Mobile App, and Authenticating Users with Azure Mobile Apps.
Azure Active Directory B2C is an identity management service for consumer-facing applications, that allows
consumers to sign-in to your application by:
Using their existing social accounts (Microsoft, Google, Facebook, Amazon, LinkedIn).
Creating new credentials (email address and password, or username and password). These credentials are
referred to as local accounts.
For more information about Azure Active Directory B2C, see Authenticating Users with Azure Active Directory
B2C.
Azure Active Directory B2C can be used to manage the authentication workflow for an Azure Mobile App. With
this approach, the identity management experience is fully defined in the cloud, and can be modified without
changing your mobile application code.
There are two authentication workflows that can be adopted when integrating an Azure Active Directory B2C
tenant with an Azure Mobile Apps instance:
Client-managed – in this approach the Xamarin.Forms mobile application initiates the authentication process
with the Azure Active Directory B2C tenant, and passes the received authentication token to the Azure Mobile
Apps instance.
Server-managed – in this approach the Azure Mobile Apps instance uses the Azure Active Directory B2C tenant
to initiate the authentication process through a web-based workflow.
In both cases, the authentication experience is provided by the Azure Active Directory B2C tenant. In the sample
application, this results in the sign-in screen shown in the following screenshots:
Sign-in with social identity providers, or with a local account, are permitted. While Microsoft, Google, and
Facebook are used as social identity providers in this example, other identity providers can also be used.
Setup
Regardless of the authentication workflow used, the initial process for integrating an Azure Active Directory B2C
tenant with an Azure Mobile Apps instance is as follows:
1. Create an Azure Mobile Apps instance. For more information, see Consuming an Azure Mobile App.
2. Enable authentication in the Azure Mobile Apps instance and the Xamarin.Forms application. For more
information, see Authenticating Users with Azure Mobile Apps.
3. Create an Azure Active Directory B2C tenant. For more information, see Authenticating Users with Azure
Active Directory B2C.
Note that the Microsoft Authentication Library (MSAL ) is required when using a client-managed authentication
workflow. MSAL uses the device's web browser to perform authentication. This improves the usability of an
application, as users only need to sign-in once per device, improving conversion rates of sign-in and authorization
flows in the application. The device browser also provides improved security. After the user completes the
authentication process, control will return to the application from the web browser tab. This is achieved by
registering a custom URL scheme for the redirect URL that's returned from the authentication process, and then
detecting and handling the custom URL once it's sent. For more information about using MSAL to communicate
with an Azure Active Directory B2C tenant, see Authenticating Users with Azure Active Directory B2C.
Client-Managed Authentication
In client-managed authentication, a Xamarin.Forms mobile application contacts an Azure Active Directory B2C
tenant to initiate an authentication flow. After successful sign-on the Azure Active Directory B2C tenant returns an
identity token which is then provided during sign-in to the Azure Mobile Apps instance. This allows the
Xamarin.Forms application to perform actions on the Azure Mobile Apps instance that requires authenticated user
permissions.
Azure Active Directory B2C Tenant Configuration
For a client-managed authentication workflow, the Azure Active Directory B2C tenant should be configured as
follows:
Include a native client.
Set the Custom Redirect URI to a URL scheme that uniquely identifies the mobile application, followed by
://auth/ . For more information about choosing a custom URL scheme, see Choosing a native app redirect
URI.
The following screenshot demonstrates this configuration:
The policy used in the Azure Active Directory B2C tenant should also be configured so that the reply URL is set to
the same custom URL scheme, followed by ://auth/ . The following screenshot demonstrates this configuration:
Azure Mobile App Configuration
For a client-managed authentication workflow, the Azure Mobile Apps instance should be configured as follows:
App Service Authentication should be turned on.
The action to take when a request is not authenticated should be set to Log in with Azure Active Directory.
The following screenshot demonstrates this configuration:
The Azure Mobile Apps instance should also be configured to communicate with the Azure Active Directory B2C
tenant. This can be accomplished by enabling Advanced mode for the Azure Active Directory authentication
provider, with the Client ID being the Application ID of the Azure Active Directory B2C tenant, and the Issuer
Url being the metadata endpoint for the Azure Active Directory B2C policy. The following screenshot
demonstrates this configuration:
Signing In
The following code example shows how to initiate a client-managed authentication workflow:
public async Task<bool> LoginAsync(bool useSilent = false)
{
...
AuthenticationResult authenticationResult = await ADB2CClient.AcquireTokenAsync(
Constants.Scopes,
GetUserByPolicy(ADB2CClient.Users, Constants.PolicySignUpSignIn),
App.UiParent);
...
var payload = new JObject();
payload["access_token"] = authenticationResult.IdToken;
The Microsoft Authentication Library (MSAL ) is used to initiate an authentication workflow with the Azure Active
Directory B2C tenant. The AcquireTokenAsync method launches the device's web browser and displays
authentication options defined in the Azure Active Directory B2C policy that's specified by the policy referenced
through the Constants.Authority constant. This policy defines the experiences that consumers will go through
during sign-up and sign-in, and the claims the application will receive on successful sign-up or sign-in.
The result of the AcquireTokenAsync method call is an AuthenticationResult instance. If authentication is
successful, the AuthenticationResult instance will contain an identity token, which will be cached locally. If
authentication is unsuccessful, the AuthenticationResult instance will contain data that indicates why
authentication failed. For information on how to use MSAL to communicate with an Azure Active Directory B2C
tenant, see Authenticating Users with Azure Active Directory B2C.
When the MobileServiceClient.LoginAsync method is invoked, the Azure Mobile Apps instance receives the
identity token wrapped in a JObject . The presence of a valid token means that the Azure Mobile Apps instance
doesn't need to initiate its own OAuth 2.0 authentication flow. Instead, the MobileServiceClient.LoginAsync method
returns a MobileServiceUser instance that will be stored in the MobileServiceClient.CurrentUser property. This
property provides UserId and MobileServiceAuthenticationToken properties. These represent the authenticated
user and an authentication token for the user, which can be used until it expires. The authentication token will be
included in all requests made to the Azure Mobile Apps instance, allowing the Xamarin.Forms application to
perform actions on the Azure Mobile Apps instance that require authenticated user permissions.
Signing Out
The following code example shows how the client-managed sign-out process is invoked:
The MobileServiceClient.LogoutAsync method de-authenticates the user with the Azure Mobile Apps instance, and
then all authentication tokens are cleared from the local cache created by MSAL.
Server-Managed Authentication
In server-managed authentication, a Xamarin.Forms application contacts an Azure Mobile Apps instance, which
uses the Azure Active Directory B2C tenant to manage the OAuth 2.0 authentication flow by displaying a sign-in
page as defined in the B2C policy. Following successful sign-on, the Azure Mobile Apps instance returns a token
that allows the Xamarin.Forms application to perform actions on the Azure Mobile Apps instance that require
authenticated user permissions.
Azure Active Directory B2C Tenant Configuration
For a server-managed authentication workflow, the Azure Active Directory B2C tenant should be configured as
follows:
Include a web app/web API, and allow the implicit flow.
Set the Reply URL to the address of the Azure Mobile App, followed by /.auth/login/aad/callback .
The policy used in the Azure Active Directory B2C tenant should also be configured so that the Reply URL is set to
the address of the Azure Mobile App, followed by /.auth/login/aad/callback . The following screenshot
demonstrates this configuration:
Azure Mobile Apps Instance Configuration
For a server-managed authentication workflow, the Azure Mobile Apps instance should be configured as follows:
App Service Authentication should be turned on.
The action to take when a request is not authenticated should be set to Log in with Azure Active Directory.
The following screenshot demonstrates this configuration:
The Azure Mobile Apps instance should also be configured to communicate with the Azure Active Directory B2C
tenant. This can be accomplished by enabling Advanced mode for the Azure Active Directory authentication
provider, with the Client ID being the Application ID of the Azure Active Directory B2C tenant, and the Issuer
Url being the metadata endpoint for the Azure Active Directory B2C policy. The following screenshot
demonstrates this configuration:
Signing In
The following code example shows how to initiate a server-managed authentication workflow:
When the MobileServiceClient.LoginAsync method is invoked, the Azure Mobile Apps instance executes the linked
Azure Active Directory B2C policy, which initiates the OAuth 2.0 authentication flow. Note that each
AuthenticateAsync method is platform -specific. However, each AuthenticateAsync method uses the
MobileServiceClient.LoginAsync method and specifies that an Azure Active Directory tenant will be used in the
authentication process. For more information, see Logging in Users.
The MobileServiceClient.LoginAsync method returns a MobileServiceUser instance that will be stored in the
MobileServiceClient.CurrentUser property. This property provides UserId and MobileServiceAuthenticationToken
properties. These represent the authenticated user and an authentication token for the user, which can be used
until it expires. The authentication token will be included in all requests made to the Azure Mobile Apps instance,
allowing the Xamarin.Forms application to perform actions on the Azure Mobile Apps instance that require
authenticated user permissions.
Signing Out
The following code example shows how the server-managed sign-out process is invoked:
public async Task<bool> LogoutAsync()
{
...
await TodoItemManager.DefaultManager.CurrentClient.LogoutAsync();
...
}
The MobileServiceClient.LogoutAsync method de-authenticates the user with the Azure Mobile Apps instance. For
more information, see Logging Out Users.
Summary
This article demonstrated how to use Azure Active Directory B2C to provide authentication and authorization to an
Azure Mobile Apps instance with Xamarin.Forms. Azure Active Directory B2C is a cloud identity management
solution for consumer-facing web and mobile applications.
Related Links
TodoAzureAuth ServerFlow (sample)
TodoAzureAuth ClientFlow (sample)
Consuming an Azure Mobile App
Authenticating Users with Azure Mobile Apps
Authenticating Users with Azure Active Directory B2C
Microsoft Authentication Library
Synchronizing Data with Web Services
4/12/2018 • 2 minutes to read • Edit Online
Offline sync allows users to interact with a mobile application, viewing, adding, or modifying data, even where
there isn't a network connection. Changes are stored in a local database, and once the device is online, the changes
can be synced with the web service.
Related Links
Introduction to Web Services
Async Support Overview
Synchronizing Offline Data with Azure Mobile Apps
12/7/2018 • 7 minutes to read • Edit Online
Overview
The Azure Mobile Client SDK provides the IMobileServiceTable interface, which represents the operations that
can be performed on tables stored in the Azure Mobile Apps instance. These operations connect directly to the
Azure Mobile Apps instance and will fail if the mobile device doesn't have a network connection.
To support offline sync, the Azure Mobile Client SDK supports sync tables, which are provided by the
IMobileServiceSyncTable interface. This interface provides the same Create, Read, Update, Delete ( CRUD )
operations as the IMobileServiceTable interface, but the operations read from or write to a local store. The local
store isn't populated with new data from the Azure Mobile Apps instance until there is a call to pull data. Similarly,
data isn't sent to the Azure Mobile Apps instance until there is a call to push local changes.
Offline sync also includes support for detecting conflicts when the same record has changed in both the local store
and in the Azure Mobile Apps instance, and custom conflict resolution. Conflicts can either be handled in the local
store, or in the Azure Mobile Apps instance.
For more information about offline sync, see Offline Data Sync in Azure Mobile Apps and Enable offline sync for
your Xamarin.Forms mobile app.
Setup
The process for integrating offline sync between a Xamarin.Forms application and an Azure Mobile Apps instance
is as follows:
1. Create an Azure Mobile Apps instance. For more information, see Consuming an Azure Mobile App.
2. Add the Microsoft.Azure.Mobile.Client.SQLiteStore NuGet package to all projects in the Xamarin.Forms
solution.
3. (Optional) Enable authentication in the Azure Mobile Apps instance and the Xamarin.Forms application. For
more information, see Authenticating Users with Azure Mobile Apps.
The following section provides additional setup instructions for configuring Universal Windows Platform (UWP )
projects to use the Microsoft.Azure.Mobile.Client.SQLiteStore NuGet package. No additional setup is required to
use the Microsoft.Azure.Mobile.Client.SQLiteStore NuGet package on iOS and Android.
Universal Windows Platform
To use SQLite on the Universal Windows Platform (UWP ), follow these steps:
1. Install the SQLite for the Universal Windows Platform Visual Studio Extension in your development
environment.
2. In the UWP project in Visual Studio, right click References > Add Reference, navigate to Extensions and add
the SQLite for Universal Windows Platform and Visual C++ 2015 Runtime for Universal Windows
Platform Apps extensions to the UWP project.
using Microsoft.WindowsAzure.MobileServices;
using Microsoft.WindowsAzure.MobileServices.SQLiteStore;
using Microsoft.WindowsAzure.MobileServices.Sync;
namespace TodoAzure
{
public partial class TodoItemManager
{
static TodoItemManager defaultInstance = new TodoItemManager();
IMobileServiceClient client;
IMobileServiceSyncTable<TodoItem> todoTable;
private TodoItemManager()
{
this.client = new MobileServiceClient(Constants.ApplicationURL);
var store = new MobileServiceSQLiteStore("localstore.db");
store.DefineTable<TodoItem>();
this.client.SyncContext.InitializeAsync(store);
this.todoTable = client.GetSyncTable<TodoItem>();
}
...
}
}
A new local SQLite database is created by the MobileServiceSQLiteStore class, provided that it doesn't already
exist. Then, the DefineTable<T> method creates a table in the local store that matches the fields in the TodoItem
type, provided that it doesn't already exist.
A sync context is associated with a MobileServiceClient instance, and tracks changes that are made with sync
tables. The sync context maintains a queue that keeps an ordered list of Create, Update, and Delete (CUD )
operations that will be sent to the Azure Mobile Apps instance later. The
IMobileServiceSyncContext.InitializeAsync() method is used to associate the local store with the sync context.
The todoTable field is an IMobileServiceSyncTable , and so all CRUD operations use the local store.
Performing Synchronization
The local store is synchronized with the Azure Mobile Apps instance when the SyncAsync method is invoked:
public async Task SyncAsync()
{
ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
try
{
await this.client.SyncContext.PushAsync();
// The first parameter is a query name that is used internally by the client SDK to implement incremental
sync.
// Use a different query name for each unique query in your program.
await this.todoTable.PullAsync("allTodoItems", this.todoTable.CreateQuery());
}
catch (MobileServicePushFailedException exc)
{
if (exc.PushResult != null)
{
syncErrors = exc.PushResult.Errors;
}
}
The IMobileServiceSyncTable.PushAsync method operates on the sync context, rather than a specific table, and
sends all CUD changes since the last push.
Pull is performed by the IMobileServiceSyncTable.PullAsync method on a single table. The first parameter to the
PullAsync method is a query name that is used only on the mobile device. Providing a non-null query name
results in the Azure Mobile Client SDK performing an incremental sync, where each time a pull operation returns
results, the latest updatedAt timestamp from the results is stored in the local system tables. Subsequent pull
operations then only retrieve records after that timestamp. Alternatively, full sync can be achieved by passing null
as the query name, which results in all records being retrieved on each pull operation. Following any sync
operation, received data is inserted into the local store.
NOTE
If a pull is executed against a table that has pending local updates, the pull will first execute a push on the sync context. This
minimizes conflicts between changes that are already queued and new data from the Azure Mobile Apps instance.
The SyncAsync method also includes a basic implementation for handling conflicts when the same record has
changed in both the local store and in the Azure Mobile Apps instance. When the conflict is that data has been
updated both in the local store and in the Azure Mobile Apps instance, the SyncAsync method updates the data in
the local store from the data stored in the Azure Mobile Apps instance. When any other conflict occurs, the
SyncAsync method discards the local change. This handles the scenario where a local change exists for data that's
been deleted from the Azure Mobile Apps instance.
In a production application, developers should write a custom IMobileServiceSyncHandler conflict-handling
implementation that's suited to their use case. For more information, see Use Optimistic Concurrency for conflict
resolution on the Azure portal, and Deep dive on the offline support in the managed client SDK on MSDN blogs.
Purging Data
Tables in the local store can be cleared of data with the IMobileServiceSyncTable.PurgeAsync method. This method
supports scenarios such as removing stale data that an application no longer requires. For example, the sample
application only displays TodoItem instances that aren't complete. Therefore, completed items no longer need to
be stored locally. Purging completed items from the local store can be accomplished as follows:
A call to PurgeAsync also triggers a push operation. Therefore, any items that are marked as complete locally will
be sent to the Azure Mobile Apps instance before being removed from the local store. However, if there are
operations pending synchronization with the Azure Mobile Apps instance, the purge will throw an
InvalidOperationException unless the force parameter is set to true . An alternative strategy is to examine the
IMobileServiceSyncContext.PendingOperations property, which returns the number of pending operations that
haven't been pushed to the Azure Mobile Apps instance, and only perform the purge if the property is zero.
NOTE
Invoking PurgeAsync with the force parameter set to true will lose any pending changes.
Initiating Synchronization
In the sample application, the SyncAsync method is invoked through the TodoList.OnAppearing method:
// Set syncItems to true to synchronize the data on startup when running in offline mode
await RefreshItems(true, syncItems: true);
}
This means that the application will attempt to sync with the Azure Mobile Apps instance when it starts.
In addition, sync can be initiated in iOS and Android by using pull to refresh on the list of data, and on the
Windows platforms by using the Sync button on the user interface. For more information, see Pull to Refresh.
Summary
This article explained how to add offline sync functionality to a Xamarin.Forms application. Offline sync allows
users to interact with a mobile application, viewing, adding, or modifying data, even where there isn't a network
connection. Changes are stored in a local database, and once the device is online, the changes can be synced with
the Azure Mobile Apps instance.
Related Links
TodoAzureAuthOfflineSync (sample)
Consuming an Azure Mobile App
Authenticating Users with Azure Mobile Apps
Azure Mobile Client SDK
MobileServiceClient
Sending Push Notifications
4/12/2018 • 2 minutes to read • Edit Online
A push notification is used to deliver information, such as a message, from a backend system to an application on a
mobile device to increase application engagement and usage. The notification can be sent at anytime, even when
the user is not actively using the targeted application.
To send a push notification, the backend system contacts the platform-specific PNS to send a notification to a client
application instance. This significantly increases the complexity of the backend when cross-platform push
notifications are required, because the backend must use each platform-specific PNS API and protocol.
Azure Notification Hubs eliminate this complexity by abstracting the details of the different platform notification
systems, allowing a cross-platform notification to be sent with a single API call, as shown in the following diagram:
To send a push notification, the backend system only contacts the Azure Notification Hub, which in turn
communicates with the different platform notification systems, therefore decreasing the complexity of the backend
code that sends push notifications.
Azure Mobile Apps have built-in support for push notifications using notification hubs. The process for sending a
push notification from an Azure Mobile Apps instance to a Xamarin.Forms application is as follows:
1. The Xamarin.Forms application registers with the PNS, which returns a handle.
2. The Azure Mobile Apps instance sends a notification to its Azure Notification Hub, specifying the handle of the
device to be targeted.
3. The Azure Notification Hub sends the notification to the appropriate PNS for the device.
4. The PNS sends the notification to the specified device.
5. The Xamarin.Forms application processes the notification and displays it.
The sample application demonstrates a todo list application whose data is stored in an Azure Mobile Apps
instance. Every time a new item is added to the Azure Mobile Apps instance, a push notification is sent to the
Xamarin.Forms application. The following screenshots show each platform displaying the received push
notification:
For more information about Azure Notification Hubs, see Azure Notification Hubs and Add push notifications to
your Xamarin.Forms app.
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
...
}
When an iOS application registers with APNS it must specify the types of push notifications it would like to
receive. The RegisterUserNotificationSettings method registers the types of notifications the application can
receive, with the RegisterForRemoteNotifications method registering to receive push notifications from APNS.
NOTE
Failing to call the RegisterUserNotificationSettings method will result in push notifications being silently received by the
application.
This method creates a simple notification message template as JSON, and registers the device to receive template
notifications from the notification hub.
NOTE
The FailedToRegisterForRemoteNotifications override should be implemented to handle situations such as no network
connection. This is important because users might start the application while offline.
// Show alert
if (!string.IsNullOrEmpty(alert))
{
var notificationAlert = UIAlertController.Create("Notification", alert, UIAlertControllerStyle.Alert);
notificationAlert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(notificationAlert,
true, null);
}
}
The userInfo dictionary contains the aps key, whose value is the alert dictionary with the remaining
notification data. This dictionary is retrieved, with the string notification message being displayed in a dialog box.
NOTE
If an application isn't running when a push notification arrives, the application will be launched but the
DidReceiveRemoteNotification method won't process the notification. Instead, get the notification payload and respond
appropriately from the WillFinishLaunching or FinishedLaunching overrides.
Edit AndroidManifest.xml and insert the following <receiver> elements into the <application> element:
Registering the application with FCM is achieved by deriving a class from the FirebaseInstanceIdService class.
This class is responsible for generating security tokens that authorize the client application to access FCM. In the
sample application the FirebaseRegistrationService class derives from the FirebaseInstanceIdService class and is
shown in the following code example:
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class FirebaseRegistrationService : FirebaseInstanceIdService
{
const string TAG = "FirebaseRegistrationService";
The OnTokenRefresh method is invoked when the application receives a registration token from FCM. The method
retrieves the token from the FirebaseInstanceId.Instance.Token property, which is asynchronously updated by
FCM. The OnTokenRefresh method is infrequently invoked, because the token is only updated when the application
is installed or uninstalled, when the user deletes application data, when the application erases the Instance ID, or
when the security of the token has been compromised. In addition, the FCM Instance ID service will request that
the application refreshes its token periodically, typically every 6 months.
The OnTokenRefresh method also invokes the SendRegistrationTokenToAzureNotificationHub method, which is used
to associate the user's registration token with the Azure Notification Hub.
Registering with the Azure Notification Hub
The AzureNotificationHubService class provides the RegisterAsync method, which associates the user's
registration token with the Azure Notification Hub. The following code example shows the RegisterAsync method,
which is invoked by the FirebaseRegistrationService class when the user's registration token changes:
This method creates a simple notification message template as JSON, and registers to receive template
notifications from the notification hub, using the Firebase registration token. This ensures that any notifications
sent from the Azure Notification Hub will target the device represented by the registration token.
Displaying the Contents of a Push Notification
Displaying the contents of a push notification is achieved by deriving a class from the FirebaseMessagingService
class. This class includes the overridable OnMessageReceived method, which is invoked when the application
receives a notification from FCM, provided that the application is running in the foreground. In the sample
application the FirebaseNotificationService class derives from the FirebaseMessagingService class, and is shown
in the following code example:
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseNotificationService : FirebaseMessagingService
{
const string TAG = "FirebaseNotificationService";
When the application receives a notification from FCM, the OnMessageReceived method extracts the message
content, and calls the SendNotification method. This method converts the message content into a local
notification that's launched while the application is running, with the notification appearing in the notification area.
H a n d l i n g N o t i fi c a t i o n I n t e n t s
When a user taps a notification, any data accompanying the notification message is made available in the Intent
extras. This data can be extracted with the following code:
if (Intent.Extras != null)
{
foreach (var key in Intent.Extras.KeySet())
{
var value = Intent.Extras.GetString(key);
Log.Debug(TAG, "Key: {0} Value: {1}", key, value);
}
}
The application's launcher Intent is fired when the user taps its notification message, so this code will log any
accompanying data in the Intent to the output window.
Universal Windows Platform
Before a Universal Windows Platform (UWP ) application can receive push notifications it must register with the
Windows Notification Service (WNS ), which will return a notification channel. Registration is invoked by the
InitNotificationsAsync method in the App class:
private async Task InitNotificationsAsync()
{
var channel = await PushNotificationChannelManager
.CreatePushNotificationChannelForApplicationAsync();
await TodoItemManager.DefaultManager.CurrentClient.GetPush()
.RegisterAsync(channel.Uri, templates);
}
This method gets the push notification channel, creates a notification message template as JSON, and registers the
device to receive template notifications from the notification hub.
The InitNotificationsAsync method is invoked from the OnLaunched override in the App class:
This ensures that the push notification registration is created or refreshed every time the application is launched,
therefore ensuring that the WNS push channel is always active.
When a push notification is received it will automatically be displayed as a toast – a modeless window containing
the message.
Summary
This article demonstrated how to use Azure Notification Hubs to send push notifications from an Azure Mobile
Apps instance to a Xamarin.Forms application. Azure Notification Hubs provide a scalable push infrastructure for
sending mobile push notifications from any backend to any mobile platform, while eliminating the complexity of a
backend having to communicate with different platform notification systems.
Related Links
Consuming an Azure Mobile App
Azure Notification Hubs
Add push notifications to your Xamarin.Forms app
Push Notifications in iOS
Firebase Cloud Messaging
TodoAzurePush (sample)
Azure Mobile Client SDK
Storing Files in the Cloud
6/8/2018 • 2 minutes to read • Edit Online
Azure Storage is a scalable cloud storage solution that can be used for storing unstructured, and structured data.
All access to Azure Storage is through a storage account. A storage account can contain an unlimited number of
containers, and a container can store an unlimited number of blobs, up to the capacity limit of the storage account.
A blob is a file of any type and size. Azure Storage supports three different blob types:
Block blobs are optimized for streaming and storing cloud objects, and are a good choice for storing backups,
media files, documents etc. Block blobs can be up to 195Gb in size.
Append blobs are similar to block blobs but are optimized for append operations, such as logging. Append
blobs can be up to 195Gb in size.
Page blobs are optimized for frequent read/write operations and are typically used for storing virtual machines,
and their disks. Page blobs can be up to 1Tb in size.
NOTE
Note that blob storage accounts support block and append blobs, but not page blobs.
A blob is uploaded to Azure Storage, and downloaded from Azure Storage, as a stream of bytes. Therefore, files
must be converted to a stream of bytes prior to upload, and converted back to their original representation after
download.
Every object that's stored in Azure Storage has a unique URL address. The storage account name forms the
subdomain of that address, and the combination of subdomain and domain name forms an endpoint for the
storage account. For example, if your storage account is named mystorageaccount, the default blob endpoint for
the storage account is https://mystorageaccount.blob.core.windows.net .
The URL for accessing an object in a storage account is built by appending the object's location in the storage
account to the endpoint. For example, a blob address will have the format
https://mystorageaccount.blob.core.windows.net/mycontainer/myblob .
Setup
The process for integrating an Azure Storage account into a Xamarin.Forms application is as follows:
1. Create a storage account. For more information, see Create a storage account.
2. Add the Azure Storage Client Library to the Xamarin.Forms application.
3. Configure the storage connection string. For more information, see Connecting to Azure Storage.
4. Add using directives for the Microsoft.WindowsAzure.Storage and Microsoft.WindowsAzure.Storage.Blob
namespaces to classes that will access Azure Storage.
NOTE
Azure Storage supports HTTP and HTTPS in a connection string. However, using HTTPS is recommended.
UseDevelopmentStorage=true
For more information about the Azure Storage Emulator, see Use the Azure Storage Emulator for Development
and testing.
Connecting to Azure Storage Using a Shared Key
The following connection string format should be used to connect to Azure Storage with a shared key:
DefaultEndpointsProtocol=[http|https];AccountName=myAccountName;AccountKey=myAccountKey
myAccountName should be replaced with the name of your storage account, and myAccountKey should be replaced
with one of your two account access keys.
NOTE
When using shared key authentication, your account name and account key will be distributed to each person that uses your
application, which will provide full read/write access to the storage account. Therefore, use shared key authentication for
testing purposes only, and never distribute keys to other users.
myBlobEndpoint should be replaced with the URL of your blob endpoint, and mySharedAccessSignature should be
replaced with your SAS. The SAS provides the protocol, the service endpoint, and the credentials to access the
resource.
NOTE
SAS authentication is recommended for production applications. However, in a production application the SAS should be
retrieved from a backend service on-demand, rather than being bundled with the application.
For more information about Shared Access Signatures, see Using Shared Access Signatures (SAS ).
Creating a Container
The GetContainer method is used to retrieve a reference to a named container, which can then be used to retrieve
blobs from the container or to add blobs to the container. The following code example shows the GetContainer
method:
NOTE
Container names must be lowercase, and must start with a letter or number. In addition, they can only contain letters,
numbers, and the dash character, and must be between 3 and 63 characters long.
The CloudBlobContainer instance can then be used to create a container if it doesn't already exist:
await container.CreateIfNotExistsAsync();
By default, a newly created container is private. This means that a storage access key must be specified to retrieve
blobs from the container. For information about making blobs within a container public, see Create a container.
return name;
}
After retrieving a container reference, the method creates the container if it doesn't already exist. A new Guid is
then created to act as a unique blob name, and a blob block reference is retrieved as an CloudBlockBlob instance.
The stream of data is then uploaded to the blob using the UploadFromStreamAsync method, which creates the blob if
it doesn't already exist, or overwrites it if it does exist.
Before a file can be uploaded to blob storage using this method, it must first be converted to a byte stream. This is
demonstrated in the following code example:
The data is converted to a byte array, which is then wrapped as a stream that's passed to the
text
UploadFileAsync method.
Downloading Data from a Container
The GetFileAsync method is used to download blob data from Azure Storage, and is shown in the following code
example:
After retrieving a container reference, the method retrieves a blob reference for the stored data. If the blob exists,
its properties are retrieved by the FetchAttributesAsync method. A byte array of the correct size is created, and the
blob is downloaded as an array of bytes that gets returned to the calling method.
After downloading the blob byte data, it must be converted to its original representation. This is demonstrated in
the following code example:
The array of bytes is retrieved from Azure Storage by the GetFileAsync method, before it's converted back to a
UTF8 encoded string.
do
{
var result = await container.ListBlobsSegmentedAsync(token);
if (result.Results.Count() > 0)
{
var blobs = result.Results.Cast<CloudBlockBlob>().Select(b => b.Name);
allBlobsList.AddRange(blobs);
}
token = result.ContinuationToken;
} while (token != null);
return allBlobsList;
}
After retrieving a container reference, the method uses the container's ListBlobsSegmentedAsync method to retrieve
references to the blobs within the container. The results returned by the ListBlobsSegmentedAsync method are
enumerated while the BlobContinuationToken instance is not null . Each blob is cast from the returned
IListBlobItem to a CloudBlockBlob in order access the Name property of the blob, before it's value is added to the
allBlobsList collection. Once the BlobContinuationToken instance is null , the last blob name has been returned,
and execution exits the loop.
After retrieving a container reference, the method retrieves a blob reference for the specified blob. The blob is then
deleted with the DeleteIfExistsAsync method.
Related Links
Azure Storage (sample)
Introduction to Storage
How to use Blob Storage from Xamarin
Using Shared Access Signatures (SAS )
Windows Azure Storage (NuGet)
Searching Data in the Cloud
4/12/2018 • 2 minutes to read • Edit Online
Azure Search is a cloud service that provides indexing and querying capabilities for uploaded data. This removes
the infrastructure requirements and search algorithm complexities traditionally associated with implementing
search functionality in an application.
Overview
Data is stored in Azure Search as indexes and documents. An index is a store of data that can be searched by the
Azure Search service, and is conceptually similar to a database table. A document is a single unit of searchable data
in an index, and is conceptually similar to a database row. When uploading documents and submitting search
queries to Azure Search, requests are made to a specific index in the search service.
Each request made to Azure Search must include the name of the service, and an API key. There are two types of
API key:
Admin keys grant full rights to all operations. This includes managing the service, creating and deleting indexes,
and data sources.
Query keys grant read-only access to indexes and documents, and should be used by applications that issue
search requests.
The most common request to Azure Search is to execute a query. There are two types of query that can be
submitted:
A search query searches for one or more items in all searchable fields in an index. Search queries are built using
the simplified syntax, or the Lucene query syntax. For more information, see Simple query syntax in Azure
Search, and Lucene query syntax in Azure Search.
A filter query evaluates a boolean expression over all filterable fields in an index. Filter queries are built using a
subset of the OData filter language. For more information, see OData Expression Syntax for Azure Search.
Search queries and filter queries can be used separately or together. When used together, the filter query is applied
first to the entire index, and then the search query is performed on the results of the filter query.
Azure Search also supports retrieving suggestions based on search input. For more information, see Suggestion
Queries.
Setup
The process for integrating Azure Search into a Xamarin.Forms application is as follows:
1. Create an Azure Search service. For more information, see Create an Azure Search service using the Azure
Portal.
2. Remove Silverlight as a target framework from the Xamarin.Forms solution Portable Class Library (PCL ). This
can be accomplished by changing the PCL profile to any profile that supports cross-platform development, but
doesn't support Silverlight, such as profile 151 or profile 92.
3. Add the Microsoft Azure Search Library NuGet package to the PCL project in the Xamarin.Forms solution.
After performing these steps, the Microsoft Search Library API can be used to manage search indexes and data
sources, upload and manage documents, and execute queries.
var searchClient =
new SearchServiceClient(Constants.SearchServiceName, new SearchCredentials(Constants.AdminApiKey));
The SearchServiceClient constructor overload takes a search service name and a SearchCredentials object as
arguments, with the SearchCredentials object wrapping the admin key for the Azure Search service. The admin
key is required to create an index.
NOTE
A single SearchServiceClient instance should be used in an application to avoid opening too many connections to Azure
Search.
An index is defined by the Index object, as demonstrated in the following code example:
searchClient.Indexes.Create(index);
}
The Index.Name property should be set to the name of the index, and the Index.Fields property should be set to
an array of Field objects. Each Field instance specifies a name, a type, and any properties, which specify how
the field is used. These properties include:
IsKey – indicates whether the field is the key of the index. Only one field in the index, of type DataType.String ,
must be designated as the key field.
IsFacetable – indicates whether it's possible to perform faceted navigation on this field. The default value is
false .
IsFilterable – indicates whether the field can be used in filter queries. The default value is false .
IsRetrievable – indicates whether the field can be retrieved in search results. The default value is true .
IsSearchable – indicates whether the field is included in full-text searches. The default value is false .
IsSortable – indicates whether the field can be used in OrderBy expressions. The default value is false .
NOTE
Changing an index after it's deployed involves rebuilding and reloading the data.
An Index object can optionally specify a Suggesters property, which defines the fields in the index to be used to
support auto-complete or search suggestion queries. The Suggesters property should be set to an array of
Suggester objects that define the fields that are used to build the search suggestion results.
After creating the Index object, the index is created by calling Indexes.Create on the SearchServiceClient
instance.
NOTE
When creating an index from an application that must be kept responsive, use the Indexes.CreateAsync method.
For more information, see Create an Azure Search index using the .NET SDK.
searchClient.Indexes.Delete(Constants.Index);
Data to be imported into the index is packaged as an IndexBatch object, which encapsulates a collection of
IndexAction objects. Each IndexAction instance contains a document, and a property that tells Azure Search
which action to perform on the document. In the code example above, the IndexAction.Upload action is specified,
which results in the document being inserted into the index if it's new, or replaced if it already exists. The
IndexBatch object is then sent to the index by calling the Documents.Index method on the SearchIndexClient
object. For information about other indexing actions, see Decide which indexing action to use.
NOTE
Only 1000 documents can be included in a single indexing request.
Note that in the code example above, the monkeyList collection is created as an anonymous object from a
collection of Monkey objects. This creates data for the id field, and resolves the mapping of Pascal case Monkey
property names to camel case search index field names. Alternatively, this mapping can also be accomplished by
adding the [SerializePropertyNamesAsCamelCase] attribute to the Monkey class.
For more information, see Upload data to Azure Search using the .NET SDK.
SearchIndexClient indexClient =
new SearchIndexClient(Constants.SearchServiceName, Constants.Index, new
SearchCredentials(Constants.QueryApiKey));
The SearchIndexClient constructor overload takes a search service name, index name, and a SearchCredentials
object as arguments, with the SearchCredentials object wrapping the query key for the Azure Search service.
Search Queries
The index can be queried by calling the Documents.SearchAsync method on the SearchIndexClient instance, as
demonstrated in the following code example:
The SearchAsync method takes a search text argument, and an optional SearchParameters object that can be used
to further refine the query. A search query is specified as the search text argument, while a filter query can be
specified by setting the Filter property of the SearchParameters argument. The following code example
demonstrates both query types:
This filter query is applied to the entire index and removes documents from the results where the location field is
not equal to China and not equal to Vietnam. After filtering, the search query is performed on the results of the
filter query.
NOTE
To filter without searching, pass * as the search text argument.
The SearchAsync method returns a DocumentSearchResult object that contains the query results. This object is
enumerated, with each Document object being created as a Monkey object and added to the Monkeys
ObservableCollection for display. The following screenshots show search query results returned from Azure
Search:
For more information about searching and filtering, see Query your Azure Search index using the .NET SDK.
Suggestion Queries
Azure Search allows suggestions to be requested based on a search query, by calling the Documents.SuggestAsync
method on the SearchIndexClient instance. This is demonstrated in the following code example:
var suggestionResults =
await indexClient.Documents.SuggestAsync<Monkey>(text, "nameSuggester", parameters);
UseFuzzyMatching – when set to true , Azure Search will find suggestions even if there's a substituted or
missing character in the search text.
HighlightPreTag – the tag that is prepended to suggestion hits.
HighlightPostTag – the tag that is appended to suggestion hits.
MinimumCoverage – represents the percentage of the index that must be covered by a suggestion query for the
query to be reported a success. The default is 80.
Top – the number of suggestions to retrieve. It must be an integer between 1 and 100, with a default value of
5.
The overall effect is that the top 10 results from the index will be returned with hit highlighting, and the results will
include documents that include similarly spelled search terms.
The SuggestAsync method returns a DocumentSuggestResult object that contains the query results. This object is
enumerated, with each Document object being created as a Monkey object and added to the Monkeys
ObservableCollection for display. The following screenshots show the suggestion results returned from Azure
Search:
Note that in the sample application, the SuggestAsync method is only invoked when the user finishes inputting a
search term. However, it can also be used to support auto-complete search queries by executing on each keypress.
Summary
This article demonstrated how to use the Microsoft Azure Search Library to integrate Azure Search into a
Xamarin.Forms application. Azure Search is a cloud service that provides indexing and querying capabilities for
uploaded data. This removes the infrastructure requirements and search algorithm complexities traditionally
associated with implementing search functionality in an application.
Related Links
Azure Search (sample)
Azure Search Documentation
Microsoft Azure Search Library
Serverless computing with Xamarin.Forms
8/29/2018 • 2 minutes to read • Edit Online
Build apps with powerful back-end functionality, without the complexity of configuring and managing a server.
Azure Functions
Get started by building your first Azure Function that interacts with Xamarin.Forms.
Get started with Azure Functions
4/2/2019 • 2 minutes to read • Edit Online
Step-by-step instructions
In addition to the video, you can follow these instructions to build your first Function using Visual Studio.
Related Links
Azure Functions docs
Implementing a simple Azure Function with a Xamarin.Forms client (sample)
Storing Data in a Document Database
4/12/2018 • 2 minutes to read • Edit Online
An Azure Cosmos DB document database is a NoSQL database that provides low latency access to JSON
documents, offering a fast, highly available, scalable database service for applications that require seamless scale
and global replication.
Setup
The process for integrating an Azure Cosmos DB document database into a Xamarin.Forms application is as
follows:
1. Create a Cosmos DB account. For more information, see Create an Azure Cosmos DB account.
2. Add the Azure Cosmos DB .NET Standard client library NuGet package to the platform projects in the
Xamarin.Forms solution.
3. Add using directives for the Microsoft.Azure.Documents , Microsoft.Azure.Documents.Client , and
Microsoft.Azure.Documents.Linq namespaces to classes that will access the Cosmos DB account.
After performing these steps, the Azure Cosmos DB .NET Standard client library can be used to configure and
execute requests against the document database.
NOTE
The Azure Cosmos DB .NET Standard client library can only be installed into platform projects, and not into a Portable Class
Library (PCL) project. Therefore, the sample application is a Shared Access Project (SAP) to avoid code duplication. However,
the DependencyService class can be used in a PCL project to invoke Azure Cosmos DB .NET Standard client library code
contained in platform-specific projects.
The Cosmos DB Uri and primary key must be provided to the DocumentClient constructor. These can be obtained
from the Azure Portal. For more information, see Connect to a Azure Cosmos DB account.
Creating a Database
A document database is a logical container for document collections and users, and can be created in the Azure
Portal, or programmatically using the DocumentClient.CreateDatabaseIfNotExistsAsync method:
The CreateDatabaseIfNotExistsAsync method specifies a Database object as an argument, with the Database
object specifying the database name as its Id property. The CreateDatabaseIfNotExistsAsync method creates the
database if it doesn't exist, or returns the database if it already exists. However, the sample application ignores any
data returned by the CreateDatabaseIfNotExistsAsync method.
NOTE
The CreateDatabaseIfNotExistsAsync method returns a Task<ResourceResponse<Database>> object, and the status
code of the response can be checked to determine whether a database was created, or an existing database was returned.
NOTE
The CreateDocumentCollectionIfNotExistsAsync method returns a Task<ResourceResponse<DocumentCollection>>
object, and the status code of the response can be checked to determine whether a document collection was created, or an
existing document collection was returned.
Optionally, the CreateDocumentCollectionIfNotExistsAsync method can also specify a RequestOptions object, which
encapsulates options that can be specified for requests issued to the Cosmos DB account. The
RequestOptions.OfferThroughput property is used to define the performance level of the document collection, and
in the sample application, is set to 400 request units per second. This value should be increased or decreased
depending on whether the collection will be frequently or infrequently accessed.
IMPORTANT
Note that the CreateDocumentCollectionIfNotExistsAsync method will create a new collection with a reserved
throughput, which has pricing implications.
The CreateDocumentQuery<T> method specifies a Uri argument that represents the collection that should be
queried for documents. In this example, the collectionLink variable is a class-level field that specifies the Uri
that represents the document collection to retrieve documents from:
The CreateDocumentQuery<T> method creates a query that is executed synchronously, and returns an IQueryable<T>
object. However, the AsDocumentQuery method converts the IQueryable<T> object to an IDocumentQuery<T> object
which can be executed asynchronously. The asynchronous query is executed with the
IDocumentQuery<T>.ExecuteNextAsync method, which retrieves the next page of results from the document database,
with the IDocumentQuery<T>.HasMoreResults property indicating whether there are additional results to be returned
from the query.
Documents can be filtered server side by including a Where clause in the query, which applies a filtering predicate
to the query against the document collection:
This query retrieves all documents from the collection whose Done property is equal to false .
Inserting a Document into a Document Collection
Documents are user defined JSON content, and can be inserted into a document collection with the
DocumentClient.CreateDocumentAsync method:
The CreateDocumentAsync method specifies a Uri argument that represents the collection the document should be
inserted into, and an object argument that represents the document to be inserted.
Replacing a Document in a Document Collection
Documents can be replaced in a document collection with the DocumentClient.ReplaceDocumentAsync method:
The ReplaceDocumentAsync method specifies a Uri argument that represents the document in the collection that
should be replaced, and an object argument that represents the updated document data.
Deleting a Document from a Document Collection
A document can be deleted from a document collection with the DocumentClient.DeleteDocumentAsync method:
The DeleteDocumentAsync method specifies a Uri argument that represents the document in the collection that
should be deleted.
Deleting a Document Collection
A document collection can be deleted from a database with the DocumentClient.DeleteDocumentCollectionAsync
method:
await client.DeleteDocumentCollectionAsync(collectionLink);
The DeleteDocumentCollectionAsync method specifies a Uri argument that represents the document collection to
be deleted. Note that invoking this method will also delete the documents stored in the collection.
Deleting a Database
A database can be deleted from a Cosmos DB database account with the DocumentClient.DeleteDatabaesAsync
method:
await client.DeleteDatabaseAsync(UriFactory.CreateDatabaseUri(Constants.DatabaseName));
The DeleteDatabaseAsync method specifies a Uri argument that represents the database to be deleted. Note that
invoking this method will also delete the document collections stored in the database, and the documents stored in
the document collections.
Summary
This article explained how to use the Azure Cosmos DB .NET Standard client library to integrate an Azure Cosmos
DB document database into a Xamarin.Forms application. An Azure Cosmos DB document database is a NoSQL
database that provides low latency access to JSON documents, offering a fast, highly available, scalable database
service for applications that require seamless scale and global replication.
Related Links
Todo Azure Cosmos DB (sample)
Azure Cosmos DB Documentation
Azure Cosmos DB .NET Standard client library
Azure Cosmos DB API
Authenticating Users with an Azure Cosmos DB
Document Database
12/7/2018 • 10 minutes to read • Edit Online
Overview
A partition key must be specified when creating a partitioned collection, and documents with the same partition
key will be stored in the same partition. Therefore, specifying the user's identity as a partition key will result in a
partitioned collection that will only store documents for that user. This also ensures that the Azure Cosmos DB
document database will scale as the number of users and items increase.
Access must be granted to any collection, and the SQL API access control model defines two types of access
constructs:
Master keys enable full administrative access to all resources within a Cosmos DB account, and are created
when a Cosmos DB account is created.
Resource tokens capture the relationship between the user of a database and the permission the user has for a
specific Cosmos DB resource, such as a collection or a document.
Exposing a master key opens a Cosmos DB account to the possibility of malicious or negligent use. However,
Azure Cosmos DB resource tokens provide a safe mechanism for allowing clients to read, write, and delete specific
resources in an Azure Cosmos DB account according to the granted permissions.
A typical approach to requesting, generating, and delivering resource tokens to a mobile application is to use a
resource token broker. The following diagram shows a high-level overview of how the sample application uses a
resource token broker to manage access to the document database data:
The resource token broker is a mid-tier Web API service, hosted in Azure App Service, which possesses the master
key of the Cosmos DB account. The sample application uses the resource token broker to manage access to the
document database data as follows:
1. On login, the Xamarin.Forms application contacts Azure App Service to initiate an authentication flow.
2. Azure App Service performs an OAuth authentication flow with Facebook. After the authentication flow
completes, the Xamarin.Forms application receives an access token.
3. The Xamarin.Forms application uses the access token to request a resource token from the resource token
broker.
4. The resource token broker uses the access token to request the user's identity from Facebook. The user's
identity is then used to request a resource token from Cosmos DB, which is used to grant read/write access to
the authenticated user's partitioned collection.
5. The Xamarin.Forms application uses the resource token to directly access Cosmos DB resources with the
permissions defined by the resource token.
NOTE
When the resource token expires, subsequent document database requests will receive a 401 unauthorized exception. At this
point, Xamarin.Forms applications should re-establish the identity and request a new resource token.
For more information about Cosmos DB partitioning, see How to partition and scale in Azure Cosmos DB. For
more information about Cosmos DB access control, see Securing access to Cosmos DB data and Access control in
the SQL API.
Setup
The process for integrating the resource token broker into a Xamarin.Forms application is as follows:
1. Create a Cosmos DB account that will use access control. For more information, see Cosmos DB Configuration.
2. Create an Azure App Service to host the resource token broker. For more information, see Azure App Service
Configuration.
3. Create a Facebook app to perform authentication. For more information, see Facebook App Configuration.
4. Configure the Azure App Service to perform easy authentication with Facebook. For more information, see
Azure App Service Authentication Configuration.
5. Configure the Xamarin.Forms sample application to communicate with Azure App Service and Cosmos DB. For
more information, see Xamarin.Forms Application Configuration.
Azure Cosmos DB Configuration
The process for creating a Cosmos DB account that will use access control is as follows:
1. Create a Cosmos DB account. For more information, see Create an Azure Cosmos DB account.
2. In the Cosmos DB account, create a new collection named UserItems , specifying a partition key of /userid .
Azure App Service Configuration
The process for hosting the resource token broker in Azure App Service is as follows:
1. In the Azure portal, create a new App Service web app. For more information, see Create a web app in an
App Service Environment.
2. In the Azure portal, open the App Settings blade for the web app, and add the following settings:
accountUrl – the value should be the Cosmos DB account URL from the Keys blade of the Cosmos DB
account.
accountKey – the value should be the Cosmos DB master key (primary or secondary) from the Keys
blade of the Cosmos DB account.
databaseId – the value should be the name of the Cosmos DB database.
collectionId – the value should be the name of the Cosmos DB collection (in this case, UserItems ).
hostUrl – the value should be the URL of the web app from the Overview blade of the App Service
account.
The following screenshot demonstrates this configuration:
3. Publish the resource token broker solution to the Azure App Service web app.
Facebook App Configuration
The process for creating a Facebook app to perform authentication is as follows:
1. Create a Facebook app. For more information, see Register and Configure an App on the Facebook Developer
Center.
2. Add the Facebook Login product to the app. For more information, see Add Facebook Login to Your App or
Website on the Facebook Developer Center.
3. Configure Facebook Login as follows:
Enable Client OAuth Login.
Enable Web OAuth Login.
Set the Valid OAuth redirect URI to the URI of the App Service web app, with /.auth/login/facebook/callback
appended.
The following screenshot demonstrates this configuration:
The App Service web app should also be configured to communicate with the Facebook app to enable the
authentication flow. This can be accomplished by selecting the Facebook identity provider, and entering the App ID
and App Secret values from the Facebook app settings on the Facebook Developer Center. For more information,
see Add Facebook information to your application.
Xamarin.Forms Application Configuration
The process for configuring the Xamarin.Forms sample application is as follows:
1. Open the Xamarin.Forms solution.
2. Open Constants.cs and update the values of the following constants:
EndpointUri – the value should be the Cosmos DB account URL from the Keys blade of the Cosmos DB
account.
DatabaseName– the value should be the name of the document database.
CollectionName – the value should be the name of the document database collection (in this case, UserItems ).
ResourceTokenBrokerUrl – the value should be the URL of the resource token broker web app from the
Overview blade of the App Service account.
Initiating Login
The sample application initiates the login process by using Xamarin.Auth to redirect a browser to an identity
provider URL, as demonstrated in the following example code:
This causes an OAuth authentication flow to be initiated between Azure App Service and Facebook, which displays
the Facebook login page:
The login can be cancelled by pressing the Cancel button on iOS or by pressing the Back button on Android, in
which case the user remains unauthenticated and the identity provider user interface is removed from the screen.
For more information about Xamarin.Auth, see Authenticating Users with an Identity Provider.
if (!string.IsNullOrWhiteSpace(resourceToken))
{
client = new DocumentClient(new Uri(Constants.EndpointUri), resourceToken);
...
}
...
}
}
};
NOTE
A document database user is a resource associated with a document database, and each database may contain zero or more
users. A document database permission is a resource associated with a document database user, and each user may contain
zero or more permissions. A permission resource provides access to a security token that the user requires when attempting
to access a resource such as a document.
If the resourcetoken API successfully completes, it will send HTTP status code 200 (OK) in the response, along
with a JSON document containing the resource token. The following JSON data shows a typical successful
response message:
{
"id": "John Smithpermission",
"token":
"type=resource&ver=1&sig=zx6k2zzxqktzvuzuku4b7y==;a74aukk99qtwk8v5rxfrfz7ay7zzqfkbfkremrwtaapvavw2mrvia4umbi/7
iiwkrrq+buqqrzkaq4pp15y6bki1u//zf7p9x/aefbvqvq3tjjqiffurfx+vexa1xarxkkv9rbua9ypfzr47xpp5vmxuvzbekkwq6txme0xxxb
jhzaxbkvzaji+iru3xqjp05amvq1r1q2k+qrarurhmjzah/ha0evixazkve2xk1zu9u/jpyf1xrwbkxqpzebvqwma+hyyaazemr6qx9uz9be==
;",
"expires": 4035948,
"userid": "John Smith"
}
The WebRedirectAuthenticator.Completed event handler reads the response from the resourcetoken API and
extracts the resource token and the user id. The resource token is then passed as an argument to the
DocumentClient constructor, which encapsulates the endpoint, credentials, and connection policy used to access
Cosmos DB, and is used to configure and execute requests against Cosmos DB. The resource token is sent with
each request to directly access a resource, and indicates that read/write access to the authenticated users'
partitioned collection is granted.
Retrieving Documents
Retrieving documents that only belong to the authenticated user can be achieved by creating a document query
that includes the user's id as a partition key, and is demonstrated in the following code example:
The query asynchronously retrieves all the documents belonging to the authenticated user, from the specified
collection, and places them in a List<TodoItem> collection for display.
The CreateDocumentQuery<T> method specifies a Uri argument that represents the collection that should be
queried for documents, and a FeedOptions object. The FeedOptions object specifies that an unlimited number of
items can be returned by the query, and the user's id as a partition key. This ensures that only documents in the
user's partitioned collection are returned in the result.
NOTE
Note that permission documents, which are created by the resource token broker, are stored in the same document
collection as the documents created by the Xamarin.Forms application. Therefore, the document query contains a Where
clause that applies a filtering predicate to the query against the document collection. This clause ensures that permission
documents aren't returned from the document collection.
For more information about retrieving documents from a document collection, see Retrieving Document
Collection Documents.
Inserting Documents
Prior to inserting a document into a document collection, the TodoItem.UserId property should be updated with
the value being used as the partition key, as demonstrated in the following code example:
item.UserId = UserId;
await client.CreateDocumentAsync(collectionLink, item);
This ensures that the document will be inserted into the user's partitioned collection.
For more information about inserting a document into a document collection, see Inserting a Document into a
Document Collection.
Deleting Documents
The partition key value must be specified when deleting a document from a partitioned collection, as
demonstrated in the following code example:
await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(Constants.DatabaseName,
Constants.CollectionName, id),
new RequestOptions
{
PartitionKey = new PartitionKey(UserId)
});
This ensures that Cosmos DB knows which partitioned collection to delete the document from.
For more information about deleting a document from a document collection, see Deleting a Document from a
Document Collection.
Summary
This article explained how to combine access control with partitioned collections, so that a user can only access
their own document database documents in a Xamarin.Forms application. Specifying the user's identity as a
partition key ensures that a partitioned collection can only store documents for that user.
Related Links
Todo Azure Cosmos DB Auth (sample)
Consuming an Azure Cosmos DB Document Database
Securing access to Azure Cosmos DB data
Access control in the SQL API.
How to partition and scale in Azure Cosmos DB
Azure Cosmos DB Client Library
Azure Cosmos DB API
Adding Intelligence with Cognitive Services
12/7/2018 • 5 minutes to read • Edit Online
Overview
The accompanying sample is a todo list application that provides functionality to:
View a list of tasks.
Add and edit tasks through the soft keyboard, or by performing speech recognition with the Microsoft Speech
API. For more information about performing speech recognition, see Speech Recognition using the Microsoft
Speech API.
Spell check tasks using the Bing Spell Check API. For more information, see Spell Checking using the Bing
Spell Check API.
Translate tasks from English to German using the Translator API. For more information, see Text Translation
using the Translator API.
Delete tasks.
Set a task's status to 'done'.
Rate the application with emotion recognition, using the Face API. For more information, see Emotion
Recognition using the Face API.
Tasks are stored in a local SQLite database. For more information about using a local SQLite database, see
Working with a Local Database.
The TodoListPage is displayed when the application is launched. This page displays a list of any tasks stored in the
local database, and allows the user to create a new task or to rate the application:
New items can be created by clicking on the + button, which navigates to the TodoItemPage . This page can also be
navigated to by selecting a task:
The TodoItemPage allows tasks to be created, edited, spell-checked, translated, saved, and deleted. Speech
recognition can be used to create or edit a task. This is achieved by pressing the microphone button to start
recording, and by pressing the same button a second time to stop recording, which sends the recording to the Bing
Speech Recognition API.
Clicking the smilies button on the TodoListPage navigates to the RateAppPage , which is used to perform emotion
recognition on an image of a facial expression:
The RateAppPage allows the user to take a photo of their face, which is submitted to the Face API with the returned
emotion being displayed.
FOLDER PURPOSE
Models Contains the data model classes for the application. This
includes the TodoItem class, which models a single item of
data used by the application. The folder also includes classes
used to model JSON responses returned from different
Microsoft Cognitive Service APIs.
Services Contains the interfaces and classes that are used to access
different Microsoft Cognitive Service APIs, along with
interfaces that are used by the DependencyService class to
locate the classes that implement the interfaces in platform
projects.
FILE PURPOSE
Constants.cs The Constants class, which specifies the API keys and
endpoints for the Microsoft Cognitive Service APIs that are
invoked. The API key constants require updating to access the
different Cognitive Service APIs.
App.xaml.cs The App class is responsible for instantiating both the first
page that will be displayed by the application on each
platform, and the TodoManager class that is used to invoke
database operations.
NuGet Packages
The sample application uses the following NuGet packages:
Newtonsoft.Json – provides a JSON framework for .NET.
PCLStorage – provides a set of cross-platform local file IO APIs.
sqlite-net-pcl – provides SQLite database storage.
Xam.Plugin.Media – provides cross-platform photo taking and picking APIs.
The ID property is used to uniquely identify each TodoItem instance, and is decorated with SQLite attributes that
make the property an auto-incrementing primary key in the database.
Invoking Database Operations
The TodoItemRepository class implements database operations, and an instance of the class can be accessed
through the App.TodoManager property. The TodoItemRepository class provides the following methods to invoke
database operations:
GetAllItemsAsync – retrieves all of the items from the local SQLite database.
GetItemAsync – retrieves a specified item from the local SQLite database.
SaveItemAsync – creates or updates an item in the local SQLite database.
DeleteItemAsync – deletes the specified item from the local SQLite database.
Platform Project Implementations
The Services folder in the PCL project contains the IFileHelper and IAudioRecorderService interfaces that are
used by the DependencyService class to locate the classes that implement the interfaces in platform projects.
The IFileHelper interface is implemented by the FileHelper class in each platform project. This class consists of a
single method, GetLocalFilePath , which returns a local file path for storing the SQLite database.
The IAudioRecorderService interface is implemented by the AudioRecorderService class in each platform project.
This class consists of StartRecording , StopRecording , and supporting methods, which use platform APIs to record
audio from the device's microphone and store it as a wav file. On iOS, the AudioRecorderService uses the
AVFoundation API to record audio. On Android, the AudioRecordService uses the AudioRecord API to record audio.
On the Universal Windows Platform (UWP ), the AudioRecorderService uses the AudioGraph API to record audio.
Invoking Cognitive Services
The sample application invokes the following Microsoft Cognitive Services:
Microsoft Speech API. For more information, see Speech Recognition using the Microsoft Speech API.
Bing Spell Check API. For more information, see Spell Checking using the Bing Spell Check API.
Translate API. For more information, see Text Translation using the Translator API.
Face API. For more information, see Emotion Recognition using the Face API.
Related Links
Microsoft Cognitive Services Documentation
Todo Cognitive Services (sample)
Speech Recognition Using the Microsoft Speech API
12/7/2018 • 4 minutes to read • Edit Online
Overview
The Microsoft Speech API has two components:
A speech recognition API for converting spoken words to text. Speech recognition can be performed via a
REST API, client library, or service library.
A text to speech API for converting text into spoken words. Text to speech conversion is performed via a REST
API.
This article focuses on performing speech recognition via the REST API. While the client and service libraries
support returning partial results, the REST API can only return a single recognition result, without any partial
results.
An API key must be obtained to use the Microsoft Speech API. This can be obtained from the Azure portal. For
more information, see Create a Cognitive Services account in the Azure portal.
For more information about the Microsoft Speech API, see Microsoft Speech API Documentation.
Authentication
Every request made to the Microsoft Speech REST API requires a JSON Web Token (JWT) access token, which
can be obtained from the cognitive services token service at
https://api.cognitive.microsoft.com/sts/v1.0/issueToken . A token can be obtained by making a POST request to
the token service, specifying an Ocp-Apim-Subscription-Key header that contains the API key as its value.
The following code example shows how to request an access token from the token service:
The returned access token, which is Base64 text, has an expiry time of 10 minutes. Therefore, the sample
application renews the access token every 9 minutes.
The access token must be specified in each Microsoft Speech REST API call as an Authorization header prefixed
with the string Bearer , as shown in the following code example:
Failure to pass a valid access token to the Microsoft Speech REST API will result in a 403 response error.
fileStream.Dispose();
return speechResult;
}
Audio is recorded in each platform-specific project as PCM wav data, and the RecognizeSpeechAsync method uses
the PCLStorage NuGet package to open the audio file as a stream. The speech recognition request URI is
generated and an access token is retrieved from the token service. The speech recognition request is posted to the
recognition API, which returns a JSON response containing the result. The JSON response is deserialized, with
the result being returned to the calling method for display.
Configuring Speech Recognition
The speech recognition process can be configured by specifying HTTP query parameters:
The main configuration performed by the GenerateRequestUri method is to set the locale of the audio content. For
a list of the supported locales, see Supported languages .
Sending the Request
The SendRequestAsync method makes the POST request to the Microsoft Speech REST API and returns the
response:
async Task<string> SendRequestAsync(Stream fileStream, string url, string bearerToken, string contentType)
{
if (httpClient == null)
{
httpClient = new HttpClient();
}
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
The POST request is then sent to recognition API. The response is then read and returned to the calling method.
The recognition API will send HTTP status code 200 (OK) in the response, provided that the request is valid,
which indicates that the request succeeded and that the requested information is in the response. For a list of
possible error responses, see Troubleshooting.
Processing the Response
The API response is returned in JSON format, with the recognized text being contained in the name tag. The
following JSON data shows a typical successful response message:
{
"RecognitionStatus":"Success",
"DisplayText":"Go shopping tomorrow.",
"Offset":16000000,
"Duration":17100000
}
In the sample application, the JSON response is deserialized into a SpeechResult instance, with the result being
returned to the calling method for display, as shown in the following screenshots:
Summary
This article explained how to use the Microsoft Speech REST API to convert audio to text in a Xamarin.Forms
application. In addition to performing speech recognition, the Microsoft Speech API can also convert text into
spoken words.
Related Links
Microsoft Speech API Documentation.
Consuming a RESTful Web Service
Todo Cognitive Services (sample)
Spell Checking Using the Bing Spell Check API
2/7/2019 • 4 minutes to read • Edit Online
Overview
The Bing Spell Check REST API has two operating modes, and a mode must be specified when making a request
to the API:
Spell corrects short text (up to 9 words) without any casing changes.
Proof corrects long text, provides casing corrections and basic punctuation, and suppresses aggressive
corrections.
An API key must be obtained to use the Bing Spell Check API. This can be obtained at Try Cognitive Services
For a list of the languages supported by the Bing Spell Check API, see Supported languages. For more
information about the Bing Spell Check API, see Bing Spell Check Documentation.
Authentication
Every request made to the Bing Spell Check API requires an API key that should be specified as the value of the
Ocp-Apim-Subscription-Key header. The following code example shows how to add the API key to the
Ocp-Apim-Subscription-Key header of a request:
public BingSpellCheckService()
{
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", Constants.BingSpellCheckApiKey);
}
Failure to pass a valid API key to the Bing Spell Check API will result in a 401 response error.
The SpellCheckTextAsync method generates a request URI and then sends the request to the SpellCheck API,
which returns a JSON response containing the result. The JSON response is deserialized, with the result being
returned to the calling method for display.
Configuring Spell Checking
The spell checking process can be configured by specifying HTTP query parameters:
This method sets the text to be spell checked, and the spell check mode.
For more information about the Bing Spell Check REST API, see Spell Check API v7 reference.
Sending the Request
The SendRequestAsync method makes the GET request to the Bing Spell Check REST API and returns the
response:
This method sends the GET request to the SpellCheck API, with the request URL specifying the text to be
translated, and the spell check mode. The response is then read and returned to the calling method.
The SpellCheck API will send HTTP status code 200 (OK) in the response, provided that the request is valid, which
indicates that the request succeeded and that the requested information is in the response. For a list of response
objects, see Response objects.
Processing the Response
The API response is returned in JSON format. The following JSON data shows the response message for the
misspelled text Go shappin tommorow :
{
"_type":"SpellCheck",
"flaggedTokens":[
{
"offset":3,
"token":"shappin",
"type":"UnknownToken",
"suggestions":[
{
"suggestion":"shopping",
"score":1
}
]
},
{
"offset":11,
"token":"tommorow",
"type":"UnknownToken",
"suggestions":[
{
"suggestion":"tomorrow",
"score":1
}
]
}
],
"correctionType":"High"
}
The flaggedTokens array contains an array of words in the text that were flagged as not being spelled correctly or
are grammatically incorrect. The array will be empty if no spelling or grammar errors are found. The tags within
the array are:
offset – a zero-based offset from the beginning of the text string to the word that was flagged.
token – the word in the text string that is not spelled correctly or is grammatically incorrect.
type – the type of the error that caused the word to be flagged. There are two possible values – RepeatedToken
and UnknownToken .
suggestions – an array of words that will correct the spelling or grammar error. The array is made up of a
suggestion and a score , which indicates the level of confidence that the suggested correction is correct.
In the sample application, the JSON response is deserialized into a SpellCheckResult instance, with the result
being returned to the calling method for display. The following code example shows how the SpellCheckResult
instance is processed for display:
This code iterates through the FlaggedTokens collection and replaces any misspelled or grammatically incorrect
words in the source text with the first suggestion. The following screenshots show before and after the spell check:
NOTE
The example above uses Replace for simplicity, but across a large amount of text it could replace the wrong token. The API
provides the offset value which should be used in production apps to identify the correct location in the source text to
perform an update.
Summary
This article explained how to use the Bing Spell Check REST API to correct spelling errors in a Xamarin.Forms
application. Bing Spell Check performs contextual spell checking for text, providing inline suggestions for
misspelled words.
Related Links
Bing Spell Check Documentation
Consuming a RESTful Web Service
Todo Cognitive Services (sample)
Bing Spell Check API v7 reference
Text Translation Using the Translator API
12/7/2018 • 4 minutes to read • Edit Online
Overview
The Translator API has two components:
A text translation REST API to translate text from one language into text of another language. The API
automatically detects the language of the text that was sent before translating it.
A speech translation REST API to transcribe speech from one language into text of another language. The API
also integrates text-to-speech capabilities to speak the translated text back.
This article focuses on translating text from one language to another using the Translator Text API.
An API key must be obtained to use the Translator Text API. This can be obtained at How to sign up for the
Microsoft Translator Text API.
For more information about the Microsoft Translator Text API, see Translator Text API Documentation.
Authentication
Every request made to the Translator Text API requires a JSON Web Token (JWT) access token, which can be
obtained from the cognitive services token service at https://api.cognitive.microsoft.com/sts/v1.0/issueToken . A
token can be obtained by making a POST request to the token service, specifying an Ocp-Apim-Subscription-Key
header that contains the API key as its value.
The following code example shows how to request an access token from the token service:
The returned access token, which is Base64 text, has an expiry time of 10 minutes. Therefore, the sample
application renews the access token every 9 minutes.
The access token must be specified in each Translator Text API call as an Authorization header prefixed with the
string Bearer , as shown in the following code example:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
For more information about the cognitive services token service, see Authentication Token API.
The TranslateTextAsync method generates a request URI and retrieves an access token from the token service.
The text translation request is then sent to the translate API, which returns an XML response containing the
result. The XML response is parsed, and the translation result is returned to the calling method for display.
For more information about the Text Translation REST APIs, see Microsoft Translator Text API.
Configuring Text Translation
The text translation process can be configured by specifying HTTP query parameters:
This method sets the text to be translated, and the language to translate the text to. For a list of the languages
supported by Microsoft Translator, see Supported languages in the Microsoft Translator Text API.
NOTE
If an application needs to know what language the text is in, the Detect API can be called to detect the language of the
text string.
This method builds the GET request by adding the access token to the Authorization header, prefixed with the
string Bearer . The GET request is then sent to the translate API, with the request URL specifying the text to be
translated, and the language to translate the text to. The response is then read and returned to the calling method.
The translate API will send HTTP status code 200 (OK) in the response, provided that the request is valid, which
indicates that the request succeeded and that the requested information is in the response. For a list of possible
error responses, see Response Messages at GET Translate.
Processing the Response
The API response is returned in XML format. The following XML data shows a typical successful response
message:
In the sample application, the XML response is parsed into a XDocument instance, with the XML root value being
returned to the calling method for display as shown in the following screenshots:
Summary
This article explained how to use the Microsoft Translator Text API to translate text from one language into text of
another language in a Xamarin.Forms application. In addition to translating text, the Microsoft Translator API can
also transcribe speech from one language into text of another language.
Related Links
Translator Text API Documentation.
Consuming a RESTful Web Service
Todo Cognitive Services (sample)
Microsoft Translator Text API.
Emotion Recognition Using the Face API
12/7/2018 • 5 minutes to read • Edit Online
Overview
The Face API can perform emotion detection to detect anger, contempt, disgust, fear, happiness, neutral, sadness,
and surprise, in a facial expression. These emotions are universally and cross-culturally communicated via the
same basic facial expressions. As well as returning an emotion result for a facial expression, the Face API can also
returns a bounding box for detected faces. Note that an API key must be obtained to use the Face API. This can be
obtained at Try Cognitive Services.
Emotion recognition can be performed via a client library, and via a REST API. This article focuses on performing
emotion recognition via the REST API. For more information about the REST API, see Face REST API.
The Face API can also be used to recognize the facial expressions of people in video, and can return a summary of
their emotions. For more information, see How to Analyze Videos in Real-time.
For more information about the Face API, see Face API.
Authentication
Every request made to the Face API requires an API key that should be specified as the value of the
Ocp-Apim-Subscription-Key header. The following code example shows how to add the API key to the
Ocp-Apim-Subscription-Key header of a request:
public FaceRecognitionService()
{
_client = new HttpClient();
_client.DefaultRequestHeaders.Add("ocp-apim-subscription-key", Constants.FaceApiKey);
}
Failure to pass a valid API key to the Face API will result in a 401 response error.
NOTE
Supported image file formats are JPEG, PNG, GIF, and BMP, and the allowed file size is from 1KB to 4MB.
In the sample application, the emotion recognition process is invoked by calling the DetectAsync method:
This method call specifies the stream containing the image data, that faceIds should be returned, that face
landmarks shouldn't be returned, and that the emotion of the image should be analyzed. It also specifies that the
results will be returned as an array of Face objects. In turn, the DetectAsync method invokes the detect REST
API that performs emotion recognition:
This method generates a request URI and then sends the request to the detect API via the SendRequestAsync
method.
NOTE
You must use the same region in your Face API calls as you used to obtain your subscription keys. For example, if you
obtained your subscription keys from the westus region, the face detection endpoint will be
https://westus.api.cognitive.microsoft.com/face/v1.0/detect .
If the image is supplied via a stream, the method builds the POST request by wrapping the image stream in a
StreamContent instance, which provides HTTP content based on a stream. Alternatively, if the image is supplied via
a URL, the method builds the POST request by wrapping the URL in a StringContent instance, which provides
HTTP content based on a string.
The POST request is then sent to detect API. The response is read, deserialized, and returned to the calling
method.
The detect API will send HTTP status code 200 (OK) in the response, provided that the request is valid, which
indicates that the request succeeded and that the requested information is in the response. For a list of possible
error responses, see Face REST API.
Processing the Response
The API response is returned in JSON format. The following JSON data shows a typical successful response
message that supplies the data requested by the sample application:
[
{
"faceId":"8a1a80fe-1027-48cf-a7f0-e61c0f005051",
"faceRectangle":{
"top":192,
"left":164,
"width":339,
"height":339
},
"faceAttributes":{
"emotion":{
"anger":0.0,
"contempt":0.0,
"disgust":0.0,
"fear":0.0,
"happiness":1.0,
"neutral":0.0,
"sadness":0.0,
"surprise":0.0
}
}
}
]
A successful response message consists of an array of face entries ranked by face rectangle size in descending
order, while an empty response indicates no faces detected. Each recognized face includes a series of optional face
attributes, which are specified by the returnFaceAttributes argument to the DetectAsync method.
In the sample application, the JSON response is deserialized into an array of Face objects. When interpreting
results from the Face API, the detected emotion should be interpreted as the emotion with the highest score, as
scores are normalized to sum to one. Therefore, the sample application displays the recognized emotion with the
highest score for the largest detected face in the image. This is achieved with the following code:
emotionResultLabel.Text = faces.FirstOrDefault().FaceAttributes.Emotion.ToRankedList().FirstOrDefault().Key;
The following screenshot shows the result of the emotion recognition process in the sample application:
Summary
This article explained how to use the Face API to recognize emotion, to rate a Xamarin.Forms application. The Face
API takes a facial expression in an image as an input, and returns data that includes the confidence across a set of
emotions for each face in the image.
Related Links
Face API.
Todo Cognitive Services (sample)
Face REST API
Xamarin.Forms Deployment and Testing
3/8/2019 • 2 minutes to read • Edit Online
Performance
There are many techniques for increasing the performance of Xamarin.Forms apps. Collectively these techniques
can greatly reduce the amount of work being performed by a CPU, and the amount of memory consumed by an
application.
This document gives an overview of the distribution techniques that are available for Xamarin.iOS applications
and serves as a pointer to more detailed documents on the topic.
Once an Xamarin.iOS app has been developed, the next step in the software development lifecycle is to distribute
the app to users, as shown in the highlighted section of the diagram below:
Apple provides the following ways to distribute an iOS application, which are supported by Xamarin.iOS:
1. The App Store
2. In-House (Enterprise)
3. Ad Hoc
All these scenarios require that applications be provisioned using the appropriate provisioning profile. Provisioning
profiles are files that contain code signing information, as well as the identity of the application and the intended
distribution mechanism. For the non-App Store distribution they also contain information about what devices the
app can be deployed to.
In-House Distribution
Sometimes called Enterprise Distribution, in-house distribution allows members of the Apple Developer
Enterprise Program to distribute apps internally to other members of the same organization. In-house
distribution has the advantages of not requiring an App Store review, and having no limit on the number of devices
on which an application can be installed. However, it is important to note that Apple Developer Enterprise
Program members do not have access to iTunes Connect, and therefore the licensee is responsible for
distributing the app.
For more information on getting set-up and how to distribute an application In-House, please refer to the In-
House Distribution guide.
Ad Hoc Distribution
Xamarin.iOS applications can be user-tested via ad hoc distribution, which is available on both the Apple
Developer Program, and the Apple Developer Enterprise Program, and allows up to 100 iOS devices to be
tested. The best use case for ad hoc distribution is distribution within a company when iTunes Connect is not an
option.
For more information on getting set-up and how to distribute an application In-House, please refer to the Ad Hoc
Distribution guide.
Summary
This article gave a brief overview of the distribution mechanisms that are available for Xamarin.iOS applications. It
introduced the iTunes App Store, Ad Hoc and In-house deployment, and provided links to more detailed
information.
Related Links
App Store Distribution
Configuring an App in iTunes Connect
Publishing to the App Store
In-House Distribution
Ad Hoc Distribution
The iTunesMetadata.plist File
IPA Support
Troubleshooting
Publishing an Application
3/8/2019 • 3 minutes to read • Edit Online
After a great application has been created, people will want to use it. This section covers the steps involved with the
public distribution of an application created with Xamarin.Android via channels such as e-mail, a private web
server, Google Play, or the Amazon App Store for Android.
Overview
The final step in the development of a Xamarin.Android application is to publish the application. Publishing is the
process of compiling a Xamarin.Android application so that it is ready for users to install on their devices, and it
involves two essential tasks:
Preparing for Publication – A release version of the application is created that can be deployed to
Android-powered devices (see Preparing an Application for Release for more information about release
preparation).
Distribution – The release version of an application is made available through one or more of the various
distribution channels.
The following diagram illustrates the steps involved with publishing a Xamarin.Android application:
As can be seen by the diagram above, the preparation is the same regardless of the distribution method that is
used. There are several ways that an Android application may be released to users:
Via a Website – A Xamarin.Android application can be made available for download on a website, from which
users may then install the application by clicking on a link.
By e-mail – It is possible for users to install a Xamarin.Android application from their e-mail. The application
will be installed when the attachment is opened with an Android-powered device.
Through a Market – There are several application marketplaces that exist for distribution, such as Google Play
or Amazon App Store for Android .
Using an established marketplace is the most common way to publish an application as it provides the broadest
market reach and the greatest control over distribution. However, publishing an application through a marketplace
requires additional effort.
Multiple channels can distribute a Xamarin.Android application simultaneously. For example, an application could
be published on Google Play, the Amazon App Store for Android, and also be downloaded from a web server.
The other two methods of distribution (downloading or e-mail) are most useful for a controlled subset of users,
such as an enterprise environment or an application that is only meant for a small or well-specified set of users.
Server and e-mail distribution are also simpler publishing models, requiring less preparation to publish an
application.
The Amazon Mobile App Distribution Program enables mobile app developers to distribute and sell their
applications on Amazon. Users can discover and shop for apps on their Android-powered devices by using the
Amazon App Store application. A screenshot of the Amazon App Store running on an Android device appears
below:
Google Play is arguably the most comprehensive and popular marketplace for Android applications. Google Play
allows users to discover, download, rate, and pay for applications by clicking a single icon either on their device or
on their computer. Google Play also provides tools to assist in the analysis of sales and market trends and to
control which devices and users may download an application. A screenshot of Google Play running on an Android
device appears below:
This section shows how to upload the application to a store such as Google Play, along with the appropriate
promotional materials. APK expansion files are explained, providing a conceptual overview of what they are and
how they work. Google Licensing services are also described. Finally, alternate means of distribution are
introduced, including the use of an HTTP web server, simple e-mail distribution, and the Amazon App Store for
Android.
Related Links
HelloWorldPublishing (sample)
Build Process
Linking
Obtaining A Google Maps API Key
Application Signing
Publishing on Google Play
Google Application Licensing
Android.Play.ExpansionLibrary
Mobile App Distribution Portal
Amazon Mobile App Distribution FAQ
Publishing Xamarin.Mac Apps to the Mac App Store
10/1/2018 • 2 minutes to read • Edit Online
Overview
Xamarin.Mac apps can be distributed in two different ways:
Developer ID – Applications signed with a Developer ID can be distributed outside of the App Store but are
recognized by GateKeeper and allowed to install.
Mac App Store – Apps must have an installer package, and both the app and the installer must be signed, for
submission to the Mac App Store.
This document explains how to use Visual Studio for Mac and Xcode to setup a Apple Developer account and
configure a Xamarin.Mac project for each deployment type.
NOTE
The choices made here will affect the way some screens appear when configuring a developer account. The descriptions and
screenshots in this document are done from the perspective of an Individual developer account. In a Company, some
options will only be available to Team Admin users.
Related Links
Installation
Hello, Mac sample
Developer ID and GateKeeper
Xamarin.Forms Performance
12/7/2018 • 10 minutes to read • Edit Online
There are many techniques for increasing the performance of Xamarin.Forms applications. Collectively these
techniques can greatly reduce the amount of work being performed by a CPU, and the amount of memory
consumed by an application. This article describes and discusses these techniques.
Overview
Poor application performance presents itself in many ways. It can make an application seem unresponsive, can
cause slow scrolling, and can reduce battery life. However, optimizing performance involves more than just
implementing efficient code. The user's experience of application performance must also be considered. For
example, ensuring that operations execute without blocking the user from performing other activities can help to
improve the user's experience.
There are a number of techniques for increasing the performance, and perceived performance, of a Xamarin.Forms
application. They include:
Enable the XAML Compiler
Choose the Correct Layout
Enable Layout Compression
Use Fast Renderers
Reduce Unnecessary Bindings
Optimize Layout Performance
Optimize ListView Performance
Optimize Image Resources
Reduce the Visual Tree Size
Reduce the Application Resource Dictionary Size
Use the Custom Renderer Pattern
NOTE
Before reading this article you should first read Cross-Platform Performance, which discusses non-platform specific
techniques to improve the memory usage and performance of applications built using the Xamarin platform.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DisplayImage.HomePage">
<ContentPage.Content>
<StackLayout>
<Image Source="waterfront.jpg" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
This is wasteful and the StackLayout element should be removed, as shown in the following code example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DisplayImage.HomePage">
<ContentPage.Content>
<Image Source="waterfront.jpg" />
</ContentPage.Content>
</ContentPage>
In addition, don't attempt to reproduce the appearance of a specific layout by using combinations of other layouts,
as this results in unnecessary layout calculations being performed. For example, don't attempt to reproduce a
Grid layout by using a combination of StackLayout instances. The following code example shows an example of
this bad practice:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<ContentPage.Content>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name:" />
<Entry Placeholder="Enter your name" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Age:" />
<Entry Placeholder="Enter your age" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Occupation:" />
<Entry Placeholder="Enter your occupation" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Address:" />
<Entry Placeholder="Enter your address" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
This is wasteful because unnecessary layout calculations are performed. Instead, the desired layout can be better
achieved using a Grid , as shown in the following code example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<ContentPage.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Label Text="Name:" />
<Entry Grid.Column="1" Placeholder="Enter your name" />
<Label Grid.Row="1" Text="Age:" />
<Entry Grid.Row="1" Grid.Column="1" Placeholder="Enter your age" />
<Label Grid.Row="2" Text="Occupation:" />
<Entry Grid.Row="2" Grid.Column="1" Placeholder="Enter your occupation" />
<Label Grid.Row="3" Text="Address:" />
<Entry Grid.Row="3" Grid.Column="1" Placeholder="Enter your address" />
</Grid>
</ContentPage.Content>
</ContentPage>
<ContentPage.Content>
<StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Hello" />
</StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Welcome to the App!" />
</StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Downloading Data..." />
</StackLayout>
</StackLayout>
</ContentPage.Content>
The same page layout can be maintained with a reduced element count, as shown in the following code example:
<ContentPage.Content>
<StackLayout Padding="20,20,0,0" Spacing="25">
<Label Text="Hello" />
<Label Text="Welcome to the App!" />
<Label Text="Downloading Data..." />
</StackLayout>
</ContentPage.Content>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Resources.App">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="HeadingLabelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
However, XAML that's specific to a page shouldn't be included in the app's resource dictionary, as the resources
will then be parsed at application startup instead of when required by a page. If a resource is used by a page that's
not the startup page, it should be placed in the resource dictionary for that page, therefore helping to reduce the
XAML that's parsed when the application starts. The following code example shows the HeadingLabelStyle
resource, which is only on a single page, and so is defined in the page's resource dictionary:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Test.HomePage"
Padding="0,20,0,0">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="HeadingLabelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
...
</ContentPage.Content>
</ContentPage>
For more information about application resources, see Working with Styles .
However, in some circumstances the OnElementChanged method can be called multiple times. Therefore, to prevent
memory leaks, which can have a performance impact, 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:
if (Control == null) {
// Instantiate the native control
}
if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null) {
// Configure the control and subscribe to event handlers
}
}
A new native control should only be instantiated once, when the Control property is null . The 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 only be unsubscribed from
when the element renderer is attached to changes. Adopting this approach will help to create an efficiently
performing custom renderer that doesn't suffer from memory leaks.
For more information about custom renderers, see Customizing Controls on Each Platform.
Summary
This article described and discussed techniques for increasing the performance of Xamarin.Forms applications.
Collectively these techniques can greatly reduce the amount of work being performed by a CPU, and the amount
of memory consumed by an application.
Related Links
Cross-Platform Performance
ListView Performance
Fast Renderers
Layout Compression
XamlCompilation
XamlCompilationOptions
Advanced Concepts & Internals
12/4/2018 • 2 minutes to read • Edit Online
Dependency Resolution
This article explains how to inject a dependency resolution method into Xamarin.Forms so that an application's
dependency injection container has control over the creation and lifetime of custom renderers, effects, and
DependencyService implementations.
Fast Renderers
This article introduces fast renderers, which reduce the inflation and rendering costs of a Xamarin.Forms control on
Android by flattening the resulting native control hierarchy.
.NET Standard
This article explains how to convert a Xamarin.Forms application to use .NET Standard 2.0.
Dependency resolution in Xamarin.Forms
12/7/2018 • 9 minutes to read • Edit Online
NOTE
While this article focuses on injecting a dependency resolution method into Xamarin.Forms that resolves registered types
using a dependency injection container, it's also possible to inject a dependency resolution method that uses factory
methods to resolve registered types. For more information, see the Dependency Resolution using Factory Methods sample.
public App()
{
...
DependencyResolver.ResolveUsing(type => container.IsRegistered(type) ? container.Resolve(type) :
null);
...
}
...
}
In this example, the dependency resolution method is set to a lambda expression that uses the Autofac
dependency injection container to resolve any types that have been registered with the container. Otherwise, null
will be returned, which will result in Xamarin.Forms attempting to resolve the type.
NOTE
The API used by a dependency injection container is specific to the container. The code examples in this article use Autofac as
a dependency injection container, which provides the IContainer and ContainerBuilder types. Alternative dependency
injection containers could equally be used, but would use different APIs than are presented here.
Note that there is no requirement to set the dependency resolution method during application startup. It can be
set at any time. The only constraint is that Xamarin.Forms needs to know about the dependency resolution method
by the time that the application attempts to consume types stored in the dependency injection container. Therefore,
if there are services in the dependency injection container that the application will require during startup, the
dependency resolution method will have to be set early in the application's lifecycle. Similarly, if the dependency
injection container manages the creation and lifetime of a particular Effect , Xamarin.Forms will need to know
about the dependency resolution method before it attempts to create a view that uses that Effect .
WARNING
Registering and resolving types with a dependency injection container has a performance cost because of the container's use
of reflection for creating each type, especially if dependencies are being reconstructed for each page navigation in the
application. If there are many or deep dependencies, the cost of creation can increase significantly.
Registering types
Types must be registered with the dependency injection container before it can resolve them via the dependency
resolution method. The following code example shows the registration methods that the sample application
exposes in the App class, for the Autofac container:
using Autofac;
using Autofac.Core;
...
public static void RegisterType<TInterface, T>() where TInterface : class where T : class, TInterface
{
builder.RegisterType<T>().As<TInterface>();
}
When an application uses a dependency resolution method to resolve types from a container, type registrations
are typically performed from platform projects. This enables platform projects to register types for custom
renderers, effects, and DependencyService implementations.
Following type registration from a platform project, the IContainer object must be built, which is accomplished by
calling the BuildContainer method. This method invokes Autofac's Build method on the ContainerBuilder
instance, which builds a new dependency injection container that contains the registrations that have been made.
In the sections that follow, a Logger class that implements the ILogger interface is injected into class constructors.
The Logger class implements simple logging functionality using the Debug.WriteLine method, and is used to
demonstrate how services can be injected into custom renderers, effects, and DependencyService implementations.
Registering custom renderers
The sample application includes a page that plays web videos, whose XAML source is shown in the following
example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
...>
<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4" />
</ContentPage>
The VideoPlayer view is implemented on each platform by a VideoPlayerRenderer class, that provides the
functionality for playing the video. For more information about these custom renderer classes, see Implementing a
video player.
On iOS and the Universal Windows Platform (UWP ), the VideoPlayerRenderer classes have the following
constructor, which requires an ILogger argument:
On all the platforms, type registration with the dependency injection container is performed by the RegisterTypes
method, which is invoked prior to the platform loading the application with the LoadApplication(new App())
method. The following example shows the RegisterTypes method on the iOS platform:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterType<FormsVideoLibrary.iOS.VideoPlayerRenderer>();
App.BuildContainer();
}
In this example, the Loggerconcrete type is registered via a mapping against its interface type, and the
VideoPlayerRenderer type is registered directly without an interface mapping. When the user navigates to the page
containing the VideoPlayer view, the dependency resolution method will be invoked to resolve the
VideoPlayerRenderer type from the dependency injection container, which will also resolve and inject the Logger
type into the VideoPlayerRenderer constructor.
The VideoPlayerRendererconstructor on the Android platform is slightly more complicated as it requires a
Context argument in addition to the ILogger argument:
The following example shows the RegisterTypes method on the Android platform:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterTypeWithParameters<FormsVideoLibrary.Droid.VideoPlayerRenderer>
(typeof(Android.Content.Context), this, typeof(ILogger), "logger");
App.BuildContainer();
}
In this example, the App.RegisterTypeWithParameters method registers the VideoPlayerRenderer with the
dependency injection container. The registration method ensures that the MainActivity instance will be injected as
the Context argument, and that the Logger type will be injected as the ILogger argument.
Registering effects
The sample application includes a page that uses a touch tracking effect to drag BoxView instances around the
page. The Effect is added to the BoxView using the following code:
The TouchEffect class is a RoutingEffect that's implemented on each platform by a TouchEffect class that's a
PlatformEffect . The platform TouchEffect class provides the functionality for dragging the BoxView around the
page. For more information about these effect classes, see Invoking events from effects.
On all the platforms, the TouchEffect class has the following constructor, which requires an ILogger argument:
On all the platforms, type registration with the dependency injection container is performed by the RegisterTypes
method, which is invoked prior to the platform loading the application with the LoadApplication(new App())
method. The following example shows the RegisterTypes method on the Android platform:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterType<TouchTracking.Droid.TouchEffect>();
App.BuildContainer();
}
In this example, the Logger concrete type is registered via a mapping against its interface type, and the
TouchEffect type is registered directly without an interface mapping. When the user navigates to the page
containing a BoxView instance that has the TouchEffect attached to it, the dependency resolution method will be
invoked to resolve the platform TouchEffect type from the dependency injection container, which will also resolve
and inject the Logger type into the TouchEffect constructor.
Registering DependencyService implementations
The sample application includes a page that uses DependencyService implementations on each platform to allow
the user to pick a photo from the device's picture library. The IPhotoPicker interface defines the functionality that
is implemented by the DependencyService implementations, and is shown in the following example:
public interface IPhotoPicker
{
Task<Stream> GetImageStreamAsync();
}
In each platform project, the PhotoPicker class implements the IPhotoPicker interface using platform APIs. For
more information about these dependency services, see Picking a photo from the picture library.
On iOS and UWP, the PhotoPicker classes have the following constructor, which requires an ILogger argument:
On all the platforms, type registration with the dependency injection container is performed by the RegisterTypes
method, which is invoked prior to the platform loading the application with the LoadApplication(new App())
method. The following example shows the RegisterTypes method on UWP:
void RegisterTypes()
{
DIContainerDemo.App.RegisterType<ILogger, Logger>();
DIContainerDemo.App.RegisterType<IPhotoPicker, Services.UWP.PhotoPicker>();
DIContainerDemo.App.BuildContainer();
}
In this example, the Logger concrete type is registered via a mapping against its interface type, and the
PhotoPicker type is also registered via a interface mapping.
The PhotoPicker constructor on the Android platform is slightly more complicated as it requires a Context
argument in addition to the ILogger argument:
The following example shows the RegisterTypes method on the Android platform:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterTypeWithParameters<IPhotoPicker, Services.Droid.PhotoPicker>(typeof(Android.Content.Context),
this, typeof(ILogger), "logger");
App.BuildContainer();
}
In this example, the App.RegisterTypeWithParameters method registers the PhotoPicker with the dependency
injection container. The registration method ensures that the MainActivity instance will be injected as the
Context argument, and that the Logger type will be injected as the ILogger argument.
When the user navigates to the photo picking page and chooses to select a photo, the OnSelectPhotoButtonClicked
handler is executed:
async void OnSelectPhotoButtonClicked(object sender, EventArgs e)
{
...
var photoPickerService = DependencyService.Resolve<IPhotoPicker>();
var stream = await photoPickerService.GetImageStreamAsync();
if (stream != null)
{
image.Source = ImageSource.FromStream(() => stream);
}
...
}
When the DependencyService.Resolve<T> method is invoked, the dependency resolution method will be invoked to
resolve the PhotoPicker type from the dependency injection container, which will also resolve and inject the
Logger type into the PhotoPicker constructor.
NOTE
The Resolve<T> method must be used when resolving a type from the application's dependency injection container via the
DependencyService .
Related links
Dependency resolution using containers (sample)
Dependency injection
Implementing a video player
Invoking events from effects
Picking a photo from the picture library
Xamarin.Forms Fast Renderers
3/25/2019 • 2 minutes to read • Edit Online
This article introduces fast renderers (added in Xamarin.Forms 2.4 ), which reduce the inflation and rendering costs
of a Xamarin.Forms control on Android by flattening the resulting native control hierarchy.
Traditionally, most of the original control renderers on Android are composed of two views:
A native control, such as a Button or TextView .
A container ViewGroup that handles some of the layout work, gesture handling, and other tasks.
However, this approach has a performance implication in that two views are created for each logical control,
which results in a more complex visual tree that requires more memory, and more processing to render on
screen.
Fast renderers reduce the inflation and rendering costs of a Xamarin.Forms control into a single view. Therefore,
instead of creating two views and adding them to the view tree, only one is created. This improves performance
by creating fewer objects, which in turn means a less complex view tree, and less memory use (which also results
in fewer garbage collection pauses).
Fast renderers are available for the following controls in Xamarin.Forms 2.4 on Android:
Button
Image
Label
Frame
Functionally, these fast renderers are no different to the original renderers. However, they are currently
experimental and can only be used by adding the following line of code to your MainActivity class before calling
Forms.Init :
Forms.SetFlags("FastRenderers_Experimental");
NOTE
Fast renderers are only applicable to the app compat Android backend, so this setting will be ignored on pre-app compat
activities.
Performance improvements will vary for each application, depending upon the complexity of the layout. For
example, performance improvements of x2 are possible when scrolling through a ListView containing thousands
of rows of data, where the cells in each row are made of controls that use fast renderers, which results in visibly
smoother scrolling.
Related Links
Custom Renderers
.NET Standard 2.0 Support in Xamarin.Forms
3/8/2019 • 2 minutes to read • Edit Online
This article explains how to convert a Xamarin.Forms application to use .NET Standard 2.0.
.NET Standard is a specification of .NET APIs that are intended to be available on all .NET implementations. It
makes it easier to share code across desktop applications, mobile apps and games, and cloud services, by bringing
identical APIs to the different platforms. For information about the platforms supported by .NET Standard, see
.NET implementation support.
.NET Standard libraries are the replacement for Portable Class Libraries (PCL ). However, a library that targets .NET
Standard is still a PCL, and is referred to as a .NET Standard-based PCL. Certain PCL profiles are mapped to .NET
Standard versions, and for profiles that have a mapping, the two library types will be able to reference each other.
For more information, see PCL compatibility.
Xamarin.Forms 2.4 allows Xamarin.Forms applications to target .NET Standard 2.0 by replacing the PCL with a
.NET Standard 2.0 library. This can be achieved as follows:
Ensure .NET Core 2.0 is installed.
Update the Xamarin.Forms solution to use Xamarin.Forms 2.4, or greater.
Add a .NET Standard library to the solution, that targets .NET Standard 2.0.
Delete the class that's added to the .NET Standard library.
Add the Xamarin.Forms 2.4 (or greater) NuGet package to the .NET Standard library.
In the platform projects, add a reference to the .NET Standard library and remove the reference to the PCL
project that contains the Xamarin.Forms user interface logic.
Copy the files from the PCL project to the .NET Standard library.
Remove the PCL project that contains the Xamarin.Forms user interface logic.
Related Links
.NET Standard
Code Sharing Options
Troubleshooting
4/12/2018 • 2 minutes to read • Edit Online
This error may occur if you attempt to update all the packages.
This is because with Android projects set to a target/compile version of Android 6.0 (API 23) or below,
Xamarin.Forms has a hard dependency on specific versions of the Android support packages. Although updated
versions of those packages may be available, Xamarin.Forms is not necessarily compatible with them.
In this case you should update only the Xamarin.Forms package as this will ensure that the dependencies remain
on compatible versions. Other packages that you have added to your project may also be updated individually as
long as they do not cause the Android support packages to update.
NOTE
If you are using Xamarin.Forms 2.3.4 or higher and your Android project's target/compile version is set to Android 7.0 (API
24) or higher, then the hard dependencies mentioned above no longer apply and you may update the support packages
independently of the Xamarin.Forms package.
Why doesn't the Visual Studio XAML designer work for Xamarin.Forms
XAML files?
Xamarin.Forms doesn't currently support visual designers for XAML files.
This guide uses the Xamarin.Forms .NET Standard library template as an example, but the same general method
will also work for the Xamarin.Forms Shared Project template. This guide is written with the example of updating
from Xamarin.Forms 1.5.1.6471 to 2.1.0.6529, but the same steps are possible to set other versions as the default
instead.
1. Copy the original template .zip from:
4. Change the "name" element of the main multi-project template file ( Xamarin.Forms.PCL.vstemplate ) to make
it unique. For example:
5. Re-zip the whole template folder. Make sure to match the original file structure of the .zip file. The
Xamarin.Forms.PCL.vstemplate file should be at the top of the .zip file, not within any folders.
6. Create a "Mobile Apps" subdirectory in your per-user Visual Studio templates folder:
7. Copy the new zipped-up template folder into the new "Mobile Apps" directory.
8. Download the NuGet package that matches the version from step 3. For example,
http://nuget.org/api/v2/package/Xamarin.Forms/2.1.0.6529 (see also
https://stackoverflow.com/questions/8597375/how -to-get-the-url-of-a-nupkg-file), and copy it into the
appropriate subfolder of the Xamarin Visual Studio extensions folder:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Xamarin\Xamarin\[Xamarin
Version]\Packages
Why doesn't the Visual Studio XAML designer work
for Xamarin.Forms XAML files?
5/24/2018 • 2 minutes to read • Edit Online
Xamarin.Forms doesn't currently support visual designers for XAML files. Because of this, when trying to open a
Forms XAML file in either Visual Studio's XAML UI Designer or XAML UI Designer with Encoding, the following
error message is thrown:
"The file cannot be opened with the selected editor. Please choose another editor."
This limitation is described in the Overview section of the Xamarin.Forms XAML Basics guide:
"There is not yet a visual designer for generating XAML in Xamarin.Forms applications, so all XAML must be
hand-written."
However, the Xamarin.Forms XAML Previewer can be displayed by selecting the View > Other Windows >
Xamarin.Forms Previewer menu option.
Android build error – The LinkAssemblies task failed
unexpectedly
3/8/2019 • 2 minutes to read • Edit Online
You may see an error message The "LinkAssemblies" task failed unexpectedly when building a Xamarin.Android
project that uses Forms. This happens when the linker is active (typically on a Release build to reduce the size of
the app package); and it occurs because the Android targets aren't updated to the latest framework. (More
information: Xamarin.Forms for Android Requirements)
The resolution to this issue is to make sure you have the latest supported Android SDK versions, and set the
Target Framework to the latest installed platform. It's also recommended that you set the Target Android
Version to the latest installed platform, and the minimum Android version to API 19 or higher. This is
considered the supported configuration.
This error may be seen in the Error pad of Visual Studio for Mac or in the Build Output window of Visual Studio; in
Android projects using Xamarin.Forms.Maps.
This is most commonly resolved by increasing the Java Heap Size for your Xamarin.Android project. Follow these
steps to increase the heap size:
Visual Studio
1. Right-click the Android project & open the project options.
2. Go to Android Options -> Advanced
3. In the Java heap size text box enter 1G.
4. Rebuild the project.
Samples
The samples are available on github, and include projects for iOS, Android, and the Universal Windows Platform
(UWP ). (Xamarin.Forms no longer supports Windows 10 Mobile, but Xamarin.Forms applications will run on the
Windows 10 desktop.)
Chapter summaries
Chapter summaries are available in the chapter table show below. These summaries describe the contents of each
chapter, and include several types of links:
Links to the actual chapters of the book (at the bottom of the page), and to related articles
Links to all the samples in the xamarin-forms-book-samples GitHub repository
Links to the API documentation for more detailed descriptions of Xamarin.Forms classes, structures,
properties, enumerations, and so forth
These summaries also indicate when material in the chapter might be somewhat outdated.
Samples
In the xamarin-forms-book-samples GitHub repository, the original-code-from -book branch contains
program samples consistent with the book. The master branch contains projects that have been upgraded to
remove deprecated APIs and reflect enhanced APIs. In addition, the Android projects in the master branch have
been upgraded for Android Material Design via AppCompat and will generally display black text on a white
background.
Related Links
MS Press blog
Sample code from book
Enterprise Application Patterns using Xamarin.Forms
eBook
11/11/2018 • 4 minutes to read • Edit Online
Architectural guidance for developing adaptable, maintainable, and testable Xamarin.Forms enterprise
applications
This eBook provides guidance on how to implement the Model-View -ViewModel (MVVM ) pattern, dependency
injection, navigation, validation, and configuration management, while maintaining loose coupling. In addition,
there's also guidance on performing authentication and authorization with IdentityServer, accessing data from
containerized microservices, and unit testing.
Preface
This chapter explains the purpose and scope of the guide, and who it's aimed at.
Introduction
Developers of enterprise apps face several challenges that can alter the architecture of the app during
development. Therefore, it's important to build an app so that it can be modified or extended over time. Designing
for such adaptability can be difficult, but typically involves partitioning an app into discrete, loosely coupled
components that can be easily integrated together into an app.
MVVM
The Model-View -ViewModel (MVVM ) pattern helps to cleanly separate the business and presentation logic of an
application from its user interface (UI). Maintaining a clean separation between application logic and the UI helps
to address numerous development issues and can make an application easier to test, maintain, and evolve. It can
also greatly improve code re-use opportunities and allows developers and UI designers to more easily collaborate
when developing their respective parts of an app.
Dependency Injection
Dependency injection enables decoupling of concrete types from the code that depends on these types. It typically
uses a container that holds a list of registrations and mappings between interfaces and abstract types, and the
concrete types that implement or extend these types.
Dependency injection containers reduce the coupling between objects by providing a facility to instantiate class
instances and manage their lifetime based on the configuration of the container. During the objects creation, the
container injects any dependencies that the object requires into it. If those dependencies have not yet been created,
the container creates and resolves their dependencies first.
Communicating Between Loosely Coupled Components
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 components, while also allowing components to be independently developed and tested.
Navigation
Xamarin.Forms includes support for page navigation, which typically results from the user's interaction with the UI,
or from the app itself, as a result of internal logic-driven state changes. However, navigation can be complex to
implement in apps that use the MVVM pattern.
This chapter presents a NavigationService class, which is used to perform view model-first navigation from view
models. Placing navigation logic in view model classes means that the logic can be exercised through automated
tests. In addition, the view model can then implement logic to control navigation to ensure that certain business
rules are enforced.
Validation
Any app that accepts input from users should ensure that the input is valid. Without validation, a user can supply
data that causes the app to fail. Validation enforces business rules, and prevents an attacker from injecting
malicious data.
In the context of the Model-View -ViewModel (MVVM ) pattern, a view model or model will often be required to
perform data validation and signal any validation errors to the view so that the user can correct them.
Configuration Management
Settings allow the separation of data that configures the behavior of an app from the code, allowing the behavior to
be changed without rebuilding the app. App settings are data that an app creates and manages, and user settings
are the customizable settings of an app that affect the behavior of the app and don't require frequent re-
adjustment.
Containerized Microservices
Microservices offer an approach to application development and deployment that's suited to the agility, scale, and
reliability requirements of modern cloud applications. One of the main advantages of microservices is that they can
be scaled-out independently, which means that a specific functional area can be scaled that requires more
processing power or network bandwidth to support demand, without unnecessarily scaling areas of the application
that are not experiencing increased demand.
Unit Testing
Testing models and view models from MVVM applications is identical to testing any other classes, and the same
tools and techniques can be used. However, there are some patterns that are typical to model and view model
classes, that can benefit from specific unit testing techniques.
Feedback
This project has a community site, on which you can post questions, and provide feedback. The community site is
located on GitHub. Alternatively, feedback about the eBook can be emailed to dotnet-architecture-ebooks-
[email protected].
Related Links
Download eBook (2Mb PDF )
eShopOnContainers (GitHub) (sample)
SkiaSharp Graphics in Xamarin.Forms
12/7/2018 • 2 minutes to read • Edit Online
SkiaSharp Preliminaries
SkiaSharp for Xamarin.Forms is packaged as a NuGet package. After you've created a Xamarin.Forms solution in
Visual Studio or Visual Studio for Mac, you can use the NuGet package manager to search for the
SkiaSharp.Views.Forms package and add it to your solution. If you check the References section of each
project after adding SkiaSharp, you can see that various SkiaSharp libraries have been added to each of the
projects in the solution.
If your Xamarin.Forms application targets iOS, use the project properties page to change the minimum
deployment target to iOS 8.0.
In any C# page that uses SkiaSharp you'll want to include a using directive for the SkiaSharp namespace, which
encompasses all the SkiaSharp classes, structures, and enumerations that you'll use in your graphics
programming. You'll also want a using directive for the SkiaSharp.Views.Forms namespace for the classes
specific to Xamarin.Forms. This is a much smaller namespace, with the most important class being SKCanvasView .
This class derives from the Xamarin.Forms View class and hosts your SkiaSharp graphics output.
IMPORTANT
The SkiaSharp.Views.Forms namespace also contains an SKGLView class that derives from View but uses OpenGL for
rendering graphics. For purposes of simplicity, this guide restricts itself to SKCanvasView , but using SKGLView instead is
quite similar.
SkiaSharp Transforms
Transforms allow graphics objects to be uniformly translated, scaled, rotated, or skewed. This article also shows
how you can use a standard 3-by-3 transform matrix for creating non-affine transforms and applying transforms
to paths.
SkiaSharp Bitmaps
Bitmaps are rectangular arrays of bits corresponding to the pixels of a display device. This series of articles shows
how to load, save, display, create, draw on, animate, and access the bits of SkiaSharp bitmaps.
SkiaSharp Effects
Effects are properties that alter the normal display of graphics, including linear and circular gradients, bitmap
tiling, blend modes, blur, and others.
Related Links
SkiaSharp APIs
SkiaSharpFormsDemos (sample)
SkiaSharp with Xamarin.Forms Webinar (video)