Xaml v Code

I still see a fair amount of Xamarin Forms UI written in C# code. If you are not that familiar with Xaml then it may seem to make sense to code up your views this way, but you will be missing out on the benefits of Xaml. Not only that but there are some really exciting new features which make Xaml an even better way to express your views which I will discuss shortly.

I was going to define the benefits of Xaml but Charles Petzold has done a great job in the Preview of his forthcoming book, Creating Mobile Apps with Xamarin.Forms. There are some great chapters on Xaml and his ‘Xaml v Code’ chapter succinctly sums up why we should all be using Xaml rather than code.

“You will find that XAML provides a more succinct and elegant definition of the user interface, and has a visual structure that better mimics the tree organisation of the visual elements on the page. XAML is also generally easier to maintain and modify than equivalent code. “

I would go further and say that, with regards to MVVM in particular, Xaml defines the template for the view, which is a visualisation of your view model. This template should be expressed in markup in much the same way that we define views in the html. It provides a much more expressive way to ‘declare’ the view in a way that allows you to lay it out in a declarative manner, rather than imperatively in code. A code-based approach tends to lead the developer to ‘program’ the layout with logic, which might include loops or conditional code mingled with the layout code. With Xaml the declarative approach allows you to focus on the layout and provide better reusable solutions where logic is required in the form of behaviours, markup extensions and converters. It also allows you to think more clearly about the bindings and the relationship with the view model. Further more Xaml allows you to define data bindings and express properties in a much more succinct manner.

For example in code you can not define bindings in-line with the layout like this.

    Content = new StackLayout
    {
        Orientation = StackOrientation.Horizontal,
        Children =
        {
            new Label
            {
                Text = ?? can not bind here
            }
        }
    };

You have to create the label as a separate variable so that you can call SetBinding and then add that variable into the layout like this.

    var label = new Label();
    label.SetBinding(Label.TextProperty, new Binding("Name"));

    Content = new StackLayout
    {
        Orientation = StackOrientation.Horizontal,
        Children =
        {
            label
        }
    };

This I find very irritating and before long you have some very unwieldy code. In Xaml bindings are defined right in the property declaration so everything fits very neatly into layout declaration like this:

    <StackLayout Orientation="Horizontal">
      <Label Text="{Binding Name}" />
    </StackLayout> 

I’m sure you’ll agree that this is more succinct and easier to follow that the code above.

I come from a WPF background. I know that most WPF developers would find it very strange and perhaps be horrified to find anyone trying to define all their views in code. A receipt for disaster almost as your application and complexity grows.

I think one of the reasons why some developers have adopted the code approach is due to many of the early examples being code based due to the lack of intellisense and tooling support for Xaml with Xamarin Forms. This is no longer the case. Xamarin Studio has, since I’ve used it, always provided intellisense for Xaml. Visual Studio now has first class intellisense support with the release of the Xamarin Mobile Essentials Productivity Tools. If you haven’t already installed this then do so now. In additional if you are a R# user, which I strongly recommended for your own sake, it also provides fantastic tooling and intellisense support in the Xaml editor. Namespaces are auto resolved, advanced colour picker for colour selection, code correction and warnings all feature in the editor. In fact it is as good as you would get in WPF.

One other thing that I discovered recently which I am very excited about is support for intellisense for bindings. By that I mean the ability to explore the properties that are available to you on the type that your view will be bound to through its binding context. In WPF this is done using the following declaration:

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Silkweb.Mobile.MountainWeather.ViewModels;assembly=Silkweb.Mobile.MountainWeather"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=viewModels:ForecastViewModel, IsDesignTimeCreatable=False}"

If you are not familiar with this the d: namespace provides some design-time support features, one of which is to define a design time data context for the type you will be binding to. The mc: namespace provides an Ignorable property that allows you to tell the xaml parser to ignore certain namespaces at runtime, namely the d: namespace. This all works in WPF and it also works in Xamarin Forms in design time to. However at runtime you will get an compilation error saying Markup Extension not found for d:DesignInstance.

Fortunately this has now been resolved with the help of Xaml Conditional Compilation (xcc) by firstfloorsoftware. You can find more about this on this forum post, which got me very exited about this feature. I followed the helpful Xamarin Forms how to. One additional thing you need to do though that I discovered here is you need to add the following Property Definition into any projects where you’re Xaml exists.

