> For the complete documentation index, see [llms.txt](https://elguerre.gitbook.io/de0an/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elguerre.gitbook.io/de0an/capitulo-5-la-construccion.-implementando-requisitos/refinando.md).

# Refinando (o Refactorizando)

Hemos concluido las páginas *Acerca de* y *Configuración*, no obstante, mejoraremos algunos aspectos en los que iremos incidiendo en capítulos sucesivos.

## Cambios en los conversores

En la página *Acerca de*, usamos dos conversores y aprendimos cómo y cuándo usarlos. Lo que no hicimos fue reutilizar los que ya nos proporciona Template 10. Entre ellos podemos encontrar *ValueWhenConverter*, que más que un conversor, se trata de un control que nos brinda su sintaxis para crear conversores utilizando únicamente XAML. A continuación, podemos ver una representación más sencilla de nuestros conversores actuales.

```xml
<ct10:ValueWhenConverter x:Name="BoolToVisibilityConverter">
    <ct10:ValueWhenConverter.When>
        <x:Boolean>True</x:Boolean>
    </ct10:ValueWhenConverter.When>
    <ct10:ValueWhenConverter.Value>
        <Visibility>Visible</Visibility>
    </ct10:ValueWhenConverter.Value>
    <ct10:ValueWhenConverter.Otherwise>
        <Visibility>Collapsed</Visibility>
    </ct10:ValueWhenConverter.Otherwise>
</ct10:ValueWhenConverter>
<ct10:ValueWhenConverter x:Name="BoolToVisibilityNegationConverter">
    <ct10:ValueWhenConverter.When>
        <x:Boolean>True</x:Boolean>
    </ct10:ValueWhenConverter.When>
    <ct10:ValueWhenConverter.Value>
        <Visibility>Collapsed</Visibility>
    </ct10:ValueWhenConverter.Value>
    <ct10:ValueWhenConverter.Otherwise>
        <Visibility>Visible</Visibility>
    </ct10:ValueWhenConverter.Otherwise>
</ct10:ValueWhenConverter>
```

Aprovecharemos para utilizar estos en su lugar. Eliminaremos por tanto las clases *BooleanToVisibilityConverter* y *BooleanToVisibilityNegationConverter*. A continuación, estas definiciones las incluiríamos y registraríamos en la clase App.xaml, sin embargo, en previsión de saber que implementaremos varios conversores más durante el desarrollo, además de agruparlos en la carpeta *Converters*, incluiremos un nuevo diccionario de recursos con el propósito de registrarlos. De esta manera, nuestra clase *App.xaml*, únicamente tendrá una referencia a este nuevo diccionario y el código quedará mucho más limpio. Procederemos con los siguientes pasos:

1. Crear un nuevo diccionario de recursos en la carpeta *Converters*.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-f281206d42fbe0bf800925ac9143354c35fe521c%2Fimage19.png?alt=media)

**Figura 18.- Diccionario de recursos para conversores**

2. Registrar en él, todas las definiciones de conversores que hasta ahora se encontraban en el fichero *App.xaml*.

```xml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ct10="using:Template10.Converters">
    <!-- Template 10 Converters -->
    <ct10:ValueWhenConverter x:Name="BoolToVisibilityConverter">
        <ct10:ValueWhenConverter.When>
            <x:Boolean>True</x:Boolean>
        </ct10:ValueWhenConverter.When>
        <ct10:ValueWhenConverter.Value>
            <Visibility>Visible</Visibility>
        </ct10:ValueWhenConverter.Value>
        <ct10:ValueWhenConverter.Otherwise>
            <Visibility>Collapsed</Visibility>
        </ct10:ValueWhenConverter.Otherwise>
    </ct10:ValueWhenConverter>
    <ct10:ValueWhenConverter x:Name="BoolToVisibilityNegationConverter">
        <ct10:ValueWhenConverter.When>
            <x:Boolean>True</x:Boolean>
        </ct10:ValueWhenConverter.When>
        <ct10:ValueWhenConverter.Value>
            <Visibility>Collapsed</Visibility>
        </ct10:ValueWhenConverter.Value>
        <ct10:ValueWhenConverter.Otherwise>
            <Visibility>Visible</Visibility>
        </ct10:ValueWhenConverter.Otherwise>
    </ct10:ValueWhenConverter>
</ResourceDictionary>
```

