Translate

martes, 21 de julio de 2015

My experience with Visual Studio 2015 after first day of official release



The very first feature I went to test is cross platform applications,
I started with Android, mostly because I am not buying a mac for build host(blame apple business model there).

In a matter of minutes I had the base for an Android Application fully coded in C# and with simple UI created through Visual Studio UI designer.

First, I opened my existent web portal project which was a MVC 5 web site.
To this website I added a WCF service which retrieves a list of places ( Description, Property Type, Country, State, City)

Then I added a new project to the solution and I selected Android/Blank App(Android).
Then from the android project I added a web reference to the WCF service created before.
This, as usual with consumed services, creates the proxy classes and the generated types.
So far no real difference from coding against traditional .NET applications.



So far so good, but still some pending steps: create a simple UI, and bind the data to a list.
Since the designer is very friendly and the toolbox supports drag and drop, it is very straightforward.

Since what I wanted to do was just show a list of values, I selected to add a ListView, easily done in less than 30 seconds.

Now, only binding the data was pending, here is where things kind of became a little complex but only because I do not program android, so I basically had to learn the concepts behind data biding in android.



First sample I found was using an ArrayAdapter, so I tested with that, this took me around an hour because I was getting unhandled exceptions I finally found that I should use both lines:

            AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironment_UnhandledExceptionRaiser;
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;




That worked, and made me realize I was using the wrong Id in the ArrayAdapter constructor.

Once I fixed that, the data was being displayed, one more problem though, all rows where displaying the class type info, not the field, in a traditional C# app we are usually able to fix this by using properties such as DisplayMember or TextField, apparently in android this is not the case, the easy and extremely not elegant solution is to string.format the fields, the most common solution would be to find a way to indicate the list it has several columns, apparently not as straighforward in android.

Finally I found about creating a custom layout and a custom adapter.
After using that approach, my data is shown as I originally wanted.

Note: I had to publish my WCF service to my local IIS to be able to access it by i[ from withing the emulator and my Nexus 7 tablet. I also had to modify the firewall so that it allows my local network devices to access my local IIS.


Custom Layout Code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:minWidth="25px"
    android:minHeight="25px">
    <TextView
        android:text="Description"
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:id="@+id/Description"
        android:layout_weight="1"
        android:textSize="20sp" />
    <TextView
        android:text="PropertyType"
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:id="@+id/PropertyType"
        android:layout_weight="1"
        android:textSize="20sp"
        android:textStyle="normal" />

</LinearLayout>

Custom Adapter Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using PTIRealEstateAndroid.PTIRealEstateWS;

namespace PTIRealEstateAndroid
{
    public class GenericPropertyAdapter : BaseAdapter<PTIRealEstateWS.GenericPropertyContract>
    {
        private readonly IList<PTIRealEstateWS.GenericPropertyContract> _items;
        private readonly Context _context;

        public GenericPropertyAdapter(Context context, IList<PTIRealEstateWS.GenericPropertyContract> items)
        {
            _items = items;
            _context = context;
        }

        public override GenericPropertyContract this[int position]
        {
            get
            {
                return this._items[position];
            }
        }

        public override int Count
        {
            get
            {
                return this._items.Count;
            }
        }

        public override long GetItemId(int position)
        {
            return position;
        }

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            var item = _items[position];
            var view = convertView;

            if (view == null)
            {
                var inflater = LayoutInflater.FromContext(_context);
                view = inflater.Inflate(Resource.Layout.GenericProperty, parent, false);
            }

            view.FindViewById<TextView>(Resource.Id.Description).Text = item.Description;
            view.FindViewById<TextView>(Resource.Id.PropertyType).Text = item.PropertyType;

            return view;

        }
    }

}

Please use the comments and let us know about your experience.