<XccRemoveIgnorableContent>True</XccRemoveIgnorableContent>

(Note: Make sure you follow this here).

I’m note sure why this isn’t documented or added as part of the install, but I guess this is very early days for this feature.

With this in place and the above namespaces and Design Instance defined I can now define Binding expressions and browse the types properties like this:

1
Even better I can even explore nested Properties of complex property types like this:

Screen Shot 2015-03-17 at 22.37.07

And if any of the bindings are invalid I get a warning with a squiggly line like this:

2

This is something you don’t even get if you try to define bindings in code, where you are restricted to using magic strings.

There is of course no designer yet for Xamarin Forms, but I don’t see that as an issue really. I never use the designer much in WPF really, preferring to define the Xaml by hand, similarly to how you would define Html in the web world. The designer is occasionally useful but it’s actually much easier to visualise what you are doing simply by looking at the Xaml. This can not be done quite so easily in code.

If you are still defining your views in code then you should consider embracing Xaml and it’s benefits. It will actually make you a better developer.

Xamarin Forms Succinctly, by Syncfusion

In my earlier post I reviewed Charting using Syncfusion Essential Studio for Xamarin Forms. I also discovered that Syncfusion have put together Xamarin Forms Succinctly, which is part of the Syncfusion Succinctly series.

Screen Shot 2015-03-11 at 21.39.58

Written by Derek Jenson, the Xamarin Forms Succinctly ebook can be downloaded for free here. It provides a great introduction to Xamarin Forms and offers an excellent chapter on Xaml, Pages and Views which I feel is currently lacking in the Xamarin Forms documentation. My only criticism is that it seems to have been written pre 1.3 which introduced the Application class and ditched the GetMainPage method. That said most of the content is well worthy of a read. I certainly found it useful and learnt some things along the way.

Download Xamarin Forms Succinctly here.

Grouping with ListView and TableView and the TableViewItemsSourceBehavior

When I select a mountain area in my weather App I want to display a list of options. These options will include forecasts, weather observations at various weather stations, avalanche and other information. I’d like to group these and display this using the native grouping features for each platform.

Both Xamarin Forms ListView and TableView have the ability to group data. I will explore both these options and show how we can create one view model structure that will cater for both approaches.

ListView allows data to be grouped, and optionally includes jump lists for quick navigation. James Montemagno from Xamarin provides us with an excellent example on how to do this here.

I took my inspiration for his generic Grouping class to create my own view model called, unsurprisingly, GroupViewModel.

    public class GroupViewModel<TKey, TItem> : ObservableCollection<TItem>
    {
        public TKey Key { get; private set; }

        public GroupViewModel(TKey key, IEnumerable<TItem> items)
        {
            Key = key;
            if (items != null)
                foreach (var item in items)
                    Items.Add(item);
        }
    }

I want each item to have a Title and a Command that I can execute when selected, so I created the following IItemViewModel.

    public interface IItemViewModel
    {
        string Title { get; set; }

        ICommand Command { get; set; }
    }

Now I can create an ItemsGroupViewModel of IItemViewModel like this, which is keyed by a string.

    public class ItemGroupViewModel : GroupViewModel<string, IItemViewModel>
    {
        public ItemGroupViewModel(string key, IEnumerable<IItemViewModel> items = null)
            : base(key, items)
        {
        }
    }

I also want to associate an object with the item view model, which might differ for each item, so I created the following generic implementation of the above interface, which adds an Items property.

    public class ItemViewModel<T> : ViewModelBase, IItemViewModel
    {
        public ItemViewModel(string title, Action<T> action, T item)
        {
            Title = title;
            Item = item;
            Command = new Command<T>(action);
        }

        public ICommand Command { get; set; }

        public T Item { get; set; }
    }
 

This allows me to add any type of ItemViewModel to the group, or groups.

Next I need a View Model to represent a list of groups, which also needs to include a page title to display for the groups called ItemGroupsViewModel.

    public class ItemGroupsViewModel : ViewModelBase 
    {
        public ItemGroupsViewModel(string title)
        {
            Title = title;
        }

        public IEnumerable<ItemGroupViewModel> Groups { get; set; }
    }

