In this post on DataFlex and native mobile applications we will show how to create a native mobile application and connect it to our DataFlex application using web services built with the WebApp Framework.

While web applications can run on devices and become more and more able to do many things native mobile applications can do there are still a lot of things that are better done in a native mobile application.

An option to create a native mobile application on 3 platforms (iOS, Android and Windows) from the same code base is Xamarin. Xamarin is a cross platform environment that allows us to build a mobile application that will build as a native iOS application as well as a native Android and Windows application.

The code base is written in C#. This is just one example of building a mobile application there are several other frameworks out there and we will be visiting some of them in future posts.

For this example our goal is to use the DataFlex Web Order workspaces web services to supply data. Specifically we are looking at showing a list of customers using the GetCustomerInfoList web service that returns a list of all customers.

So in order for this to work we will need the Web Order workspace working and running.

By default the url for the web service would be

http://localhost/WebOrder_19_1/CustomerAndOrderInfo.wso/GetCustomerInfoList

and when called from a browser we would receive an output similar to the following

We could use this but switching the output to JSON will make it a lot more useful so we use the following URL which will return the data in JSON format

http://localhost/WebOrder_19_1/CustomerAndOrderInfo.wso/GetCustomerInfoList/JSON

Having the data ready we can switch to creating our native mobile application

To do this we create a Xamarin project in Visual Studio. We select the project type as a Cross Platform App (Xamarin Forms).

on the next screen we will select a Blank App template and the .NET Standard Code sharing strategy

After clicking ok Visual Studio will create a simple Xamarin Application with a single page

Lets quickly build this simple app. We can build it either for Windows, Android or iOS.

To build our little example we want to change this screen of course

We want a list showing our customers and we also want to add a field for the host name so we can enter a different host name for our web service if needed

On the DataFlex side we have a struct called tCutomerInfo that holds the data for each customer record

// Customer Information
// This structure matches the structure of the Customer table
struct tCustomerInfo
    integer iCustNumber
    string  sName
    string  sCustAddress
    string  sCity
    string  sState
    string  sZip
    string  sPhoneNumber
    string  sFaxNumber
    string  sEmailAddress
    real    rCreditLimit
    real    rPurchases
    real    rBalance
    string  sComments
    string  sStatus
end_struct

first we need the equivalent class on the Xamarin side to receive that information

We add the following class

namespace XamAndFlex
{
    class CustomerInfo
    {
        public int iCustNumber { get; set; }
        public string sName { get; set; }
        public string sCustAddress { get; set; }
        public string sCity { get; set; }
        public string sState { get; set; }
        public string sZip { get; set; }
        public string sPhoneNumber { get; set; }
        public string sFaxNumber { get; set; }
        public string sEmalAddress { get; set; }
        public decimal rCreditLimit { get; set; }
        public decimal rPurchases { get; set; }
        public decimal rBalance { get; set; }
        public string sComments { get; set; }
        public string sStatus { get; set; }
    }
}

now lets add a property for our host address to the application. In App.xaml.cs we will add the following

        private static string _hostAddress;
        public static string HostAddress { get { return _hostAddress; } set { _hostAddress = value; } }

and then lets add the initialization in the constructor

        public App()
        {
            InitializeComponent();

            HostAddress = "http://localhost/";
            MainPage = new XamAndFlex.MainPage();
        }

Now we also add a static function to return an HttpClient that we will need later on for calling the web service

        private static HttpClient _client;
        public static HttpClient GetClient()
        {
            if (_client == null)
            {
                _client = new HttpClient();
                _client.Timeout = TimeSpan.FromSeconds(8);
            }
            return _client;
        }

Having done all this it is time to create a view model for our view

First we will create a simple base view model class as follows

namespace XamAndFlex
{
    public class BaseViewModel : INotifyPropertyChanged
    {

        protected bool SetProperty<T>(ref T backingStore, T value,
            [CallerMemberName]string propertyName = "",
            Action onChanged = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingStore, value))
                return false;

            backingStore = value;
            onChanged?.Invoke();
            OnPropertyChanged(propertyName);
            return true;
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var changed = PropertyChanged;
            if (changed == null)
                return;

            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}

this class is a very simple base view model supporting property changed notifications

now we can use this class as a base class for our CustomerListViewModel

namespace XamAndFlex
{
    class CustomerListViewModel : BaseViewModel
    {
        public CustomerListViewModel()
        {
            Customers = new ObservableCollection<CustomerInfo>();
        }

        public ObservableCollection<CustomerInfo> Customers { get; set; }

        public async Task<bool> GetCustomers()
        {

            string uri = String.Format("{0}WebOrder_19_1/CustomerAndOrderInfo.wso/GetCustomerInfoList/JSON", App.HostAddress);


            try
            {
                var cl = App.GetClient();
                var content = await cl.GetStringAsync(uri);

                var custs = JsonConvert.DeserializeObject<List<CustomerInfo>>(content);
                Customers = new ObservableCollection<CustomerInfo>(custs);
                OnPropertyChanged("Customers");
            }
            catch (Exception ex)
            {
            }

            return true;
        }
    }
}

