Compartir a través de


Parte II. Notas Rapidas (sticky notes) App W8: MVVM y SQLite (es-ES)

**Arquitectura y Desarrollo.  **

Antes de comenzar con la parte medular del Modelo, hay que ejemplificar el diseño arquitectónico para el flujo de la información que va a tener la aplicación utilizando el patrón MVVM, el cual debería de ser de esta forma:

https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F2.bp.blogspot.com%2F-alr30tByS1I%2FUJFqaok9bHI%2FAAAAAAAAAA4%2FHF4mU80zWLo%2Fs1600%2Farquitectura.png&container=blogger&gadget=a&rewriteMime=image%2F*

 

En lo particular he obtenido excelentes resultados al crear clases para cada entidad de negocio e implementar la interface INotifyPropertyChanged en cada una, de esta forma se personaliza el desarrollo y a la vez el encapsulamiento de acceso a datos para que sea accedido por cualquier ViewModel  cuando sea solicitado, de esta forma estas clases en conjunto con Entity Framework pasarían a ser el componente “Model” de nuestra arquitectura.

Lo primero es crear una clase base y abstracta que nos ayude en la implementación de la interfaz INotifyPropertyChanged  hacia todas las clases de lógica de negocio. El enlace de datos o DataBinding es un componente básico del modelo MVVM, de esta forma el centro del enlace de datos es la interfaz INotifyPropertyChanged, esta interfaz aparentemente simple se utiliza para sincronizar los cambios de propiedad de un objeto con los controles (listbox, texblock, grid, stackpanel, etc) de la interfaz de usuario (View). Para mayor comprensión del uso de este patrón puedes consultar la página oficial de MVVM.

Bien entonces se va a  crear la clase denominada ModeloNotasRapidas, comenzaremos definiendo la implementación de INotifyPropertyChanged, se tendrá que ver de esta forma:

https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F1.bp.blogspot.com%2F-U69sQHhcGhI%2FUJFrUEVnNXI%2FAAAAAAAAABA%2F6EDZWFcFb6o%2Fs1600%2Fnotify.png&container=blogger&gadget=a&rewriteMime=image%2F*

 

 

Ahora se crearan las propiedades y los métodos los cuales estarán en lazados con la clase que va a manipular las acciones de la base de datos, definiremos estos métodos como CrearNotaRapida, EliminarNotaRapida, RetornarNotasRapidas. De esta forma se debe de tener:

        #region Metodos

        public async void CrearNotaRapida(string titulo, string dato)

        { 

           NotaCreada = await  bdmanager.CreateNote(titulo, dato);

        }

        public async void RetornarNotasRapidas()

        {

            ListaNotas =  await bdmanager.ReturnNotes();

        }

        public  async void EliminarNotaRapida(TablaNota dataNotes)

        {

           RemoverNota =  await bdmanager.RemoveNote(dataNotes);

        }

        #endregion

#region Propiedades

        public List<TablaNota> listanotas;

        public List<TablaNota> ListaNotas

        {

            get

            {

                return listanotas;

            }

            set

            {

                listanotas = value;

                RaisePropertyChanged("ListaNotas");

            }

        }

 

        public bool notaCreada

        public bool NotaCreada

        {

            get

            {

                return notaCreada;

            }

            set

            {

                notaCreada = value;

                RaisePropertyChanged("NotaCreada");

            }

        }

        public bool removerNota;

        public bool RemoverNota

        {

            get

            {

                return removerNota;

            }

            set

            {

                removerNota = value;

                RaisePropertyChanged("RemoverNota");

            }

        }

        #endregion

Por el momento se tienen los elementos básicos para poder iniciar a crear el ViewModel, lo primero que se debe de realizar es des comentar las líneas de código que por defecto:

            if (IsInDesignMode)

            {

                // Code runs in Blend --> create design time data.

            }

            else

            {

                // Code runs "for real"

            }

Donde:

Si IsInDesigMode es Verdadero:

Es cuando se está desarrollando en Expression Blend y puedas ver reflejado en modo de diseño, Si no es así, si el desarrollo lo estas llevando acabo el Visual Studio 2012 debes de poner el código en la parte de Else.