Now in my MountainAreaViewModel all I need to do is to create a list of options, which I can display when a mountain area is selected.

public ItemsViewModel Options { get; set; }

private void Initialise()
{
    var groups = new List<ItemGroupViewModel>
    {
        new ItemGroupViewModel("Forecasts")
        {
            new ItemViewModel<ForecastReportViewModel>("Met Office 5 day forecast", ShowForecast, ForecastReport),
            new ItemViewModel<SummitForecastViewModel>("Met Office Summit Forecasts", ShowSummitForecast, SummitForecast),
            new ItemViewModel<MWISForecastViewModel>("MWIS Weather Forecast", ShowMWISForecast, MWISForecast)
        },
        new ItemGroupViewModel("Other")
        {
            new ItemViewModel<AvalancheReportViewModel>("Sais Avalanche Report", ShowAvalancheForecast, AvalancheReport),
            new ItemViewModel<AreaInfoViewModel>("Area Info", ShowAreaInfo, AreaInfo)
        }
    };

    var locations = _observationService.GetAreaObservationLocations(_location.Id);
    if (locations != null)
    {
        groups.Insert(1, new ItemGroupViewModel("Weather Stations", 
            locations.Select(location => new ItemViewModel<ObservationLocation>(location.Name,
            ShowObservations, location))));
    }

    Options = new ItemGroupsViewModel("Options") { Groups = groups };
}

Assume here that my observationService returns a list of weather observation locations, which I then use to create a grouped list of weather stations. Notice that each item calls one of the methods, ShowForecast, ShowObservations etc, which are passed as an action to the ItemViewModel.

And finally I create a view displaying a ListView with its ItemSource bound to the Options property and ground by Key.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:Silkweb.Mobile.Core.Views;assembly=Silkweb.Mobile.Core"
             x:Class="Silkweb.Mobile.MountainWeather.Views.ItemsView"
             Title="{Binding Title}">
  <ListView ItemsSource="{Binding Groups}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
            IsGroupingEnabled="True"
            GroupDisplayBinding="{Binding Key}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <views:TextCellExtended Text="{Binding Title}"
                                ShowDisclosure="True" Command="{Binding Command}" CommandParameter="{Binding Item}" />
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</ContentPage>

Notice here that I am also using the TextCellExtended, which allows me to display the disclosure chevron to indicate more items.

Running this in my app I can now see the following options when I select a weather area.

Screen Shot 2015-03-10 at 21.35.18

This is great, but it’s actually not quite what I wanted. I want the options to be displayed more like they are in the settings of the phone, which look more like this.

Screen Shot 2015-03-09 at 22.44.37

Notice here the groupings spaced out with a header. TableView allows us to create this kind of layout, defining TableSections for each group. Unfortunately TableView does not provide an ItemsSource property that allows it to bind to a list or items. You have to define each TableSection manually either in Xaml or in code. This got me thinking about creating a Behavior that would do this dynamically. What I need is a behavior that can bind to the above ItemGroupsViewModel and create the TableSections. This behavior also needs to be able to define an ItemTemplate property that defines the template for each item. I therefore created the following TableViewItemsSourceBehavior.

    public class TableViewItemsSourceBehavior : BindableBehavior<TableView>
    {
        public static readonly BindableProperty ItemsSourceProperty =
            BindableProperty.Create<TableViewItemsSourceBehavior, IEnumerable<ItemGroupViewModel>>(p => p.ItemGroupsSource, null, BindingMode.Default, null, ItemsSourceChanged);

        public IEnumerable<ItemGroupViewModel> ItemGroupsSource
        {
            get { return (IEnumerable<ItemGroupViewModel>)GetValue(ItemsSourceProperty); } 
            set { SetValue(ItemsSourceProperty, value); } 
        }

        public static readonly BindableProperty ItemTemplateProperty =
            BindableProperty.Create<TableViewItemsSourceBehavior, DataTemplate>(p => p.ItemTemplate, null);

        public DataTemplate ItemTemplate
        { 
            get { return (DataTemplate)GetValue(ItemTemplateProperty); } 
            set { SetValue(ItemTemplateProperty, value); } 
        }

        private static void ItemsSourceChanged(BindableObject bindable, IEnumerable<ItemGroupViewModel> oldValue, IEnumerable<ItemGroupViewModel> newValue)
        {
            var behavior = bindable as TableViewItemsSourceBehavior;
            if (behavior == null) return;
            behavior.SetItems();
        }

        private void SetItems()
        {
            if (ItemGroupsSource == null) return;

            AssociatedObject.Root.Clear();

            foreach (var group in ItemGroupsSource)
            {
                var tableSection = new TableSection { Title = group.Key };

                foreach (var itemViewModel in group)
                {
                    var content = ItemTemplate.CreateContent();
                    var cell = content as Cell;
                    if (cell == null) continue;
                    cell.BindingContext = itemViewModel;
                    tableSection.Add(cell);
                }

                AssociatedObject.Root.Add(tableSection);
            }
        }
    }

