This is the sixth blog post in the "Building the Logify Client App" series. As you may already know, this blog series details how we designed and built our new Logify mobile client (a mobile client for our automated crash reporting system) with DevExpress Xamarin.Forms UI Controls. If you have yet to review our previous posts, feel free to do so using the links below:
- Xamarin.Forms UI Controls - Building the Logify Client App (Part 1)
- Xamarin.Forms UI Controls - Building the Logify Client App (Part 2)
- Xamarin.Forms UI Controls - Building the Logify Client App (Part 3)
- Xamarin.Forms UI Controls - Building the Logify Client App (Part 4)
- Xamarin.Forms UI Controls - Building the Logify Client App (Part 5)
In our previous blog post, we created an intuitive exception filtering system. In this post, we’ll create our exception report screen. Exception information includes a significant amount of structured data. To implement an easy-to-read/easy-to-understand exception report screen, we chose to place each information block on a separate tab. The DevExpress Xamarin TabView is a good fit for this usage scenario.
Using Logify’s API
Our Logify mobile client obtains a full report from the Logify server via the following API:
GET https://logifyrestapiendpoint/report?apiKey=ApiKey&reportId=ReportId
Server response – JSON with a special structure:
{
"AppName" : "Clinical Study",
"Cards" : [
{
"Type" : 1,
"Values" : [
{
"Header" : "Exception",
"Stack" : [
"Exception of type 'System.Web.HttpUnhandledException' was thrown.",
"at System.Web.UI.Page.HandleError(Exception e)",
...
],
"Type" : "Exception",
"Message" : "Exception System.Web.HttpUnhandledException"
}
],
"Title" : "Exceptions"
},
...
]
}
TabView Implementation
As noted in previous blog posts, our Xamarin TabView control offers flexible appearance customization options. For purposes of the exception report screen, we decided to use custom templates for both items and item headers.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label
Grid.Row="0"
Text="{Binding AppName}"/>
<navigation:TabView
Grid.Row="1"
x:Name="tabControl"
ItemsSource="{Binding Cards}"
ItemHeaderTemplate="{StaticResource headerItemTemplate}"
ItemTemplate="{StaticResource reportDetailTemplateSelector}"
IsSelectedItemIndicatorVisible="False"
HeaderPanelBackgroundColor="Transparent"
HeaderPanelPosition="Bottom"/>
</Grid>
Our tab header item needs to look like a Xamarin.Forms IndicatorView control. To implement this appearance, we add an item header template with two icons (for selected and non-selected states). A viewmodel maintains the current state for each element in the data source.
using System.Collections.Generic;
using Logify.Mobile.Models;
namespace Logify.Mobile.ViewModels.ReportDetail {
public abstract class ReportDetailInfoContainerBase: NotificationObject {
public abstract CardType CardType { get; }
public string CardHeader { get; set; }
bool isSelected;
public bool IsSelected {
get => isSelected;
set => SetProperty(ref isSelected, value);
}
}
}
In the following step, we will create a converter and add the converter and a data template to the resource section within the markup.
using System;
using System.Globalization;
using Xamarin.Forms;
namespace Logify.Mobile.Services.Converters {
public class BoolToObjectConverter : IValueConverter {
public Object FalseSource { get; set; }
public Object TrueSource { get; set; }
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture) {
if (!(value is bool)) {
return null;
}
return (bool)value ? TrueSource : FalseSource;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
}
<ContentPage.Resources>
<converters:BoolToObjectConverter
x:Key="selectedIconConverter"
FalseSource="Circle.svg"
TrueSource="SelectedCircle.svg"/>
<DataTemplate x:Key="headerItemTemplate">
<editors:IconView
ImageSource="{Binding IsSelected, Converter = {StaticResource selectedIconConverter}}"/>
</DataTemplate>
...
</ContentPage.Resources>
We also need to implement a custom data template for each tab item. An exception report includes a few sections with different bits of information. Consequently, we need to use a few different data templates. The code below adds a template selector to the resource section.
<ContentPage.Resources>
<converters:BoolToObjectConverter
x:Key="selectedIconConverter"
FalseSource="Circle.svg"
TrueSource="SelectedCircle.svg"/>
<DataTemplate x:Key="headerItemTemplate">
<editors:IconView
ImageSource="{Binding IsSelected, Converter = {StaticResource selectedIconConverter}}"/>
</DataTemplate>
<templates:ReportDetailTemplateSelector
x:Key="reportDetailTemplateSelector"
KeyValueTemplate="{StaticResource keyValueTemplate}"
StackedTemplate="{StaticResource stackedTemplate}"
SimpleListTemplate="{StaticResource simpleListTemplate}"
CommentsTemplate="{StaticResource commentsTemplate}"
TabularTemplate="{StaticResource tabularTemplate}"/>
</ContentPage.Resources>
Follow this link to view the markup of templates.
Finally, we’ll add a floating button to the page. You can check final markup here.
As you can see in the image above, we used our Xamarin TabView control to create a compact UX for the mobile client’s exception report view. We also used data templates to customize the appearance of the TabView itself. In our next post, we’ll implement a Monitored Apps view with the DevExpress Xamarin DataGrid control.
We’ll share the source code for the entire application once we complete this blog series. Until then, feel free to submit comments/questions using the comment section below.