There are two approaches for data binding each of which has merits depending on the situation. The first is MVVM as mentioned previously. This works well for fields that your ViewModel should know about, such as the text in an entry field but this isn't always the case and it's important to have a complete understanding before choosing the right method for your needs.
MVVM Approach
ViewModel
public class MyPageViewModel : INotifyPropertyChanged
{
private string myTextField;
public string MyTextField
{
get { return myTextField; }
set
{
if( !myTextField.Equals( value ) )
{
myTextField = value;
OnPropertyChanged("MyTextField");
}
}
}
}
View
<?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="SandboxForms.Pages.MainPage"
xmlns:viewmodels="clr-namespace:SandboxForms.ViewModels;SandboxForms">
<ContentPage.BindingContext>
<viewmodels:MainPageViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout Padding="20">
<!-- I am applying EndAndExpand to the entry and
StartAndExpand to the label to center them each other -->
<Entry
HorizontalOptions="FillAndExpand"
VerticalOptions="EndAndExpand"
Placeholder="Write here and see the magic!!!"
Text="{Binding MyTextField}"/>
<Label
HorizontalTextAlignment="End"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand"
Text="{Binding MyTextField}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
This is generally a preferred approach by most developers as opposed to mixing business logic directly in the code behind of your UI.
There are a number of helpers, and frameworks out there that you can look at if you aren't familiar with this. The following are some of the more popular ones.
- MvvmHelpers - James Montemagno
- Prism Library (my personal favorite)
- Mvvm Cross
- Mvvm Light
View Centric Approach
Sometimes it actually would violate the MVVM pattern to directly bind to a property of our ViewModel, and other times we may want to display something in our View without the need of updating a backing field in the ViewModel. As an example we can look at Xamarin's guide to data binding.
<?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="XamlSamples.SliderBindingsPage"
Title="Slider Bindings Page">
<StackLayout>
<Label Text="ROTATION"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
<Label BindingContext="{x:Reference slider}"
Text="{Binding Value,
StringFormat='The angle is {0:F0} degrees'}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
I should note that one of the most common times I would recommend using this approach is with Context Actions in a ListView, since our ViewModel may contain the Command that we want to execute on the individual cell, however the cell in which we are executing the context action actually is bound to the object from our IEnumerable<T>
and not our ViewModel. In this particular case we would do something like the following:
<?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:Name="someListPage"
x:Class="MyApp.Views.SomeListPage">
<ListView ItemsSource="{Binding Gear}"
CachingStrategy="RecycleElement"
IsRefreshing="{Binding IsRefreshing}"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Description}" Detail="{Binding Detail}">
<TextCell.ContextActions>
<MenuItem Text="Remove"
Command="{Binding BindingContext.RemoveItemCommand,Source={x:Reference someListPage}}"
CommandParameter="{Binding .}"
IsDestructive="True" />
</TextCell.ContextActions>
</TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
You'll notice that for this to work we first give the page itself a name that we can then reference for our binding for the ContextAction
Command property. This is only changing where we are looking for this single property. We then resume using the normal binding context for the CommandParameter property and pass in the actual object the cell is bound to with {Binding .}
Hope this helps you better understand your options for binding with Xaml. Happy Coding!