{"id":627,"date":"2018-11-16T05:22:03","date_gmt":"2018-11-16T10:22:03","guid":{"rendered":"http:\/\/salzlechner.com\/dev\/?p=627"},"modified":"2018-11-19T05:44:23","modified_gmt":"2018-11-19T10:44:23","slug":"dataflex-and-native-mobile-applications-xamarin","status":"publish","type":"post","link":"http:\/\/salzlechner.com\/dev\/2018\/11\/16\/dataflex-and-native-mobile-applications-xamarin\/","title":{"rendered":"DataFlex and Native Mobile Applications &#8211; Xamarin"},"content":{"rendered":"<p>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.<\/p>\n<p>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.<\/p>\n<p>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.<\/p>\n<p>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.<\/p>\n<p>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\u00a0GetCustomerInfoList web service that returns a list of all customers.<\/p>\n<p>So in order for this to work we will need the Web Order workspace working and running.<\/p>\n<p>By default the url for the web service would be<\/p>\n<p><strong>http:\/\/localhost\/WebOrder_19_1\/CustomerAndOrderInfo.wso\/GetCustomerInfoList<\/strong><\/p>\n<p>and when called from a browser we would receive an output similar to the following<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-628\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf1.png\" alt=\"\" width=\"365\" height=\"236\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf1.png 681w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf1-300x194.png 300w\" sizes=\"(max-width: 365px) 100vw, 365px\" \/><\/p>\n<p>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<\/p>\n<p><strong>http:\/\/localhost\/WebOrder_19_1\/CustomerAndOrderInfo.wso\/GetCustomerInfoList\/JSON<\/strong><\/p>\n<p>Having the data ready we can switch to creating our native mobile application<\/p>\n<p>To do this we create a Xamarin project in Visual Studio. We select the project type as a Cross Platform App (Xamarin Forms).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-629\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf2.png\" alt=\"\" width=\"440\" height=\"301\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf2.png 1309w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf2-300x205.png 300w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf2-768x526.png 768w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf2-1024x701.png 1024w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf2-1080x739.png 1080w\" sizes=\"(max-width: 440px) 100vw, 440px\" \/><\/p>\n<p>on the next screen we will select a Blank App template and the .NET Standard Code sharing strategy<\/p>\n<p>After clicking ok Visual Studio will create a simple Xamarin Application with a single page<\/p>\n<p>Lets quickly build this simple app. We can build it either for Windows, Android or iOS.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-630\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf3.png\" alt=\"\" width=\"329\" height=\"623\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf3.png 751w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf3-158x300.png 158w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf3-540x1024.png 540w\" sizes=\"(max-width: 329px) 100vw, 329px\" \/><\/p>\n<p>To build our little example we want to change this screen of course<\/p>\n<p>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<\/p>\n<p>On the DataFlex side we have a struct called tCutomerInfo that holds the data for each customer record<\/p>\n<pre class=\"lang:default decode:true \">\/\/ Customer Information\r\n\/\/ This structure matches the structure of the Customer table\r\nstruct tCustomerInfo\r\n    integer iCustNumber\r\n    string  sName\r\n    string  sCustAddress\r\n    string  sCity\r\n    string  sState\r\n    string  sZip\r\n    string  sPhoneNumber\r\n    string  sFaxNumber\r\n    string  sEmailAddress\r\n    real    rCreditLimit\r\n    real    rPurchases\r\n    real    rBalance\r\n    string  sComments\r\n    string  sStatus\r\nend_struct<\/pre>\n<p>first we need the equivalent class on the Xamarin side to receive that information<\/p>\n<p>We add the following class<\/p>\n<pre class=\"lang:c# decode:true \">namespace XamAndFlex\r\n{\r\n    class CustomerInfo\r\n    {\r\n        public int iCustNumber { get; set; }\r\n        public string sName { get; set; }\r\n        public string sCustAddress { get; set; }\r\n        public string sCity { get; set; }\r\n        public string sState { get; set; }\r\n        public string sZip { get; set; }\r\n        public string sPhoneNumber { get; set; }\r\n        public string sFaxNumber { get; set; }\r\n        public string sEmalAddress { get; set; }\r\n        public decimal rCreditLimit { get; set; }\r\n        public decimal rPurchases { get; set; }\r\n        public decimal rBalance { get; set; }\r\n        public string sComments { get; set; }\r\n        public string sStatus { get; set; }\r\n    }\r\n}<\/pre>\n<p>now lets add a property for our host address to the application. In App.xaml.cs we will add the following<\/p>\n<pre class=\"lang:c# decode:true\">        private static string _hostAddress;\r\n        public static string HostAddress { get { return _hostAddress; } set { _hostAddress = value; } }<\/pre>\n<p>and then lets add the initialization in the constructor<\/p>\n<pre class=\"lang:c# decode:true \">        public App()\r\n        {\r\n            InitializeComponent();\r\n\r\n            HostAddress = \"http:\/\/localhost\/\";\r\n            MainPage = new XamAndFlex.MainPage();\r\n        }<\/pre>\n<p>Now we also add a static function to return an HttpClient that we will need later on for calling the web service<\/p>\n<pre class=\"lang:c# decode:true \">        private static HttpClient _client;\r\n        public static HttpClient GetClient()\r\n        {\r\n            if (_client == null)\r\n            {\r\n                _client = new HttpClient();\r\n                _client.Timeout = TimeSpan.FromSeconds(8);\r\n            }\r\n            return _client;\r\n        }<\/pre>\n<p>Having done all this it is time to create a view model for our view<\/p>\n<p>First we will create a simple base view model class as follows<\/p>\n<pre class=\"lang:c# decode:true\">namespace XamAndFlex\r\n{\r\n    public class BaseViewModel : INotifyPropertyChanged\r\n    {\r\n\r\n        protected bool SetProperty&lt;T&gt;(ref T backingStore, T value,\r\n            [CallerMemberName]string propertyName = \"\",\r\n            Action onChanged = null)\r\n        {\r\n            if (EqualityComparer&lt;T&gt;.Default.Equals(backingStore, value))\r\n                return false;\r\n\r\n            backingStore = value;\r\n            onChanged?.Invoke();\r\n            OnPropertyChanged(propertyName);\r\n            return true;\r\n        }\r\n\r\n        #region INotifyPropertyChanged\r\n        public event PropertyChangedEventHandler PropertyChanged;\r\n        protected void OnPropertyChanged([CallerMemberName] string propertyName = \"\")\r\n        {\r\n            var changed = PropertyChanged;\r\n            if (changed == null)\r\n                return;\r\n\r\n            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));\r\n        }\r\n        #endregion\r\n    }\r\n}<\/pre>\n<p>this class is a very simple base view model supporting property changed notifications<\/p>\n<p>now we can use this class as a base class for our CustomerListViewModel<\/p>\n<pre class=\"lang:c# decode:true\">namespace XamAndFlex\r\n{\r\n    class CustomerListViewModel : BaseViewModel\r\n    {\r\n        public CustomerListViewModel()\r\n        {\r\n            Customers = new ObservableCollection&lt;CustomerInfo&gt;();\r\n        }\r\n\r\n        public ObservableCollection&lt;CustomerInfo&gt; Customers { get; set; }\r\n\r\n        public async Task&lt;bool&gt; GetCustomers()\r\n        {\r\n\r\n            string uri = String.Format(\"{0}WebOrder_19_1\/CustomerAndOrderInfo.wso\/GetCustomerInfoList\/JSON\", App.HostAddress);\r\n\r\n\r\n            try\r\n            {\r\n                var cl = App.GetClient();\r\n                var content = await cl.GetStringAsync(uri);\r\n\r\n                var custs = JsonConvert.DeserializeObject&lt;List&lt;CustomerInfo&gt;&gt;(content);\r\n                Customers = new ObservableCollection&lt;CustomerInfo&gt;(custs);\r\n                OnPropertyChanged(\"Customers\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n            }\r\n\r\n            return true;\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>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.<\/p>\n<p>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.<\/p>\n<p>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<\/p>\n<p>Xamarin Forms uses Xaml to describe user interfaces. Our MainPage.xaml file looks as follows<\/p>\n<pre class=\"lang:yaml decode:true \">&lt;?xml version=\"1.0\" encoding=\"utf-8\" ?&gt;\r\n&lt;ContentPage xmlns=\"http:\/\/xamarin.com\/schemas\/2014\/forms\"\r\n             xmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2009\/xaml\"\r\n             xmlns:local=\"clr-namespace:XamAndFlex\"\r\n             x:Class=\"XamAndFlex.MainPage\"&gt;\r\n\r\n    &lt;ContentPage.Padding&gt;\r\n        &lt;OnPlatform x:TypeArguments=\"Thickness\"  iOS=\"0, 20, 0, 0\"                     Android=\"0, 0, 0, 0\"                     WinPhone=\"0, 0, 0, 0\" \/&gt;\r\n    &lt;\/ContentPage.Padding&gt;\r\n    \r\n    &lt;StackLayout Orientation=\"Vertical\"&gt;\r\n        &lt;Image Source=\"starzenlogo.png\"&gt;&lt;\/Image&gt;\r\n\r\n        &lt;StackLayout Margin=\"5\" Orientation=\"Horizontal\" &gt;\r\n            &lt;StackLayout Orientation=\"Vertical\"&gt;\r\n                &lt;Label Text=\"Host Name:\" FontSize=\"Micro\" \/&gt;\r\n                &lt;Entry WidthRequest=\"300\" x:Name=\"hostNameEntry\" \/&gt;\r\n            &lt;\/StackLayout&gt;\r\n\r\n            &lt;Button Text=\"Refresh\" Clicked=\"btnRefresh_Clicked\"\/&gt;\r\n            \r\n        &lt;\/StackLayout&gt;\r\n        \r\n        &lt;ListView RowHeight=\"100\" ItemsSource=\"{Binding Customers}\"&gt;\r\n            &lt;ListView.ItemTemplate&gt;\r\n                &lt;DataTemplate&gt;\r\n                    &lt;ViewCell&gt;\r\n                            &lt;Grid &gt;\r\n                                &lt;StackLayout HorizontalOptions=\"Center\" Orientation=\"Vertical\" Margin=\"5\"&gt;\r\n                                    &lt;StackLayout HorizontalOptions=\"Center\" Spacing=\"5\" Orientation=\"Horizontal\"&gt;\r\n                                        &lt;Label VerticalOptions=\"Center\" Text=\"{Binding sName}\" FontSize=\"Small\" FontAttributes=\"Bold\" \/&gt;\r\n                                        &lt;Label VerticalOptions=\"Center\" Text=\"{Binding iCustNumber}\" FontSize=\"Micro\" \/&gt;\r\n                                    &lt;\/StackLayout&gt;\r\n                                    &lt;Label HorizontalOptions=\"Center\" Text=\"{Binding sCustAddress}\" FontSize=\"Micro\"  \/&gt;\r\n                                    &lt;StackLayout HorizontalOptions=\"Center\" Spacing=\"5\" Orientation=\"Horizontal\"&gt;\r\n                                        &lt;Label Text=\"{Binding sCity}\" FontSize=\"Micro\" \/&gt;\r\n                                        &lt;Label Text=\"{Binding sState}\" FontSize=\"Micro\" \/&gt;\r\n                                        &lt;Label Text=\"{Binding sZip}\" FontSize=\"Micro\" \/&gt;\r\n                                    &lt;\/StackLayout&gt;\r\n\r\n                                &lt;\/StackLayout&gt;\r\n\r\n                        &lt;\/Grid&gt;\r\n                    &lt;\/ViewCell&gt;\r\n                &lt;\/DataTemplate&gt;\r\n            &lt;\/ListView.ItemTemplate&gt;\r\n        &lt;\/ListView&gt;\r\n    &lt;\/StackLayout&gt;\r\n\r\n&lt;\/ContentPage&gt;\r\n<\/pre>\n<p>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.<\/p>\n<p>The rest of the page is a StackLayout containing a logo image another stack layout that contains the host address fields and the ListView<\/p>\n<p>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.<\/p>\n<p>The ListView uses binding to bind its <em>ItemsSource<\/em> property to the <em>Customers<\/em> property of our <em>CustomerListViewModel<\/em>. The item template uses data binding to bind to the customer records fields.<\/p>\n<p>Now on to the code side of the main page<\/p>\n<p>First we define the view model property,\u00a0 create an instance and also add it as a BindingContext to our main page.<\/p>\n<p>In addition we initialize the host name from our application property<\/p>\n<pre class=\"lang:c# decode:true\">        private CustomerListViewModel customerListViewModel; \r\n\r\n        public MainPage()\r\n\t\t{\r\n            InitializeComponent();\r\n\r\n            customerListViewModel = new CustomerListViewModel();\r\n            BindingContext = customerListViewModel;\r\n\r\n            hostNameEntry.Text = App.HostAddress;\r\n\r\n\r\n        }<\/pre>\n<p>We also need to add the clicked event for our refresh button. Again this could be a command in our view model as well<\/p>\n<pre class=\"lang:c# decode:true \"> private async void btnRefresh_Clicked(object sender, EventArgs e)\r\n        {\r\n            App.HostAddress = hostNameEntry.Text;\r\n            if (!App.HostAddress.EndsWith(\"\/\"))\r\n            {\r\n                App.HostAddress = App.HostAddress + \"\/\";\r\n            }\r\n            await customerListViewModel.GetCustomers();\r\n        }<\/pre>\n<p>We get the host name from the entry field update our applications host name property and call the GetCustomers method in our view model.<\/p>\n<p>In addition we could automatically refresh the list when the screen is shown<\/p>\n<p>To do this we override the OnAppearing event<\/p>\n<pre class=\"lang:c# decode:true \">        protected override async void OnAppearing()\r\n        {\r\n            base.OnAppearing();\r\n            await customerListViewModel.GetCustomers();\r\n            \r\n        }<\/pre>\n<p>In the OnAppearing event we also make a call to the GetCustomers method of our viewmodel to fill the list.<\/p>\n<p>lets build our project and see what it looks like as a windows application<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-633\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf4.png\" alt=\"\" width=\"358\" height=\"468\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf4.png 502w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf4-229x300.png 229w\" sizes=\"(max-width: 358px) 100vw, 358px\" \/><\/p>\n<p>the same application built on Android will look as follows<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-635\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf6.png\" alt=\"\" width=\"360\" height=\"639\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf6.png 1440w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf6-169x300.png 169w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf6-768x1365.png 768w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf6-576x1024.png 576w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf6-1080x1920.png 1080w\" sizes=\"(max-width: 360px) 100vw, 360px\" \/><\/p>\n<p>and last but certainly not least the iOS version. For iOS builds a connected mac is required to do the builds<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-634\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf5.png\" alt=\"\" width=\"364\" height=\"690\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf5.png 751w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf5-158x300.png 158w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2018\/11\/xamdf5-540x1024.png 540w\" sizes=\"(max-width: 364px) 100vw, 364px\" \/><\/p>\n<p>This shows a small example on how you can build a native mobile application using Xamarin and connect it to a DataFlex WebApp webservice.<\/p>\n<p>We have used Xamarin in a few mobile applications often were offline capability was a big requirement.<\/p>\n\n\t\t<div class='author-shortcodes'>\n\t\t\t<div class='author-inner'>\n\t\t\t\t<div class='author-image'>\n\t\t\t<img src='http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2016\/02\/mike5crop-566174_60x60.jpg' alt='' \/>\n\t\t\t<div class='author-overlay'><\/div>\n\t\t<\/div> \n\t\t<div class='author-info'>\n\t\t\tMichael Salzlechner is the CEO of StarZen Technologies, Inc.<\/p>\n<p>He was part of the Windows Team at Data Access Worldwide that created the DataFlex for Windows Product before joining\u00a0<a href=\"http:\/\/starzen.com\">StarZen Technologies<\/a>. StarZen Technologies provides consulting services as well as custom Application development and third party products specifically for DataFlex developers<\/p>\n\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n","protected":false},"excerpt":{"rendered":"<p>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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","ngg_post_thumbnail":0,"footnotes":""},"categories":[6,27,36],"tags":[],"class_list":["post-627","post","type-post","status-publish","format-standard","hentry","category-dataflex","category-dataflex-webapp","category-xamarin"],"_links":{"self":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/627","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/comments?post=627"}],"version-history":[{"count":4,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/627\/revisions"}],"predecessor-version":[{"id":640,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/627\/revisions\/640"}],"wp:attachment":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/media?parent=627"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/categories?post=627"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/tags?post=627"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}