Compartir a través de


Este artículo proviene de un motor de traducción automática.

Windows Phone

Compilar aplicaciones de MVVM con Xamarin y MvvmCross

Thomas LeBrun

El patrón de modelo-View-ViewModel (MVVM) pretende convertirse en el patrón de referencia de la opción para cualquier aplicación XAML (Windows Presentation Foundation [WPF], Windows 8, Windows Phone y Silverlight). Introducido al principio de WPF, separa las preocupaciones, Testabilidad y mucho más. La mejor parte es que usted puede utilizarlo para cualquier otras tecnologías, incluso aquellos que no utilizan XAML. De hecho, puede utilizar el patrón con ASP.NET, con JavaScript y mucho más.

Xamarin le permite desarrollar aplicaciones Android o iOS en código C#. Estas aplicaciones vienen con sus propios modelos de desarrollo, pero gracias a un marco llamado MvvmCross, usted puede traer el patrón MVVM a estas plataformas tan bien. En este artículo, te voy a dar todo lo que necesitas entender MvvmCross y cómo usarlo en tus aplicaciones Android e iOS.

Un rápido vistazo a MVVM

Ha habido un montón de artículos sobre MVVM últimamente, así que no voy a gastar mucho tiempo revisando el patrón MVVM. Para resumir, MVVM se compone de tres partes: el modelo (que corresponde a los datos que usted querrá mostrar y manipular en la pantalla), la vista (que es el componente de presentación y la interfaz de usuario) y el ViewModel (que tendrá el modelo y Mostrar en la vista mediante el enlace de datos y responderá a la interacción del usuario). Figura 1 muestra una representación gráfica del patrón MVVM.

Resumen del modelo-View-ViewModel patrón
Figura 1 Resumen del modelo-View-ViewModel patrón

En el desarrollo con tecnologías de Microsoft, es fácil ver la reutilización de MVVM. Pero ¿qué pasa con las tecnologías no son de Microsoft? ¿Android? ¿IOS?

Por supuesto, todavía puede implementar sus propios patrones o metodologías, pero no los pueden proporcionar algunas de las características más potentes de MVVM, como enlace de datos y capacidad de prueba. Uno de los mayores beneficios de MVVM siguiente es el ViewModels son fácilmente comprobables. Esto también le permite empujar código de multiplataforma en la vista. Este código lo contrario estarían contenida en una plataforma -­clase específica, como un controlador.

Xamarin y MvvmCross "solucionar" esto y ofrecen una forma unificada de usar MVVM en otras plataformas. Antes de mirar usando MVVM en otras plataformas, voy a tomar un momento para explicar Xamarin.

Xamarin para aplicaciones Android/iOS

Xamarin es un conjunto de herramientas que ofrece alto rendimiento código compilado con acceso completo a todas las APIs nativas. Le permite crear aplicaciones nativas con experiencias específicas de dispositivos. Puedes hacer cualquier cosa que puedes hacer en Objective-C o Java, en C# con Xamarin.

Mientras que puede usar para desarrollar aplicaciones Xamarin Studio, también puede utilizar Visual Studio y todas las otras herramientas que ya utilizas para C# desarrollo hoy. Esto incluye Team Foundation Server (para el control de código fuente) y plug-ins como Resharper, GhostDoc y así sucesivamente.

Desde la perspectiva de un desarrollador, Xamarin ofrece tres principales products—Xamarin.Mac, Xamarin.iOS (MonoTouch.dll) y Xamarin.Android (Mono.Android.dll). Todos estos son desarrollados en la cima de Mono, la versión open source de Microsoft .NET Framework. Mono en realidad inicialmente fue creado por Miguel De Icaza, cofundador y actual director técnico de Xamarin.

En iOS, un dedicado compilador compila aplicaciones escritas directamente en código nativo de brazo en C#. Para Android, el proceso es similar a la ejecución y la compilación. net. Se compila el código fuente a un lenguaje intermedio (IL). Cuando el código se ejecuta en el dispositivo, una segunda compilación (realizada justo a tiempo) compila el código IL a código nativo. Esto tiene sentido porque las aplicaciones de Android están desarrolladas en Java, que tiene una arquitectura interna similar a la arquitectura de .NET Framework. Se puede ver una representación visual del proceso de compilación para iOS y Android en figura 2.

compilación nativa con Xamarin
Figura 2 compilación nativa con Xamarin

La mayoría de las veces, no tienes que preocuparse por la gestión de memoria, asignación de recursos y así sucesivamente porque todo está gestionado por el tiempo de ejecución que proporciona Xamarin. Sin embargo, hay casos cuando tienes que ser consciente de lo que sucede, como interoperabilidad con Objective-C. Esto podría crear ciclos o donde su clase administrada en realidad envuelve algunos recursos caros, como UIImage en iOS. Para más información, consulte bit.ly/1iRCIa2.