SetItems is called when the ItemsSource property is set. This simply iterates through the groups and creates a TableSection for each group, then iterates through each item and adds a Cell using the ItemTemplate.

You may have noticed that this behavior inherits from BindableBehavior. As you may recall I previously blogged about a bug with the Behavior class, but it turns out this is by design and is now briefly explained at the bottom of the behaviors guide here.

“Sharing Behaviors
Behaviors can be shared between multiple controls because they are easily added to a Style, which in turn can be applied to many controls either explicitly or implicitly.

This means that while you can add bindable properties to a behavior that are set or queried in XAML, if you do create behaviors that have state they should not be shared between controls in a Style in the ResourceDictionary.

This is also why the BindingContext is not set by Xamarin.Forms. User-created behaviors shouldn’t rely on the binding context for accessing data.”

Therefore any behaviors that define BindableProperties need to set the BindingContext on the behavior manually when the behavior is attached to the UI control. I also wanted to mimic the WPF Behavior class by providing an AssociatedObject property for the UI control the behavior belongs to. Here is the BindableBehavior class.

    public class BindableBehavior<T> : Behavior<T> where T : BindableObject
    {
        public T AssociatedObject { get; private set; }

        protected override void OnAttachedTo(T view)
        {
            base.OnAttachedTo(view);

            AssociatedObject = view;

            if (view.BindingContext != null)
                BindingContext = view.BindingContext;

            view.BindingContextChanged += OnTableViewOnBindingContextChanged;
        }

        protected override void OnDetachingFrom(T view)
        {
            view.BindingContextChanged -= OnTableViewOnBindingContextChanged;
        }

        private void OnTableViewOnBindingContextChanged(object sender, EventArgs e)
        {
            BindingContext = AssociatedObject.BindingContext;
        }
    }

This simply manages setting the BindingContext and the AssociatedObject used in the TableViewItemsSourceBehavior. Now lets use this behavior and replace the previous ItemsView with a TableView as follows.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:Silkweb.Mobile.Core.Views;assembly=Silkweb.Mobile.Core"
             xmlns:behaviors="clr-namespace:Silkweb.Mobile.Core.Behaviors;assembly=Silkweb.Mobile.Core"
             x:Class="Silkweb.Mobile.MountainWeather.Views.ItemsView"
             Title="{Binding Title}">

  <TableView Intent="Menu">
      <TableView.Behaviors>
        <behaviors:TableViewItemsSourceBehavior ItemsSource="{Binding Groups}">
          <behaviors:TableViewItemsSourceBehavior.ItemTemplate>
            <DataTemplate>
              <views:TextCellExtended Text="{Binding Title}" ShowDisclosure="True" Command="{Binding Command}" CommandParameter="{Binding Item}" />
            </DataTemplate>
          </behaviors:TableViewItemsSourceBehavior.ItemTemplate>
        </behaviors:TableViewItemsSourceBehavior>
      </TableView.Behaviors>
    </TableView>

</ContentPage>

Here I have set the Intent of the TableView to Menu and added the Behavior which is bound to the Groups property of ItemGroupsViewModel. It also defines the DataTemplate for each item as a TextCellExtended control as before. Now lets run this and see how it looks.

Screen Shot 2015-03-10 at 21.33.30

