Xuni Dashboard Demo for Tablet and Phone
Since the release of Xuni I’ve had a huge interest in using all of our controls together to create more advanced and adaptive interfaces for multiple mobile platforms. Xamarin.Forms gives us an environment for developing applications for new devices, and Xuni gives us the tools to make our interface visually interesting. In a previous blog post I outlined some general principles for going about dashboard design, and in this article I’ll spend some time going through a simple implementation. The Dashboard Demo Sample uses the datasource common to our other First Xuni Control blogs. The data consists of quarter objects, and in each there are properties for Sales, Downloads, and Expenses. This data is relatively simple, but I would still like to represent it in a few different ways. It would be helpful to be able to compare Sales, Downloads, and Expenses for each quarter. Also it is important to be able to see sales as a whole and see which quarters contributed the most to the sales total for the year. Finally, there needs to be some manner of visualizing the sales result for a given year within the context of the sales goal. The next step is to pair the appropriate controls to our data. A bar chart was my choice for an easy avenue for comparing Sales, Downloads, and Expenses on a quarterly basis, also giving some ability to see the general trends for each over the course of a year. A pie chart makes the most sense to represent our yearly sales as a whole with the quarters as individual slices, and gauges are a simple way to represent a percentage to goal. At this point we can produce a very simple mockup: This will be the model for our tablet design. Another consideration we will eventually have to make is a separate interface for phones and tablets. Separate designs will allow us to take advantage of the extra screen real estate available on tablets and a more streamlined interface that is optimized for phones. We’ve already covered creating a first FlexChart, FlexPie, and the various Gauges in other blogs so we’ll focus more on actually using the controls together. Most of our manipulation of our controls will be done in Xaml. We’ll create a Forms Xaml page (I’ve titled it TabletDash) 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="DashboardDemo.TabletDash"
xmlns:xunig="clr-namespace:Xuni.Xamarin.Gauge;assembly=Xuni.Xamarin.Gauge"
xmlns:xunic="clr-namespace:Xuni.Xamarin.FlexChart;assembly=Xuni.Xamarin.FlexChart"
xmlns:xunip="clr-namespace:Xuni.Xamarin.FlexPie;assembly=Xuni.Xamarin.FlexPie"
xmlns:chartcore="clr-namespace:Xuni.Xamarin.ChartCore;assembly=Xuni.Xamarin.ChartCore">
<StackLayout>
<Grid Padding="10" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<xunic:FlexChart x:Name="chart" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" HeaderText ="Financial Information" ItemsSource="{Binding Data}" BindingX="Name" ChartType="Column" Grid.Row="0" Grid.Column="0" Grid.RowSpan="4" Grid.ColumnSpan="2">
<xunic:FlexChart.Series>
<xunic:ChartSeries x:Name="Sales2014" Name="2014 Sales" Binding="Sales" Color="#88BDE6" BorderColor ="#88BDE6" ></xunic:ChartSeries>
<xunic:ChartSeries x:Name="Downloads2014" Name="2014 Downloads" Binding="Downloads" Color="#FBB258" BorderColor ="#FBB258" ></xunic:ChartSeries>
<xunic:ChartSeries x:Name="Expenses2014" Name="2014 Expenses" Binding="Expenses" Color="#90CD97" BorderColor="#90CD97" ></xunic:ChartSeries>
</xunic:FlexChart.Series>
<xunic:FlexChart.Legend >
<chartcore:ChartLegend BackgroundColor="#00000000" LabelFont="12" Position="Bottom">
</chartcore:ChartLegend>
</xunic:FlexChart.Legend>
</xunic:FlexChart>
<xunip:FlexPie x:Name="pie" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" HeaderText ="Sales" ItemsSource="{Binding Data}" HeightRequest="50" WidthRequest="50" BindingName="Name" Binding ="Sales" Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" InnerRadius="0.5">
<xunip:FlexPie.Legend >
<chartcore:ChartLegend LabelFont="12" Position="Bottom">
</chartcore:ChartLegend>
</xunip:FlexPie.Legend>
</xunip:FlexPie>
<Grid Padding="10" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" Grid.RowSpan="2" Grid.Row="2" Grid.Column="2" >
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label x:Name="label" Text="Sales Goal 2013" HorizontalOptions="Center" FontSize="16" Grid.Row="0" />
<xunig:XuniBulletGraph x:Name="graph" HorizontalOptions="FillAndExpand" VerticalOptions="Center" ShowText="All" Value="65" PointerColor="#FBB258" ValueFontColor="White" Min="0" Max="100" HeightRequest="25" WidthRequest="50" Thickness="0.25" Good="100" GoodRangeColor="#90CD97" Bad="50" BadRangeColor="#88BDE6" Target="70" Grid.Row="1" TargetColor="White">
</xunig:XuniBulletGraph>
<Label x:Name="label2" Text="Sales Goal 2014" HorizontalOptions="Center" FontSize="16" Grid.Row="2" />
<xunig:XuniBulletGraph x:Name="graph2" HorizontalOptions="FillAndExpand" VerticalOptions="Center" ShowText="All" Value="86" PointerColor="#FBB258" ValueFontColor="White" Min="0" Max="100" HeightRequest="25" WidthRequest="50" Thickness="0.25" Good="100" GoodRangeColor="#90CD97" Bad="50" BadRangeColor="#88BDE6" Target="70" Grid.Row="3" TargetColor="White">
</xunig:XuniBulletGraph>
<Label x:Name="label3" Text="Sales Goal 2015" HorizontalOptions="Center" FontSize="16" Grid.Row="4" />
<xunig:XuniBulletGraph x:Name="graph3" HorizontalOptions="FillAndExpand" VerticalOptions="Center" ShowText="All" Value="23" PointerColor="#FBB258" ValueFontColor="White" Min="0" Max="100" HeightRequest="25" WidthRequest="50" Thickness="0.25" Good="100" GoodRangeColor="#90CD97" Bad="50" BadRangeColor="#88BDE6" Target="70" Grid.Row="5" TargetColor="White">
</xunig:XuniBulletGraph>
</Grid>
</Grid>
</StackLayout>
</ContentPage>
The above Xaml uses a grid layout to provide a higher level of control positioning than we've used in our previous examples which were all based around stack layouts. We're dividing the page into four rows and three columns and then nesting another grid layout into the right corner for positioning our gauge controls. Additionally, we're also taking advantage of RowSpans and ColumnSpans to size our controls over the portions of the grid we want them to cover. We will also need to instantiate a DataSource object in the code behind, as well as set the binding context for our chart and pie control:
public TabletDash()
{
InitializeComponent();
DataSource ds = new DataSource();
this.chart.BindingContext = ds;
this.pie.BindingContext = ds;
}
This will cover our needs for our tablet interface. The next step is to create a separate Forms Xaml Page for the PhoneDash:
<?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="DashboardDemo.PhoneDash"
xmlns:xunig="clr-namespace:Xuni.Xamarin.Gauge;assembly=Xuni.Xamarin.Gauge"
xmlns:xunic="clr-namespace:Xuni.Xamarin.FlexChart;assembly=Xuni.Xamarin.FlexChart"
xmlns:xunip="clr-namespace:Xuni.Xamarin.FlexPie;assembly=Xuni.Xamarin.FlexPie"
xmlns:chartcore="clr-namespace:Xuni.Xamarin.ChartCore;assembly=Xuni.Xamarin.ChartCore">
<StackLayout>
<xunic:FlexChart x:Name="chart" HeaderText ="Financial Information" ItemsSource="{Binding Data}" BindingX="Name" ChartType="Column">
<xunic:FlexChart.Series>
<xunic:ChartSeries x:Name="Sales2014" Name="2014 Sales" Binding="Sales"
Color="#88BDE6" BorderColor ="#88BDE6">
</xunic:ChartSeries>
<xunic:ChartSeries x:Name="Downloads2014" Name="2014 Downloads" Binding="Downloads"
Color="#FBB258" BorderColor ="#FBB258">
</xunic:ChartSeries>
<xunic:ChartSeries x:Name="Expenses2014" Name="2014 Expenses" Binding="Expenses"
Color="#90CD97" BorderColor="#90CD97">
</xunic:ChartSeries>
</xunic:FlexChart.Series>
<xunic:FlexChart.Legend >
<chartcore:ChartLegend LabelFont="12" Position="Bottom">
</chartcore:ChartLegend>
</xunic:FlexChart.Legend>
</xunic:FlexChart>
<xunip:FlexPie x:Name="pie" HeaderText ="Sales" ItemsSource="{Binding Data}" HeightRequest="50" WidthRequest="50" BindingName="Name" Binding ="Sales" InnerRadius="0.5">
<xunip:FlexPie.Legend >
<chartcore:ChartLegend LabelFont="12" Position="Bottom">
</chartcore:ChartLegend>
</xunip:FlexPie.Legend>
</xunip:FlexPie>
<Label x:Name="label1" Text="Sales Goal 2015" HorizontalOptions="Center" FontSize="16" />
<xunig:XuniBulletGraph x:Name="graph3" ShowText="All" Value="23" PointerColor="#FBB258" ValueFontColor="White" Min="0" Max="100" HeightRequest="10" WidthRequest="50" Thickness="0.25" Good="100" GoodRangeColor="#90CD97" Bad="50" BadRangeColor="#88BDE6" Target="70" TargetColor="White">
</xunig:XuniBulletGraph>
</StackLayout>
</ContentPage>
The PhoneDash has a different interface than what is seen on a tablet. Rather than use a grid layout we will instead use a stack layout to position the controls in a line since there is less space to work with. In addition to this, we will also limit the number of gauges shown on this page so that the only one to display is for the current year to allow things to fit cleanly on a phone screen. Once again we'll instantiate and set the binding contexts in the code behind:
public PhoneDash()
{
InitializeComponent();
DataSource ds = new DataSource();
this.chart.BindingContext = ds;
this.pie.BindingContext = ds;
}
This completes our phone interface. Now we have separate pages to represent our data on both tablet and phone. We need to add a mechanism to switch between the TabletDash and PhoneDash. This can be handled in the App.cs class. The implementation is very straightforward, test if the Device.Idiom == TargetIdiom.Phone and, if it is, return the PhoneDash. Otherwise we will return the TabletDash.
public App()
{
MainPage = GetMainPage();
}
public static Page GetMainPage()
{
if (Device.Idiom == TargetIdiom.Phone)
{
return new PhoneDash();
}
else
{
return new TabletDash();
}
}
One other detail we need to account for before deployment is that Xuni is properly licensed. There is some documentation here, but we can briefly cover the licensing process. We will generate a license key using our application name and this licensing page. That key can then be placed inside the application in a License class. To use the key in the application we need to make a small adjustment to the OnStart() method in the App.cs class.
protected override void OnStart()
{
// Handle the license when your app starts
Xuni.Xamarin.Core.LicenseManager.Key = License.Key;
}
Now we should be able to run our Dashboard Demo application. Download DashboardDemo