Hay consideraciones especiales para aplicaciones de iOS. Mientras que Xamarin Studio en un Mac proporciona todo lo necesario para iOS devel­sarrollo, los usuarios de Visual Studio en un PC tendrá un Mac con Xamarin herramientas instaladas. Esto le permite compilar aplicaciones sobre la red y probar en el simulador de iOS o un dispositivo iOS.

Xamarin le permite construir iOS y Android aplicaciones usando C# o F #, pero utilizando el patrón Model-View-Controller tradicional. Si quieres portabilidad, mantenibilidad y mayor capacidad de prueba, usted necesita una manera de traer el patrón MVVM a estas plataformas. Entrar en MvvmCross.

MvvmCross para aplicaciones Xamarin

MvvmCross es una fuente abierta, marco MVVM multiplataforma desarrollado por Stuart Lodge. Está disponible para aplicaciones WPF y Android, iOS, Windows Phone, Windows 8. MvvmCross trae el patrón MVVM a plataformas donde estaba antes no estaban disponible, como iOS y Android.

También admite el enlace de datos en las vistas. Esta es una característica de gran alcance que proporciona gran separación de preocupaciones. El punto de vista utilizará el ViewModels ofrecer comportamientos adecuados en la aplicación. MvvmCross incluso se localiza la ViewModels en un proyecto dedicado para que pueda fácilmente de referencia y reutilizarlos en otros.

Este es el punto más importante cuando se habla de MvvmCross. Ubicando la ViewModels en una biblioteca de clase Portable (PCL), puede añadirlos como referencia para cualquier otro proyecto. Por supuesto, no es el único interesante punto de MvvmCross. También hay una plug-in arquitectura, inyección de dependencias (DI) y mucho más.

Usando MvvmCross en Android/iOS

Usar MvvmCross es fácil porque es sólo unos pocos paquetes de NuGet que agrega a sus proyectos. Una vez que hayas hecho esto, hay unos pasos menores, que tienes que tomar antes de iniciar la aplicación. Las medidas varían un poco entre iOS y Android, pero son bastante similares. El proyecto de base contiene tu ViewModels y la clase App. Esto inicializa los servicios y define el ViewModel que iniciaremos en lanzamiento:

public class App : MvxApplication
{
  public override void Initialize()
  {
    this.CreatableTypes()
      .EndingWith("Service")
      .AsInterfaces()
      .RegisterAsLazySingleton();
    this.RegisterAppStart<HomeViewModel>();
  }
}

En tu aplicación Android o iOS, tienes que crear un archivo Setup.cs. Esto será el proyecto de base de referencia y saber cómo crear una instancia de la aplicación el tiempo de ejecución:

public class Setup : MvxAndroidSetup
{
  public Setup(Context applicationContext) : base(applicationContext)
  {
  }
  protected override IMvxApplication CreateApp()
  {
    return new Core.App();
  }
}

Entonces el archivo de instalación crea la aplicación utilizando el archivo de la aplicación. Éste indica que el tiempo de ejecución para cargar un ViewModel particular al iniciarse mediante el método RegisterAppStart.

Cada vista es específico para cada aplicación. Esta es la única parte que cambia. En Android, la clase hereda de MvxActivity (actividades estándar en Android heredan de actividad). Para iOS, las opiniones se heredan de MvxViewController (estándar ViewController en iOS heredan de UIViewController):

[Activity(ScreenOrientation = ScreenOrientation.Portrait)]
public class HomeView : MvxActivity
{
  protected override void OnViewModelSet()
  {
    SetContentView(Resource.Layout.HomeView);
  }
}

MvvmCross necesita saber el ViewModel con el cual se asocia una vista. Puedes hacerlo gracias a la Convención de nomenclatura predeterminada. Usted puede cambiar fácilmente también lo reemplaza la propiedad ViewModel de la vista o utilizando el MvxViewForAttribute:

[Activity(ScreenOrientation = ScreenOrientation.Portrait)]
[MvxViewFor(typeof(HomeViewModel))]
public class HomeView : MvxActivity
{ ... }

En iOS y Android, las opiniones están diseñadas con diferentes enfoques. En iOS, la vista está definida en el código de C#. En Android, también puede utilizar código de C#. Mejor aún, sin embargo, puede utilizar el formato AXML (formato XML utilizado para describir la interfaz de usuario en Android). Debido a estas diferencias, enlaces de datos se definen diferentemente en cada plataforma.

En iOS, es crear un BindingDescriptionSet para representar el enlace entre la vista y la vista. En ese conjunto, puede especificar que el control que desea enlazar a la propiedad que antes de aplicar el enlace:

var label = new UILabel(new RectangleF(10, 10, 300, 40));
Add(label);
var textField = new UITextField(new RectangleF(10, 50, 300, 40));
Add(textField);
var set = this.CreateBindingSet<HomeView, 
  Core.ViewModels.HomeViewModel>();
set.Bind(label).To(vm => vm.Hello);
set.Bind(textField).To(vm => vm.Hello);
set.Apply();

En Android usando AXML, puede utilizar el nuevo atributo XML MvxBind para realizar el enlace de datos:

<TextView xmlns:local="http://schemas.android.com/apk/res-auto"
          android:text="Text"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:id="@+id/tripitem_title"
          local:MvxBind="Text Name"
          android:gravity="center_vertical"
          android:textSize="17dp" />

El atributo MvxBind toma en parámetros que especifican la propiedad de enlazar el control y la propiedad del ViewModel a utilizar como la fuente. Si eres un desarrollador XAML, tenga en cuenta que el modo de MvvmCross es TwoWay por defecto. En XAML, el modo de enlace por defecto es OneWay. El marco MvvmCross comprende unos atributos XML personalizados disponibles en Mvx­BindingAttributes.xml, como pueden ver en figura 3.

Figura 3 contenido del archivo MvxBindingAttributes.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-stylable name="MvxBinding">
    <attr name="MvxBind" format="string"/>
    <attr name="MvxLang” format="string"/>
  </declare-styleable>
  <declare-stylable name="MvxControl">
    <attr name="MvxTemplate" format="string"/>
  </declare-styleable>
  <declare-styleable name="MvxListView">
    <attr name="MvxItemTemplate" format= "string"/>
    <attr name="MvxDropDownItemTemplate" format="string"/>
  </declare-stylable>
  <item type="id" name="MvxBindingTagUnique">
  <declare-styleable name="MvxImageView">
    <attr name="MvxSource" format="string"/>
  </declare-stylable>
</resources>

El contenido de este archivo es simple, pero muy importante. El archivo indica los atributos que se pueden utilizar en los archivos AXML. Así, se puede ver en una operación de enlace, puede utilizar atributos MvxBind o MvxLang. También puede utilizar algunos controles nuevos (MvxImageView, MvxListView). Cada uno de ellos ha dedicado los atributos personalizados, como se puede ver en
figura 4.

Figura 4 nuevos controles tienen atributos personalizados

<LinearLayout
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_weight="2">
  <Mvx.MvxListView
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    local:MvxBind="ItemsSource Trips;ItemClick SelectTripCommand"
    local:MvxItemTemplate="@layout/tripitemtemplate" />
</LinearLayout>

Esto debería ser familiar a los desarrolladores de XAML. Las propiedades ItemsSource y ItemClick están obligadas a algunas propiedades del origen de datos (el problema en este caso). La MvxItemTemplate define la interfaz para cada elemento en el control ListView.

Se puede esperar la sintaxis para iOS será muy diferente, pero, en realidad, es bastante similar. La sintaxis utilizada en el archivo AXML, denominada "Fluido" atascamiento, es simplemente un formato de texto vinculante que puede asignar a así como la versión C#. El comando utilizado en el ejemplo anterior para seleccionar un elemento en la lista es un objeto ICommand:

public ICommand<Trip> SelectTripCommand { get; set; }

La implementación de esta interfaz es proporcionada por MvvmCross utilizando la clase MvxCommand:

private void InitializeCommands()
{
  this.SelectTripCommand = new MvxCommand<Trip>(
    trip => this.ShowViewModel<TripDetailsViewModel>(trip),
    trip => this.Trips != null && this.Trips.Any() && trip != null);
}

Un problema común cuando se usa el patrón MVVM es conversión de tipos. Esto sucede cuando se definir propiedades usando un tipo que no esté directamente consumible por la interfaz de usuario. Por ejemplo, tal vez tengas una propiedad de imagen como una matriz de bytes, pero que desea utilizar para la propiedad source de un control de imagen. En XAML, puede solucionar este problema con la interfaz IValueConverter, que asigna los valores entre la vista y la vista.

El proceso es muy similar con MvvmCross, gracias a la interfaz IMvxValueConverter y sus dos métodos Convert y ConvertBack. Esta interfaz permite realizar conversiones similares a XAML, pero con un tecnología cross-objetivo en mente. Tenga en cuenta esta interfaz tiene el mismo inconveniente como XAML. Toma un objeto como parámetro y devuelve como el valor. Bastidor es requerido. Para optimizar esto, MvvmCross ofrece la clase genérica MvxValueConverter, que se lleva en los parámetros para la entrada y los tipos de devolución:

public class ByteArrayToImageConverter : 
  MvxValueConverter<byte[], Bitmap>
{
  protected override Bitmap Convert(byte[] value, Type targetType,
    object parameter, CultureInfo culture)
  {
    if (value == null)
        return null;
    var options = new BitmapFactory.Options { InPurgeable = true };
    return BitmapFactory.DecodeByteArray(value, 
      0, value.Length, options);
  }
}

