Showing posts with label xamarin. Show all posts
Showing posts with label xamarin. Show all posts

2017/10/24

Return to Xamarin and So Long to PCL

Working on a new project and using C# for the majority of the PC client. We need a mobile app as well, so Xamarin seemed like the logical choice to maximize code reuse.

When previously working with Xamarin I was introduced to PCL. But, I was forever running into problems with platforms I was targeting and the ones supported by packages on nuget.

Apparently well aware of its flaws Microsoft has since deprecated PCL in favor of .Net Standard. We've started targeting the bleeding edge .Net Standard 2.0 since it provides the widest API coverage and meets our platform requirements. What follows is my experience getting a multi-platform (initially just Android and UWP) Xamarin.Forms app using .Net Standard 2.0 building and running with Visual Studio 2017 Community.


Creation

Using the VS 2017 new project wizard, there's currently no obvious way to create a Xamarin app that uses .Net Standard 2.0. Under Other Languages, Visual C#, there's Cross Platform App (Xamarin). Next, for UI Technology choose Xamarin.Forms and Code Sharing Strategy choose Portable Class Library (PCL). From there the following two links got me started converting the PCL project to .Net Standard:


Building

Building for the first time resulted in a bunch of errors similar to the following:
 obj\Debug\netstandard2.0\mobile_app.AssemblyInfo.cs(14,12,14,54): error CS0579: Duplicate 'System.Reflection.AssemblyCompanyAttribute' attribute  
 obj\Debug\netstandard2.0\mobile_app.AssemblyInfo.cs(15,12,15,60): error CS0579: Duplicate 'System.Reflection.AssemblyConfigurationAttribute' attribute  
 obj\Debug\netstandard2.0\mobile_app.AssemblyInfo.cs(16,12,16,58): error CS0579: Duplicate 'System.Reflection.AssemblyDescriptionAttribute' attribute  
To fix this, I need to remove Properties/AssemblyInfo.cs from the project.
 App.xaml.cs(6,7,6,14): error CS0246: The type or namespace name 'Xamarin' could not be found (are you missing a using directive or an assembly reference?)  
 MainPage.xaml.cs(6,7,6,14): error CS0246: The type or namespace name 'Xamarin' could not be found (are you missing a using directive or an assembly reference?)  
 App.xaml.cs(10,32,10,43): error CS0246: The type or namespace name 'Application' could not be found (are you missing a using directive or an assembly reference?)  
 MainPage.xaml.cs(10,37,10,48): error CS0246: The type or namespace name 'ContentPage' could not be found (are you missing a using directive or an assembly reference?)  
 App.xaml.cs(19,33,19,40): error CS0115: 'App.OnStart()': no suitable method found to override  
 App.xaml.cs(24,33,24,40): error CS0115: 'App.OnSleep()': no suitable method found to override  
 App.xaml.cs(29,33,29,41): error CS0115: 'App.OnResume()': no suitable method found to override  
For this, right-click VS project, Manage NuGet Packages, and add Xamarin.Forms.
 error : Project 'mobile_app\mobile_app\mobile_app\mobile_app.csproj' targets '.NETStandard,Version=v2.0'. It cannot be referenced by a project that targets 'UAP,Version=v10.0.10586'.  
I couldn't just build a UWP application with .NetStandard 2.0, it required upgrading Visual Studio 2017 to 15.4 and setting the Minimum Version of the UWP project to "Windows 10 Fall Creators Update" (may first need to set Target Version to the same).
 Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified.  
 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'  
   at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)  
   at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)  
   at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)  
   at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(CustomAttributeRecord caRecord, MetadataImport scope, Assembly& lastAptcaOkAssembly, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, Object[] attributes, IList derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg)  
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes, Boolean isDecoratedTargetSecurityTransparent)  
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeAssembly assembly, RuntimeType caType)  
   at System.Reflection.RuntimeAssembly.GetCustomAttributes(Type attributeType, Boolean inherit)  
   at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType, Boolean inherit)  
   at System.Attribute.GetCustomAttribute(Assembly element, Type attributeType, Boolean inherit)  
   at System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T](Assembly element)  
   at Microsoft.Build.Tasks.ProcessResourceFiles.ReadAssemblyResources(String name, String outFileOrDir)  
Updating Microsoft.NETCore.UniversalWindowsPlatform package to the latest version on nuget solved this. There's also a warning about incompatible versions of Xamarin.Forms, but for that I just removed the reference to the old assembly from the UWP project.


Running

 DEP3321: To deploy this application, your deployment target should be running Windows Universal Runtime version 10.0.16299.0 or higher. You currently are running version 10.0.15063.674. Please update your OS, or change your deployment target to a device with the appropriate version.  