Lo primero que se debe de realizar es la instancia del ModeloNotasRapidas de forma global private ModeloNotasRapidas modelo, así de esta forma se podrá crear la sincronizar los cambios de propiedad de un objeto del modelo: 

modelo.PropertyChanged += ModeloOnPropertyChanged;

private void ModeloOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)

        {

            switch (propertyChangedEventArgs.PropertyName)

            {

                case "NotaCreada":

                    RaisePropertyChanged("NotaCreada");

                    break;

                case "RemoverNota":

                    RaisePropertyChanged("RemoverNota");

                    break;

                case "ListaNotas":

                    RaisePropertyChanged("ListaNotas");

                    break;

            }

        }

Una vez teniendo esto se debe de considerar el tener cambio de propiedad para cada uno de los métodos que contenemos en el modelo como lo es el crear, remover y listar las notas rápida para ello se debe de considera tener propiedades, comandos y métodos de acción, esto debería quedar de la siguiente forma:

        #region Propiedades

        public List<TablaNota> ListaNotas

        {

            get

            {

                return modelo.ListaNotas;

            }

        }

        public TablaNota notaSeleccionada;

        public TablaNota NotaSeleccionada

        {

            get

            {

                return notaSeleccionada;

            }

            set

            {

                notaSeleccionada = value;

                RaisePropertyChanged("NotaSeleccionada");

            }

        }

        public string datoNota;

        public string DatoNota

        {

            get

            {

                return datoNota;

            }

            set

            {

                datoNota = value;

                RaisePropertyChanged("DatoNota");

            }

        }

        public string titulo;

        public string Titulo

        {

            get

            {

                return titulo;

            }

            set

            {

                titulo = value;

                RaisePropertyChanged("Titulo");

            }

        }

        #endregion

        #region Comandos

        /// <summary>

        /// Gets AgregarNotaCommand.

        /// </summary>

        public RelayCommand AgregarNotaCommand

        {

            get { return new RelayCommand(ExecuteAgregarNota); }

        }

        /// <summary>

        /// Gets EliminarNotaCommand.

        /// </summary>

        public RelayCommand EliminarNotaCommand

        {

            get { return new RelayCommand(ExecuteEliminarNota); }

        }

 

        public ICommand NotaSeleccionadaCommand

        {

            get;

            private set;

        }

        #endregion

        #region Accion

        private void ExecuteNotaSeleccionadaAsync(TablaNota obj) { }

 

        /// <summary>

        /// Ejecuta la acción Agregar Nota.

        /// </summary>

        private void ExecuteAgregarNota()

        {

            if(!string.IsNullOrEmpty(DatoNota))

            {

                modelo.CrearNotaRapida(Titulo, DatoNota);

                Titulo = "Titulo";

                DatoNota = "";

            }     

        }

        /// <summary>

        /// Ejecuta accion Eliminar nota

        /// </summary>

        private void ExecuteEliminarNota()

        {

            if (NotaSeleccionada != null)

                modelo.EliminarNotaRapida(NotaSeleccionada);

        }

        #endregion

Para la vista se deben de considerar el tener un usercontrol con el nombre NotasControl el cual deberá de estar constituido por una ListView este elemento será el que contendrá a las notas por medio de un datatemplate, al calce del XAML ire puntualizando a detella, entonces debe de estar de la siguiente manera:

<UserControl

    x:Class="NotasRapidas.Views.NotesControl"

    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d=http://schemas.microsoft.com/expression/blend/2008

    xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006

    mc:Ignorable="d"

    d:DesignHeight="650" Width="1356">

       <UserControl.Resources>

              <DataTemplate x:Key="DataTemplate">

                     <Grid Height="244" Width="241" Margin="25">

                           <Grid.Background>

                                  <ImageBrush ImageSource="ms-appx:///imagen/stickynote.png" Stretch="UniformToFill"/>

                           </Grid.Background>

                <TextBox  HorizontalAlignment="Left" Height="37" Margin="12,8,0,0" TextWrapping="Wrap" Text="{Binding Titulo}" VerticalAlignment="Top" Width="106" Foreground="#FF67E410" TextChanged="TextBox_TextChanged_1"  />

                <TextBox  HorizontalAlignment="Left" Height="141" Margin="10,51,0,0" TextWrapping="Wrap" Text="{Binding Dato}" VerticalAlignment="Top" Width="215" Foreground="#FF67E410" TextChanged="TextBox_TextChanged_2"  />

                <TextBlock HorizontalAlignment="Left" Height="37" Margin="123,8,0,0" TextWrapping="Wrap" Text="{Binding Fecha}" VerticalAlignment="Top" Width="102" Foreground="#FF67E410"/>

                     </Grid>

              </DataTemplate>

       </UserControl.Resources>

