In our last post (Creating Device-Specific Properties in Cross-Platform Apps with Xamarin Forms) we looked at how we can leverage Page Resources to create device-specific properties that can be reused across the page. Today we'll look at how we can convert these and other reusable property definitions to global resources so that all of an apps resources can be maintained from a single location.
No App.xaml? Static Classes to the Rescue!
XAML apps such as for Windows an Windows Phone exposes a global App.xaml file which compiles along with the application. This allows you to define resources declaratively with XAML at the App level so that they are available globally across the application. However, Xamarin Forms does not appear to support this global xaml definition, nor is there a global Resources property to which we can add items, so we'll need to use a different strategy. This approach relies on the x:Static markup extension of Xamarin Forms, which allows you to bind control properties to static classes and static properties. By defining and exposing global properties through static classes, these properties can be maintained separately from the individual XAML pages and accessed globally throughout the application. For more details and examples on this approach take a look at the section titled "The x:Static Markup Extension" from the Xamarin document here: Part 3. XAML Markup Extensions. For my app, I've decided to define the properties in different static classes, one for each type of property, such as Font, Padding, and Color. This way it's easy to locate the class to update a specific property. Here is a copy of the FontResources class I've defined, which as you can see recreates the Font property from our last post. By using the static Device.OnPlatform method, we can recreate the ability to render a different value for each device, specifying the arguments for iOS, Android, and Windows Phone in that order.
public static class FontResources {
public static readonly Font Title = Font.SystemFontOfSize(42);
public static readonly Font Header = Font.SystemFontOfSize(Device.OnPlatform(16, 16, 26));
public static readonly Font Subheader = Font.SystemFontOfSize(Device.OnPlatform(12, 14, 24));
public static readonly Font Standard = Font.SystemFontOfSize(Device.OnPlatform(12, 12, 22));
public static readonly Font Small = Font.SystemFontOfSize(Device.OnPlatform(10, 10, 16));
public static readonly Font Button = Font.SystemFontOfSize(Device.OnPlatform(11, 11, 18));
}
This method is available for several different property types, such as color. Here I've created a ColorResources class which allows us to define platform-specific colors for each device.
public static class ColorResources { public static readonly Color ListTextColor = Device.OnPlatform(Color.Blue, Color.Green, Color.Red); }
To use these properties, simply bind the intended property using there x:Static method:
<StackLayout Orientation="Horizontal" VerticalOptions="Center"> <Label Text="{Binding Name}" HorizontalOptions="FillAndExpand" Font="{x:Static common:FontResources.Standard}" TextColor="{x:Static common:ColorResources.ListTextColor}" /> <Label Text="{Binding Location}" HorizontalOptions="End" Font="{x:Static common:FontResources.Standard}" TextColor="{x:Static common:ColorResources.ListTextColor}" /> </StackLayout>
Because these are defined globally, updating them is as simple as changing the values defined in the static classes. By creating and binding to a static color property value, we are able to easily specify a different color for each device with only a single line of code.
Wrapping Up and Next Steps
Thanks to the resources and other Xamarin properties and helpers, we've created a more consistent visual experience for the user, and can even add device-specific properties such as color and layout.
Get the CODE!
However, we are still missing some important behavior to give our users a better user experience. In our next post, we'll look at how easily we can add a Loading indicator as well as automatically refreshing the lists when changes are made. Until then, as always, I hope this is helpful!
Enjoyed this post and/or found it useful?