Now that looks much better and is just what I wanted. I can now easily extend this list of options simply by adding new items to the ItemsGroupViewModel. It is also very easy to choose to use either a ListView or TableView with the help of the TableViewItemsSourceBehavior. This gives me great flexibility and reuse within my application for other grouped lists which I will need to add later.

Charting Weather Observations with Xamarin forms Syncfusion Essential Studio

In my series on creating a Xamarin Forms App I have been developing a Mountain Weather App for UK mountain regions. I want to add weather observations from various weather stations, which provide observational readings over the last 24 hours. This is particularly useful for anyone venturing out in to the mountains, especially in winter when temperature and wind variations provide an indication of conditions. I have been consuming weather data from the Met Office Data Point service. This also provides an excellent data feed of weather observations across the UK, including those provided by weather stations located at various mountain summits. I want to consume and chart this data in my application.

Searching for chart components on the Xamarin Forms Components page reveals the following components currently available.

Screen Shot 2015-03-03 at 07.22.16

I’m only interested in those that cover all platforms and are either free or inexpensive. The Syncfusion Essential Studio looks like the best option here. I have used Syncfusion before with WPF and found their components and support to be very good. The price of $99 also seems extremely good value for what you get, which includes Charts, Gauges, TreeMap and Excel, World and PDF libraries. This can be downloaded from either of the following links.

https://components.xamarin.com/view/SyncfusionEssentialStudio

http://www.syncfusion.com/products/xamarin

You will also find some good documentation in the getting started guide and on line documentation.

Follow these links to add the appropriate references to your solution projects and also take note that you must add the SFChartRenderer to the Windows Phone and iOS projects.

Firstly I need to consume the weather observation data from the Met Office site-specific observations service. (As with the other DataPoint services you will need to obtain an API Key if you are interested in using this service). I’m not going to go into any detail on this as I want this post to focus on the charting. I have created a set of data model classes based on the Json that the service returns. This is easily created in Visual Studio using the File > Paste Special > “Paste Json as Classes” feature. The resulting class model looks like this:

    public class Observations
    {
        public Siterep SiteRep { get; set; }
    }

    public class Siterep
    {
        public Wx Wx { get; set; }
        public DV DV { get; set; }
    }

    public class Wx
    {
        [JsonProperty("Param")]
        public Param[] Elements { get; set; }
    }

    public class Param
    {
        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("units")]
        public string Units { get; set; }

        [JsonProperty("$")]
        public string Description { get; set; }
    }

    public class DV
    {
        [JsonProperty("dataDate")]
        public DateTime DataDate { get; set; }

        [JsonProperty("type")]
        public string Type { get; set; }

        public Location Location { get; set; }
    }

    public class Location
    {
        [JsonProperty("i")]
        public string Id { get; set; }

        [JsonProperty("lat")]
        public string Latitude { get; set; }

        [JsonProperty("lon")]
        public string Longitude { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("country")]
        public string Country { get; set; }

        [JsonProperty("continent")]
        public string Continent { get; set; }

        [JsonProperty("elevation")]
        public string Elevation { get; set; }

        public Period[] Period { get; set; }
    }

    public class Period
    {
        public string type { get; set; }
        public string value { get; set; }
        public Rep[] Rep { get; set; }
    }

    public class Rep
    {
        //WindGust
        public string G { get; set; }

        //Temperature
        public string T { get; set; }

        //Visibility
        public string V { get; set; }

        //WindDirection
        public string D { get; set; }

        //WindSpeed
        public string S { get; set; }

        //WeatherType
        public string W { get; set; }

        //Pressure
        public string P { get; set; }

        //PressureTendency
        public string Pt { get; set; }

        //DewPoint
        public string Dp { get; set; }

        //ScreenRelativeHumidity
        public string H { get; set; }

        [JsonProperty("$")]
        public string Value { get; set; }
    }