Este código muestra el template de la nota rápida, cuenta con un cambio de propiedad en su texto para que este se notifique al viewmodel el nuevo texto que contendrá la nota tanto en título como en información, la apariencia que tendrá el template es la siguiente:

https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F4.bp.blogspot.com%2F-HOvAQVnmqzg%2FUJFtSNw5y0I%2FAAAAAAAAABI%2F8LXUFEDwV1A%2Fs1600%2Fnota.png&container=blogger&gadget=a&rewriteMime=image%2F*

<Grid>

<Border BorderBrush="Yellow" CornerRadius="0" BorderThickness="0,0,0,6" Background="Transparent" Margin="0,0,0,601">

            <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" Margin="0,0,0,6" Width="315">

                <Button x:Name="btnAdd" Content="Agregar" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="#FFFBC407" Command="{Binding Path=AgregarNotaCommand}" Height="37" Click="btnAdd_Click"/>

                <Button x:Name="btnDelete" Content="Eliminar" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  Background="#FFFBC407"  Command="{Binding Path=EliminarNotaCommand}"  Click="btnDelete_Click"/>

            </StackPanel>

        </Border>

Los Command de Agregar y Eliminar, son enviados al viewmodel para que ahí se procese una acción ya sea agregar una nota o eliminar una nota.

Los eventos click que manejan los botones son únicamente para validar que los textos no vayan vacíos y enviar un mensaje de verificación.

        <Grid Margin="0,54,0,0" Background="#FFF89A1E">

            <ListView x:Name="ListaNotes"  ItemTemplate="{StaticResource DataTemplate}" SelectedItem="{Binding Path=NotaSeleccionada, Mode=TwoWay}"

                    ItemsSource="{Binding ListaNotas}"

                      HorizontalAlignment="Left" Width="1356"

            IsItemClickEnabled="{Binding NotaSeleccionadaCommand}"  >

              <ListView.ItemsPanel>

                    <ItemsPanelTemplate>

                        <WrapGrid MaximumRowsOrColumns="4"  Orientation="Horizontal"/>

                    </ItemsPanelTemplate>

                </ListView.ItemsPanel>

            </ListView>

        </Grid>

    </Grid>

</UserControl>

Dentro de las propiedades que contiene ListView, se agregaran:

SelectedItem una notificación al viewmodel sobre el elemento seleccionado, este nos servirá para saber cual sera removido.

IsItemClickEnable. Esta acción nos enviara al comando la selección de la nota, enmarcando el recuadro de la nota.

La apariencia que tendrá el control en general será la siguiente:

https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F2.bp.blogspot.com%2F-CSA7tjxDWTk%2FUJFuEmQbFhI%2FAAAAAAAAABQ%2FeX03OeQm8RE%2Fs1600%2FaparienciaVnta.png&container=blogger&gadget=a&rewriteMime=image%2F*

 

La apariencia general que deberá de contener el proyecto es la siguiente:

https://images-blogger-opensocial.googleusercontent.com/gadgets/proxy?url=http%3A%2F%2F2.bp.blogspot.com%2F-CTyctNj9lFQ%2FUJFuSb_OvcI%2FAAAAAAAAABY%2FsOD9zkYXD6I%2Fs1600%2FaparienciaGral.png&container=blogger&gadget=a&rewriteMime=image%2F*

Trate de englobar lo más importante que se utiliza en el patrón MVVM, también realice algunas adecuaciones para la rotación de la pantalla, por mencionar alguna, pongo el código compartido para que puedan ver a mayor detalle algunas cosas que omitiera.

La Parte III. Incluirá el proceso de publicación de esta aplicación en Windows Store.

Cualquier duda o comentario, la contestare de inmediato. Saludos