Referencia del convertidor es fácil. En iOS, utilice el método WithConversion en la sintaxis del fluido:

var set = this.CreateBindingSet<HomeView, 
  Core.ViewModels.HomeViewModel>();
set.Bind(label).To(vm => vm.Trips).WithConversion("ByteArrayToImage");
set.Apply();

En Android, la referencia del convertidor directamente en el archivo AXML:

<ImageView
  local:MvxBind="Bitmap Image,Converter=ByteArrayToImage"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content" />

Convertidores están ubicados por sus nombres utilizando la reflexión. De forma predeterminada, el marco buscará cualquier tipo que contenga "convertidor" en el nombre. Usted puede inscribirse también manualmente convertidores sobreescribiendo el método FillValueConverters en la clase de configuración.

MvvmCross proporciona un DIcontainer sencillo y ligero. Usted puede registrar las clases e interfaces en el contenedor utilizando patrones múltiples, incluyendo un registro de singleton, un registro dinámico y más:

Mvx.RegisterType<ISQLiteConnectionFactory, SQLiteConnectionFactory>();
Mvx.RegisterSingletong<ISQLiteConnectionFactory, SQLiteConnectionFactory>();

Resolución de tipos en el contenedor puede suceder dos maneras. En primer lugar, usted puede utilizar el método Mvx.Resolve para resolver explícitamente el tipo. También es compatible con la inyección de constructor, que permite MvvmCross realizar reflexión y resolver automáticamente los parámetros durante la creación del objeto:

private readonly ISQLiteConnectionFactory _sqlFactory;
public DataAccessLayerService(ISQLiteConnectionFactory sqlFactory)
{
  this._sqlFactory = sqlFactory;
}

Usted puede utilizar la inyección de constructor para servicios, así como ViewModels. Esto es importante para entender porque cualquiera de los servicios desarrollado para su aplicación en el proyecto es, por defecto, multiplataforma.

También puede aprovechar los servicios que parecen ser multiplataforma, pero para qué aplicación es específica de la plataforma. Por ejemplo, tomar una foto con la cámara, consiguiendo el usuario coordina, usando una base de datos y así sucesivamente. Con inyección de constructor, ViewModels pueden recibir una interfaz donde la aplicación es específica de la plataforma.

Para definir este mecanismo de inyección y código específico de plataforma, MvvmCross proporciona un sistema de plug-in. El sistema le permite crear e inyectar nuevas características en tiempo de ejecución. Cada plug-in es un servicio, expuesto por un interfaz, que tiene una aplicación concreta para cada plataforma. El sistema registra la interfaz e implementación. Aplicaciones consumen los plug-ins con DI. DI también permite a los desarrolladores de plug-in proporciona una implementación simplificada "burlarse de" las pruebas y desarrollo.

Desde la perspectiva de un desarrollador, escribir un plug-in es tan sencillo como escribir una interfaz. Se crea una clase que implementa la interfaz y un cargador plug-in. El cargador plug-in es una clase que implementa la interfaz IMvxPluginLoader. Registra el plug-in interfaz e implementación (usando Mvx.RegisterType) cuando se llama a su método EnsureLoaded.

Existen muchos plug-ins disponibles. Le proporcionan características tales como acceso a los archivos, correo electrónico, conversión de JSON y así sucesivamente. Usted puede encontrar la mayoría de ellos usando NuGet. Tenga en cuenta que algunos plug-ins no incluir implementaciones para todas las plataformas. Preste atención a este detalle cuando planea aprovechar un plug-in. Incluso si un plug-in le falta apoyo para su plataforma, le resultará más fácil seguir el patrón e implementar la plataforma falta en lugar de crear un nuevo plug-in por tu cuenta. Si esto sucede, considera contribuir su implementación a dueño del plug-in para que otros también pueden utilizar también.

MvvmCross es un valioso marco. Considere esto en el desarrollo de aplicaciones móviles — incluso en Android y iOS. El patrón MVVM, juntado con el enlace de datos y plug-ins, proporciona un potente sistema para crear código altamente portátil y mantenible.


Thomas LeBrun es una consultora en la Plaza de infinito, un socio francés Microsoft trabajando en tecnologías como Windows 8, Windows Phone, Windows Presentation Foundation (WPF), Silverlight, superficie y mucho más. Ha escrito dos libros sobre WPF y el patrón MVVM. También es un ponente habitual en eventos comunitarios. Lo puedes seguir es blog en blog.thomaslebrun.net y en Twitter en twitter.com/thomas_lebrun.

Gracias al siguiente experto técnico de Microsoft por revisar este artículo: Jared Bienz