As ever I am using an MVVM approach, so now that we have our Model let’s create the View Models. Firstly I want to display a list of the weather elements available for a given site. Each element is represented by the ObservationElementViewModel which I will use to chart each weather element.

    public class ObservationElementViewModel : ViewModelBase
    {
        private readonly INavigator _navigator;

        public ObservationElementViewModel(string location, Param element, INavigator navigator)
        {
            _navigator = navigator;
            Location = location;
            Id = element.Name;
            Name = element.Description;
            Units = element.Units;
            Title = element.Description;
            Observations = new List<ChartDataPoint>();
            ShowObservationsCommand = new Command(ShowObservations);
        }

        private async void ShowObservations()
        {
            await _navigator.PushAsync(this);
        }

        public string Name { get; set; }

        public string Units { get; set; }

        public List<ChartDataPoint> Observations { get; set; }

        public string Location { get; set; }

        public DateTime DateTimeFrom { get; set; }

        public DateTime DateTimeTo { get; set; }

        public ICommand ShowObservationsCommand { get; set; }
    }

The key thing to note here is the Observations property, which is a list of ChartDataPoint objects. ChartDataPoint is a Syncfusion class used to chart a series of data and will be used by the view to bind to the data for the series. There is also a ShowObservationCommand that will be called when an element is tapped and displays the chart using the INavigator class which I discussed in my earlier series. The other properties are for decorating the view with additional data.

The ObservationsViewModel represents the list of elements. This consumes the Siterep model and creates a list of ObservationElementViewModels as follows.

    public class ObservationsViewModel : ViewModelBase
    {
        public ObservationsViewModel(
            Siterep siterep, 
            Func<string, Param, ObservationElementViewModel> observationElementViewModelFactory)
        {
            var siterep1 = siterep;
            Title = siterep1.DV.Location.Name;
            var properties = typeof(Rep).GetRuntimeProperties().ToArray();
            var observations = new Dictionary<string, ObservationElementViewModel>();

            foreach (var period in siterep.DV.Location.Period)
            {
                foreach (var rep in period.Rep)
                {
                    foreach (var property in properties)
                    {
                        var propertyValue = property.GetValue(rep) as string;
                        if (propertyValue == null) continue;

                        double value;
                        if (!double.TryParse(propertyValue, out value))
                            continue;

                        DateTime dateTime = DateTime.Parse(period.value).AddMinutes(int.Parse(rep.Value));
                        var code = property.Name;
                        ObservationElementViewModel observationElementViewModel;

                        if (!observations.TryGetValue(code, out observationElementViewModel))
                        {
                            var element = siterep1.Wx.Elements.FirstOrDefault(x => x.Name == code);
                            if (element == null) continue;

                            observationElementViewModel = observationElementViewModelFactory(siterep1.DV.Location.Name, element);
                            observationElementViewModel.DateTimeFrom = dateTime;
                            observations.Add(code, observationElementViewModel);
                        }
                        else
                            observationElementViewModel.DateTimeTo = dateTime;

                        observationElementViewModel.Observations.Add(new ChartDataPoint(dateTime, value));
                    }
                }
            }

            Observations = observations.Values;
        }

        public IEnumerable<ObservationElementViewModel> Observations { get; set; }
    }

This iterates through the model to create the hourly observations over the last 24 hours for each element. I iterate through each property on the Rep object, create an ObservationElementViewModel for each element and add to the Observations by creating a ChartDataPoint for each element observation.

Now all that’s needed are the views. The list of observations is very simple and is represented by the ObservationsView which looks like this.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:Silkweb.Mobile.Core.Views;assembly=Silkweb.Mobile.Core"
             x:Class="Silkweb.Mobile.MountainWeather.Views.ObservationsView"
             Title="{Binding Title}">
  <Grid>
    <ListView ItemsSource="{Binding Path=Observations}">
      <ListView.ItemTemplate>
        <DataTemplate>
          <views:TextCellExtended ShowDisclosure="True" Command="{Binding ShowObservationsCommand}" Text="{Binding Name}" />
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
  </Grid>
  
</ContentPage>

This simply contains a ListView which binds the ItemsSource to the Observation property on the ObservationsViewModel. The ItemTemplate uses an extended version of a TextCell called TextCellExtended (discussed in my earlier series) which binds it’s command to the ShowObservationsCommand on the ObservationElementViewModel and displays it’s name.