3. Modificar el fichero *App.xaml*, para referenciar a este nuevo diccionario.

```xml
<common:BootStrapper x:Class="ElGuerre.Taskin.Uwp.App"
    ...
    >
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Styles\Custom.xaml" />
                <ResourceDictionary Source="Converters\Converters.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <ResourceDictionary.ThemeDictionaries>
            </ResourceDictionary.ThemeDictionaries>
            <local:LocalizedStrings x:Key="LocalizedStrings" />
            <vm:ViewModelLocator x:Key="Locator" />
        </ResourceDictionary>
    </Application.Resources>
</common:BootStrapper>
```

4. Compilar y asegurar que todo sigue siendo correcto.

{% hint style="info" %}
**Nota**: No reinventemos la rueda cada vez, encontremos lo que buscamos y utilicémoslo. Compartamos nuestro código tanto entre aplicaciones como con la comunidad de desarrolladores. NuGet es nuestro aliado. Además, siempre nos ofrecerá un alto reconocimiento y confianza frente a otros desarrolladores.
{% endhint %}

## Enlace a datos con x:Bind

Hasta ahora el enlazado a datos que hemos utilizado ha sido siempre con *Binding*, sin embargo, existe otra sintaxis para poder hacerlo, *x:Bind*, que permite hacer el enlazado con algunas diferencias:

* Validación en tiempo de compilación, por lo que todos los objetos a enlazar han de estar fuertemente “tipados”.
* El modo de validación predeterminado es *OneTime*.
* Enlazado más rápido y menos consumo de memoria.
* Al ser fuertemente “tipado” no es posible reutilizar plantillas para diferentes tipos de datos. Caso en el cual, bien se define una para cada tipo o bien se emplea *Binding*.
* El enlazado a propiedades o valores de otros controles, resulta más costoso.

Ambos presentan pros y contras dependiendo de cuándo pretendan ser usados, así pues, trataremos de utilizarlo en la medida de posible. Evitaremos errores en tiempo de ejecución (que siempre son más difíciles de detectar) y mejoraremos en rendimiento.

Aplicaremos estos cambios en nuestra aplicación para lo que seguiremos el siguiente procedimiento:

1. Incluir una nueva propiedad en las clases asociadas a las páginas *(AboutPage.xaml.cs y SettingsPage.xaml.cs)*

```csharp
public IAboutViewModel ViewModel => DataContext as AboutViewModel;
...
public ISettingsViewModel ViewModel => DataContext as SettingsViewModel;
```

2. Actualizar la plantilla *AboutSectionsTemplate* de la página *AboutPage.xaml.*

```xml
<DataTemplate x:Key="AboutSectionsTemplate"
    xmlns:m="using:ElGuerre.Taskin.Uwp.Models"
    x:DataType="m:AboutSectionModel">
    <Grid>
        ...
        <ItemsControl Grid.Row="1"
            Grid.Column="1"
            Margin="10,0,0,0"
            ItemsSource="{x:Bind Items}">
            <ItemsControl.ItemTemplate>
                <DataTemplate x:DataType="m:AboutSectionItem">
                    <StackPanel Orientation="Horizontal">
                        …
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</DataTemplate>
```

3. Sustituir *Bindings* por *x:Bind*, para todas las propiedades públicas de los ViewModels. Por ejemplo, para enlazar la propiedad *Section*s (en la página de ayuda), con la propiedad *ItemsSource* del control *ItemsControl*, realizar el siguiente cambio:

```xml
<PivotItem x:Uid="AboutPivotItemInfo" Header="general">
    <ScrollViewer HorizontalScrollMode="Disabled">
        <ItemsControl ItemsSource="{x:Bind ViewModel.Sections}"
            ...
            <ItemsControl.ItemContainerStyle>
        </ItemsControl>
    </ScrollViewer>
</PivotItem>
```

