Exercise 1: Driving behavior through properties (XAM320)
In this exercise, you'll add in selection support, and use data triggers to change the UI based on property values exposed in view models.
To complete the exercise, you will need Visual Studio for Windows or macOS with the Xamarin development tools installed. You will also need either an emulator/simulator or a device to run the exercise on. Please see the setup page if you need help installing the Xamarin development environment.
Open the starter solution
Open the starter solution from the Exercise 1 > Start folder in your copy of the cloned or downloaded course materials in either Visual Studio on Windows or Visual Studio for Mac.
Build and run the application to make sure it is working before making changes. It displays quotes using an XML data file as the backing storage. There are two projects that implement the data infrastructure:
-
GreatQuotes
This is the shared PCL which contains the XAML pages, converters and common data structures used in the application. The common data used is in the Data folder and consists of three files:
- GreatQuote.cs is a model class for a single quote.
- IQuoteLoader.cs is an interface which is implemented by the QuoteLoader class in the shared project which is used to load and save the quotes to an XML file.
- QuoteManager.cs is a static class with two static methods to load and save the quotes. It resolves IQuoteLoader from the Xamarin.Forms Dependency Service.
-
GreatQuotes.Data
This is a Shared Project which contains a single source file to load the quotes from an XML file.
-
QuoteLoader.cs is a static class which implements the
IQuoteLoader
interface. It uses compiler directives to split up the platform specific code. This class is loaded into the Xamarin.Forms Dependency Service.
-
QuoteLoader.cs is a static class which implements the
Add selection support
Your first step is to add some property support for selection.
- Open the
MainViewModel
and add a new public property of typeQuoteViewModel
named SelectedQuote. Use a public getter and setter, and use a backing field. -
Make sure to implement property change notification when setting the new property - as a quick shortcut, you can use the
SetPropertyValue
method from the base view model - this will set the underlying field and raise a property change notification for you. It has the form:SetPropertyValue<T>(ref T field, T newValue);
QuoteViewModel selectedQuote; public QuoteViewModel SelectedQuote { get { return selectedQuote; } set { SetPropertyValue(ref selectedQuote, value); } }
-
Next, let's use the property. Open the QuoteListPage.xaml file and locate the
ListView
. Add a new property binding for theSelectedItem
property to the view model property. Use a two-way binding (Mode
property). Leave theItemTapped
event handler in place, you still need that for the moment to handle navigation.<ListView ItemsSource="{Binding Quotes}" SelectedItem="{Binding SelectedQuote, Mode=TwoWay}" ItemTapped="OnQuoteSelected">
-
Next, open the code behind file (QuoteListPage.xaml.cs) and locate the
OnQuoteSelected
method. It's currently passing the tapped item to theQuoteDetailPage
as part of the constructor. Remove the parameter, you don't need it anymore as long as the second page has access to the view model! - Finally, open the QuoteDetailPage.xaml.cs file and fix the constructor to not take the parameter. Instead, change the
BindingContext
to be theSelectedQuote
property of theMainViewModel
. Remember the view model is a singleton exposed by theApp
class. - Run the application and make sure it still works properly - it should correctly navigate and still display the quote details when it's on the second screen. However, there is a minor, but annoying bug on some platforms. When you return to the original screen, the
ListView
still shows selection and the cell you tapped on is highlighted. Let's fix that. - In the
QuoteDetailPage
constructor, clear theSelectedQuote
property (set it tonull
) after you set theBindingContext
. This will clear theListView
selection. - Run the app again to verify the change.
Use DataTriggers
If you examine the QuoteListPage
or QuoteDetailPage
XAML, you will find it uses a value converter named GenderToColorConverter
which is located in the Converters folder. This is located in the application resources and reused on both pages. You're going to remove it from the second page.
- Open the
QuoteDetailPage
XAML file and locate theLabel
which displays the author name. - Change the
TextColor
property to just be "Blue" and remove the binding. Now all quote authors will be in blue. - Add a
DataTrigger
to theLabel
which changes theTextColor
property when theGender
isGender.Female
. Refer to the slides if you need some guidance, or check the code hint below. - Run the application and navigate to the Eleanor Roosevelt quote. The quote author at the bottom of the page should be in pink.
- You might want to use the same technique on the
QuoteListPage
as well - however it won't work there. That's using aTextCell
to display the quote - and unfortunately,TextCell
does not derive fromVisualElement
where the trigger support lives. So, it will either need to be changed to aViewCell
with a fullLabel
(which is less efficient thanTextCell
), or continue using a converter. Here, you've chosen the latter as it doesn't hurt anything, however you could try the former if you have some extra time.
<Label Grid.Row="1" Text="{Binding Author}"
TextColor="Blue"
HorizontalOptions="End" HorizontalTextAlignment="End">
<Label.Triggers>
<DataTrigger TargetType="Label"
Binding="{Binding Gender}"
Value="Female">
<Setter Property="TextColor" Value="Pink" />
</DataTrigger>
</Label.Triggers>
</Label>
Exercise summary
In this exercise, you've pushed the selection management into the view model and started removing value converters, instead relying on properties with triggers to control the visual properties.
You can view the completed solution in the Exercise 1 > Completed folder of your copy of the cloned or downloaded course materials.