the viewmodel consists of a simple Observable collection property that will contain the list of customers and an asynchronous method to load the customer list from the web service.

the method simply creates the url and then calls the web service which in turn returns json data. We then deserialize the Json data into a list of CustomerInfo objects and create an observable collection from that list.

now back to our main screen. We want to have an entry field to enter the host address and a refresh button to force a refresh on the list and also of course a list that shows the Customers

Xamarin Forms uses Xaml to describe user interfaces. Our MainPage.xaml file looks as follows

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamAndFlex"
             x:Class="XamAndFlex.MainPage">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"  iOS="0, 20, 0, 0"                     Android="0, 0, 0, 0"                     WinPhone="0, 0, 0, 0" />
    </ContentPage.Padding>
    
    <StackLayout Orientation="Vertical">
        <Image Source="starzenlogo.png"></Image>

        <StackLayout Margin="5" Orientation="Horizontal" >
            <StackLayout Orientation="Vertical">
                <Label Text="Host Name:" FontSize="Micro" />
                <Entry WidthRequest="300" x:Name="hostNameEntry" />
            </StackLayout>

            <Button Text="Refresh" Clicked="btnRefresh_Clicked"/>
            
        </StackLayout>
        
        <ListView RowHeight="100" ItemsSource="{Binding Customers}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                            <Grid >
                                <StackLayout HorizontalOptions="Center" Orientation="Vertical" Margin="5">
                                    <StackLayout HorizontalOptions="Center" Spacing="5" Orientation="Horizontal">
                                        <Label VerticalOptions="Center" Text="{Binding sName}" FontSize="Small" FontAttributes="Bold" />
                                        <Label VerticalOptions="Center" Text="{Binding iCustNumber}" FontSize="Micro" />
                                    </StackLayout>
                                    <Label HorizontalOptions="Center" Text="{Binding sCustAddress}" FontSize="Micro"  />
                                    <StackLayout HorizontalOptions="Center" Spacing="5" Orientation="Horizontal">
                                        <Label Text="{Binding sCity}" FontSize="Micro" />
                                        <Label Text="{Binding sState}" FontSize="Micro" />
                                        <Label Text="{Binding sZip}" FontSize="Micro" />
                                    </StackLayout>

                                </StackLayout>

                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

</ContentPage>

We have a content page. In the content page we define a padding and we only use padding on the iOS platform. On iOS the top bar would otherwise be overlapping our main window.

The rest of the page is a StackLayout containing a logo image another stack layout that contains the host address fields and the ListView

The host address fields consist of a simple label and entry field as well as a button. The button has a simple clicked event, we could of course create a command in our ViewModel as well.

The ListView uses binding to bind its ItemsSource property to the Customers property of our CustomerListViewModel. The item template uses data binding to bind to the customer records fields.

Now on to the code side of the main page

First we define the view model property,  create an instance and also add it as a BindingContext to our main page.

In addition we initialize the host name from our application property

        private CustomerListViewModel customerListViewModel; 

        public MainPage()
		{
            InitializeComponent();

            customerListViewModel = new CustomerListViewModel();
            BindingContext = customerListViewModel;

            hostNameEntry.Text = App.HostAddress;


        }

We also need to add the clicked event for our refresh button. Again this could be a command in our view model as well

 private async void btnRefresh_Clicked(object sender, EventArgs e)
        {
            App.HostAddress = hostNameEntry.Text;
            if (!App.HostAddress.EndsWith("/"))
            {
                App.HostAddress = App.HostAddress + "/";
            }
            await customerListViewModel.GetCustomers();
        }

We get the host name from the entry field update our applications host name property and call the GetCustomers method in our view model.

In addition we could automatically refresh the list when the screen is shown

To do this we override the OnAppearing event

        protected override async void OnAppearing()
        {
            base.OnAppearing();
            await customerListViewModel.GetCustomers();
            
        }

In the OnAppearing event we also make a call to the GetCustomers method of our viewmodel to fill the list.

lets build our project and see what it looks like as a windows application

the same application built on Android will look as follows

and last but certainly not least the iOS version. For iOS builds a connected mac is required to do the builds

This shows a small example on how you can build a native mobile application using Xamarin and connect it to a DataFlex WebApp webservice.

We have used Xamarin in a few mobile applications often were offline capability was a big requirement.

Michael Salzlechner is the CEO of StarZen Technologies, Inc.

He was part of the Windows Team at Data Access Worldwide that created the DataFlex for Windows Product before joining StarZen Technologies. StarZen Technologies provides consulting services as well as custom Application development and third party products specifically for DataFlex developers