Un caso particular es el enlace de imágenes con la propiedad *ImagePath.* Al existir secciones sin imágenes (en el fichero *AboutSections.json*), *x:Bind* lanza una excepción al intentar enlazar un nulo que no es capaz de convertir a una imagen.

Aunque podríamos solucionar este problema con el siguiente conversor, optaremos por mantener el tipo de enlazado *Binding*.

```csharp
public object Convert(object value, Type targetType, object parameter, string language)
{
    if (!String.IsNullOrEmpty(value as string))
    {
        Uri uri = null;
        string url = value.ToString();
        if (url.StartsWith("/"))
            uri = new Uri(string.Concat("ms-appx://", url),
                UriKind.Absolute);
        else
            uri = new Uri(url, UriKind.Absolute);
        return new BitmapImage(uri);
    }
    return new BitmapImage();
}
```

Concluiremos manteniendo el tipo *Binding*, para el enlazado entre los controles *TextBlock* y *Slider* (en la página de configuración) y para las plantillas *MainCommandBarTemplate*, que incluyen enlaces a comandos.

## Actualización de plantillas personalizadas

Nuestra aplicación ya cuenta con dos páginas con las que cualquier otra aplicación debería contar, por lo que las incluiremos como parte de nuestra plantilla personalizada.

Dispondremos de una plantilla para generar proyectos desde cero. Pero, ¿Qué ocurre con nuevas páginas o ViewModels? ¿Tendremos que crearlas siempre manualmente? Para evitarlo recurriremos a la creación de *snippets*, que no son ni más ni menos que fragmentos de código personalizados que Visual Studio es capaz de reconocer. Crearemos nuestros snippets completando los siguientes pasos:

1. Crear una nueva carpeta (.snippets) en la raíz del proyecto.
2. En la carpeta anterior, crear un nuevo fichero con extensión “ViewModel.snippet”.
3. Al abrirlo dispondremos de una interfaz gráfica para crear y editar nuestro *snippet*. Por ejemplo, para un el código asociado a una página.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-12973a80de6779f4b406b68d48d4b034f1131cea%2Fimage20.png?alt=media)

**Figura 19.- Creación y edición de un Snippet para el código asociado a una página**

4. Encerrar entre símbolos “$” el nombre de la página y todas sus repeticiones. Así, al crear el *snippet*, introduciremos su prefijo una sola vez y el resto del código se generará automáticamente.
5. Desde el menú: “Tool – Snippets Manager…”, seleccionar el lenguaje CSharp
6. Pulsar Añadir (o *Add*) y seleccionar la ruta de la carpeta *Snippets*, que hemos creado en el paso 1.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-87c836e12941fc4e9054d369621eaf0156c4afd1%2Fimage21.png?alt=media)

**Figura 20.- Gestión de snippets con Code Snippets Manager**

7. Pulsar OK para finalizar.

Una vez creado, solo tenemos que usarlo al igual que cualquier otro snippet de .NET, por ejemplo, escribiendo el *shortcut* marcado en la figura 20, es decir, *tipagecs*.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-e035a27eff69520ee9d96cb90b7a16ee940b8f61%2Fimage22.png?alt=media)

**Figura 21.- Snippet para ViewModels en ejecución**

Para más detalle sobre *snippets*, consultar la página: <https://msdn.microsoft.com/es-es/library/z41h7fat.aspx>.

Existen otras alternativas para la personalización de código de clases o páginas, pero por el momento, con ésta será más que suficiente.

{% hint style="info" %}
**Nota**: Durante el capítulo hemos incluido código completo de alguna de las clases con el objetivo de facilitar posibles aclaraciones. En adelante, haremos referencias al nombre de clases, métodos, propiedades, etc., destacando únicamente lo más importante. Ya hemos aprendido la dinámica y contamos con un conocimiento base. Por lo que, en ocasiones nos referiremos a algunos temas en particular en términos más generales. En cualquier caso, no desesperes, encontrarás todo el código publicado en GitHub ([https://github.com/juanluelguerre/Taskin](https://github.com/juanluelguerre/Taskin/tree/develop)). ¡Es más, puede ser el gran momento, para que comiences a participar proponiendo cambios y mejoras en el código!
{% endhint %}