Here we're targeting Fall Creators Update but I wasn't running it yet. Previously I would have to enroll in Windows 10 Insider Preview, but as of today Fall Creators Update is officially released. Finally, I'm not sure if this is actually required for UWP apps, but it's needed for Android so I'll mention it here anyway. Xaml files need to be available at runtime, so right-click each and in Properties set "Build Action" to "Embedded resource".



2016/04/05

Xamarin Forms part 1

This is the first part of my Xamarin Forms dive.

Binding

Arguably the single most important thing to master as it connects your View (UI) to the ViewModel, it's only fitting I start out with Binding (1, 2 and 3). Since I’ve been using Forms I’ve found that binding is key to getting things working but various nuances are scattered about in numerous demos.

Bindings connect a "source" (either another UI element in the View or something in the ViewModel) to a "target" (some UI element in the View) that displays it.

To start with, you'll see that most projects create an XML namespace that refers to a .Net assembly generated by your project:

<!-- "xmlns:local" ties "local" XML namespace to the "luck" C# namespace in the "luck" assembly -->
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:luck;assembly=luck"
    x:Class="luck.MainPage"
    >
</ContentPage>

// "local:MainViewModel" in XAML thus refers to a C# class similar to:
namespace luck {
    public class MainViewModel {
        // Implementation
    }
}
You can then easily create static bindings, references, and resources:
<!-- Static -->
<Label Text="{x:Static local:MainViewModel.Text}" />

// C# ViewModel
public class MainViewModel {
    public static string Text = "text";
}

<!-- Reference -->
<Label Text="text" x:Name="MyText" />
<Label Text="{x:Reference MyText}" />

<!-- Resource -->
    <ContentPage.Resources>
        <ResourceDictionary>
            <local:LocalizationConverter
                x:Key="LocalizationConverter" />
        </ResourceDictionary>
    </ContentPage.Resources>
    <Label Text="{Binding SelectedItem.DisplayName,
        Converter={StaticResource LocalizationConverter}}" />
There's additional information about Resources and markup extensions here, and I'll come back to ResourceDictionary a bit later in this series when I get to Styles.

Alternatively, the Binding markup extension is the most common binding technique and more advanced as it supports several different properties. The easiest way of specifying a source is by setting the BindingContext for the entire Page since it is inherited by all children. This can be done either in your code-behind constructor:

public MainPage ()
{
     InitializeComponent ();
     BindingContext = new MainViewModel (); 
}
or via XAML:
    <ContentPage.BindingContext>
        <local:MainViewModel />
    </ContentPage.BindingContext>
You can then bind a simple value:
<Label Text="{Binding Text}" />

public class MainViewModel {
    public string Text { get; set; }
}
As already mentioned, Binding supports several different properties. Path specifies the property of the source to which we are binding and can be omitted if it's the first property. The following two are equivalent:
<Label Text="{Binding Text}" />
<Label Text="{Binding Path=Text}" />
The Path property is able to access sub-properties as well as the index operator. For example:
<Label Text="{Binding Values.Count}" />
<Label Text="{Binding Values[key]}" />

// In the ViewModel
public Dictionary Values { get; set; }
According to this, if you have large numbers of values to set you can simplify multiple indexed bindings by setting the binding context:
<StackLayout BindingContext="{Binding Values}" />
    <Label Text="{Binding [key]}" />
<StackLayout />
There is also a shorthand syntax to bind directly to the BindingContext itself:
<Label Text="{Binding .}" />
The Source property allows the binding to explicitly specify the "source" of a binding. It's analogous to the BindingContext (where the target specifies the source) and the following are equivalent:
<Label BindingContext="{x:Reference items}" Text="{Binding SelectedItem, StringFormat='{0}'}" />
<Label Text="{Binding SelectedItem, Source={x:Reference items}, StringFormat='{0}'}" />
The biggest difference being using BindingContext will be inherited by all sub-children of the UI element. At one point I found myself repeatedly specifying BindingContext and Source for a number of nested elements and then running into problems where I could no longer reference the original BindingContext, etc. In this case I had to carefully consider what I was binding where and reorganise the data provided by my ViewModel to cut back on the excessive use of Source.

StringFormat can be used to apply string conversion and formatting:

<Label Text="{Binding Value, StringFormat='Formatted {0}'}" />
Internally it uses String.Format method so it accepts all the same forms. Note that because both .Net formatting and markup extensions use curly braces, StringFormat must be enclosed in single quotes.