Now let’s create a view to for the chart using Sysncfusion charts called ObservationsChartView. The Xaml for this looks like this:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:chart="clr-namespace:Syncfusion.SfChart.XForms;assembly=Syncfusion.SfChart.XForms"
             x:Class="Silkweb.Mobile.MountainWeather.Views.ObservationsChartView"
             Title="{Binding Title}" Padding="10">

  <StackLayout>
    <Label Text="{Binding Location}" FontSize="Large" TextColor="Accent" HorizontalOptions="Center" />
    <StackLayout Orientation="Horizontal" HorizontalOptions="Center">
      <Label Text="{Binding DateTimeFrom, StringFormat='From {0:HH} hrs on {0:dd/MM}'}" FontSize="Small" />
      <Label Text="{Binding DateTimeTo, StringFormat='To {0:HH} hrs on {0:dd/MM}'}" FontSize="Small" />
    </StackLayout>

    <chart:SfChart VerticalOptions="FillAndExpand">

      <chart:SfChart.PrimaryAxis>
        <chart:DateTimeAxis x:Name="DateAxis" IntervalType="Hours" ShowMajorGridLines="True">

          <chart:DateTimeAxis.MajorGridLineStyle>
            <chart:ChartLineStyle StrokeWidth="1" StrokeColor="#7EDBDBDB" />
          </chart:DateTimeAxis.MajorGridLineStyle>

          <chart:DateTimeAxis.Title>
            <chart:ChartAxisTitle Text="Hour" TextColor="Accent" />
          </chart:DateTimeAxis.Title>

          <chart:DateTimeAxis.LabelStyle>
            <chart:ChartAxisLabelStyle LabelFormat="HH" TextColor="Accent" />
          </chart:DateTimeAxis.LabelStyle>

        </chart:DateTimeAxis>
      </chart:SfChart.PrimaryAxis>

      <chart:SfChart.SecondaryAxis>
        <chart:NumericalAxis ShowMajorGridLines="True">
          <chart:NumericalAxis.MajorGridLineStyle>
            <chart:ChartLineStyle StrokeWidth="1" StrokeColor="#7EDBDBDB" />
          </chart:NumericalAxis.MajorGridLineStyle>

          <chart:NumericalAxis.Title>
            <chart:ChartAxisTitle Text="{Binding Units}" TextColor="Accent" />
          </chart:NumericalAxis.Title>

          <chart:NumericalAxis.LabelStyle>
            <chart:ChartAxisLabelStyle TextColor="Accent" />
          </chart:NumericalAxis.LabelStyle>

        </chart:NumericalAxis>
      </chart:SfChart.SecondaryAxis>

      <chart:SfChart.Series>
        <chart:AreaSeries ItemsSource="{Binding Observations}" Color="#7E9FCCEC" StrokeColor="Accent">
          <chart:AreaSeries.DataMarker>
            <chart:ChartDataMarker MarkerWidth="4" MarkerHeight="4" MarkerColor="Accent" ShowLabel="False" ShowMarker="True" />
          </chart:AreaSeries.DataMarker>
        </chart:AreaSeries>
      </chart:SfChart.Series>
    </chart:SfChart>
  </StackLayout>
</ContentPage>

This uses the Syncfusion SfChart to construct a chart with a DataTime x-Axs and a Numeric y-Axis, with an AreaSeries for the data series. I found this very easy to create and was very impressed with the SfChart object. As you can see it is fairly self-explanatory. Notice the AreaSeries ItemSource is bound to the Observations property of the ObservationElementViewModel and the NumericalAxis Title Text is bound to the Units property. Also note that I have used a StackLayout and some labels to create the title rather than using the Chart title to provide me with a more detailed title showing the location and dates from and to.

Running this in my Weather Application I can now see a list of Elements for a given mountain area.

Screen Shot 2015-03-03 at 22.10.08

And tapping on each element reveals the following charts.

Screen Shot 2015-03-03 at 22.15.44Screen Shot 2015-03-03 at 22.11.26Screen Shot 2015-03-03 at 22.12.15Screen Shot 2015-03-03 at 22.14.32

Quite impressive results I think. There are lots of other series you can use including Bar, Line, Stacked Bar etc, however for this data AreaSeries seemed to be the best to highlight the variation from zero. It would perhaps be nice to have a zoom and cross wire feature but for the price and everything you get in the Essential Studio this is fantastic value for money.

I will be exploring some of the other components in future posts including the Gauge and the PDF component, which I’m very excited about.