The Converter property is more generalised than StringFormat and also accepts an optional ConverterParameter value:

 <Label Text="{Binding SomeInt, Converter={StaticResource IntConverter}, ConverterParameter=10}" />

 public class IntConverter : IValueConverter
 {
  public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
   int intparam;
   if (!int.TryParse(parameter as string, out intparam))
    intparam = 1;

   return (int)value * intparam;
  }

  public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
   int intparam;
   if (!int.TryParse(parameter as string, out intparam))
    intparam = 1;

   return ((int)value) / intparam;
  }
 }
Mode The final property Mode is available to solve some specific binding problems. I've not done anything with it just yet, so I'll refer to two relevant documents from Xamarin (1, 2) and revisit it later when I understand it better.

Dynamic Bindings

For values that can be changed at runtime, either the property you're binding to or the entire ViewModel needs to implement INotifyPropertyChanged interface. For example, using System.Collections.ObjectModel.ObservableCollection:
public static ObservableCollection Chats = new ObservableCollection();


You can even define your own:
    public class ObservableString : System.ComponentModel.INotifyPropertyChanged
    {
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        string val;
        public string Value
        {
            get { return val; }
            set {
                val = value;
                OnPropertyChanged ("Value");
            }
        }

        void OnPropertyChanged(string propertyName = null)
        {
            if (PropertyChanged != null)
                PropertyChanged (this, new System.ComponentModel.PropertyChangedEventArgs (propertyName));
        }
    }
But this only seems to work with static bindings. The more standard approach is to implement INotifyPropertyChanged for your entire ViewModel:
    public class LoginViewModel : INotifyPropertyChanged
    {
        bool m_isBusy = false;
        public bool IsBusy {
            get {
                return m_isBusy;
            }
            set {
                if (value != m_isBusy) {
                    m_isBusy = value;
                    OnPropertyChanged ("IsBusy");
                }
            }
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged (string propertyName)
        {
            var changed = PropertyChanged;
            if (changed != null) {
                PropertyChanged (this, new PropertyChangedEventArgs (propertyName));
            }
        }
        #endregion
    }
With .Net 4.5 OnPropertyChanged can be simplified:
        public bool IsBusy {
            get {
                return m_isBusy;
            }
            set {
                if (value != m_isBusy) {
                    m_isBusy = value;
                    OnPropertyChanged ();
                }
            }
        }

        protected virtual void OnPropertyChanged ([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
        { /* same as above */ }
A minor improvement, but now the compiler guarantees that the property name always matches the "magic string". There’s further improvements to reduce all the boilerplate needed to implement properties (specifically this, and more generally like this and this).

This ran a bit long, but it should wrap up the first dump of my notes on Xamarin Forms. Next up: Callbacks, Commands, and Triggers... oh my!

2016/03/25

Xamarin Forms

While never a UI programmer or UX/UI designer, I’ve used or been exposed to several UI/layout/formatting systems over the years: LATEX, Tkinter, MFC, Scaleform, HTML/stylesheets, several in-house systems, EZGUI and uGUI in Unity, etc. And no matter what, it seems like the UI of every project ends up horribly out of control. Occasionally (often?) no attempt is made to embrace a sensible workflow or sanely design/organise the UI. But, even when MVC or some other established design pattern is attempted it usually fails.

More often than not it’s due to lack of really understanding the model, developers taking shortcuts to "save time" (this is really a production failure), or a disconnect with the pattern in the heat of implementation. But, I think a framework or environment (i.e. lack of process) that permits such transgressions is just as much to blame.

One of the things that initially attracted me to Xamarin was the ability to develop multi-platform native apps in a language we were already using for other things- C#. Additionally, via Xamarin Forms their embrace of MVVM (wikipedia) similar to WPF. While I don't believe in silver bullets, I do like investigating the approaches taken by different frameworks.

Invariably, any UI-oriented project needs superfluous animation to give it flair. Spurned by this post I decided this was a good opportunity to investigate ways of translating design requirements into concrete implementation using Xamarin’s framework targeting MVVM. Particularly looking at how it enables for creating a mostly data-driven UI, and permitting UI prototyping or UX/UI iteration de-coupled from writing code (an insurmountable obstacle to most non-programmers for some reason- although that’s a post for another day).

There’s lots of basic tutorials on getting a button on screen etc. so I’m not really covering that and assume you already have a basic understanding of Xamarin Forms. I want to reference some of the various other sources I’ve looked at, how and why I was trying to compose things, and the problems I ran into. For reference, this is all in the context of a companion app prototype I'm writing for our in-development PC/XboxOne MMOFPS. Because it's still under-wraps I obviously can't post screenshots, but I'll try to present (carefully scrubbed) code.

This series is broken into three parts: basics, intermediate, and finally visual aspects where I tie everything together for my fabulous programmer UX.