Archivo por meses: junio 2021

Acceder a los recursos definidos en ResourceDictionary o Application.Resources desde código (C#) (Xamarin.Forms y NET MAUI)

Pues eso… es alqo que me ha estado dando un poco la lata en las aplicaciones de Xamarin.Forms, y es acceder a los recursos definidos en el fichero App.xaml tanto dentro de Application.Resources como en las definiciones de ResourceDictionary.

Aquí te explico cómo hacerlo en los dos casos, además de usar un fichero externo con las definiciones de los recursos.

 

Contenido:

 

Empezaré con las definiciones directas en los recursos de App.xaml.

Acceder desde código a las definiciones de recursos definidos en App.xaml

 —

Acceder desde código a las definiciones de Application.Resources

Para acceder a los recursos definidos en Application.Resources desde código es simple (al menos cuando se sabe cómo 😉 ).
Por ejemplo, si tenemos dos recursos definidos, uno ColorAzul1 y el otro ColorAzul2, de esta forma:

<Application.Resources>
    <Color x:Key="ColorAzul">#0073cf</Color>
    <Color x:Key="ColorRojo">Firebrick</Color>
</Application.Resources>

Si queremos usar uno u otro desde código dependiendo de alguna condición, por ejemplo que estemos usando la app en Android o en iOS y que ocurra alguna otra condición (ver nota), podemos hacerlo de esta forma:

if (esUnaPrueba)
    LabelInternet.TextColor = (Color)Application.Current.Resources["ColorAzul"];
else
    LabelInternet.TextColor = (Color)Application.Current.Resources["ColorRojo"];

Como ves en el código a los recursos definidos en Application.Resources se accede usando Application.Current.Resources["key del recurso"];

El cast usando en el código de ejemplo es necesario ya que el valor devuelto por ese elemento de la colección Resources es de tipo object.
Esa forma de hacerlo la conocí gracias a esta entrada en los foros de Xamarin.

Nota: Lo de que ocurra alguna otra condición es porque en los recursos podemos indicar para qué plataforma lo definimos. Aunque para el caso de los colores no sé muy bien como se haría, para el resto puedes ver esto.

 

Acceder desde código a las definiciones de ResourceDictionary

Por otro lado, si el recurso lo tenemos en una rama de ResourceDictionary, por ejemplo de esta forma:

    <ResourceDictionary>
        <Color x:Key="Color2Azul">#0073cf</Color>
        <Color x:Key="Color2Rojo">Firebrick</Color>
    </ResourceDictionary>
</Application.Resources>

Para acceder a esos recursos definidos en ResourceDictionary desde el código de C# lo tendrás que hacer de esta otro forma:

if (esAzul)
    LabelInternet2.SetDynamicResource(Label.TextColorProperty, "Color2Azul");
else
    LabelInternet2.SetDynamicResource(Label.TextColorProperty, "Color2Rojo");

El truco para usar esa otro forma, lo saqueé del mismo post que te indiqué antes, pero estaba abajo del todo, concretamente de aquí.
A lo mejor hay otra forma, pero… a mí me ha servido esta que te muestro.

 

Ahora toca explicarte cómo agregar ficheros de recursos (ResourceDictionary) y usarlos directamente en los recursos del fichero App.Xaml.

Definir recursos (ResourceDictionary) en fichero separado y usarlo en App.xaml

También puedes usar esos ficheros de recursos desde una página concreta.

Ahora también te lo explicaré, que a mí me da mucho coraje cuando se comenta algo así en un post y después no se explica porque se supone que se sabe cómo hacerlo… y aunque puede que sepas cómo hacerlo (eso hasta yo lo sabía hace unos cuantos años cuando empecé con todo esto de XAML, hará al menos 16 años), puede que hayas encontrado este post al buscar cómo hacer eso concretamente y no el resto de cosas que estoy explicando.

Crear un fichero XAML de recursos del tipo ResourceDictionary

En el proyecto añade un nuevo fichero del tipo XAML, yo no he visto cómo agregar uno directamente desde la ventana de agregar nuevo elemento al proyecto, así que, puedes agregar un fichero de texto y después cambiarle la extensión de .txt a .xaml 😉
En la figura 1 puedes ver más claro cómo agregar ese fichero.

Figura 1. Añadir un nuevo fichero al proyecto.

Nota: Después de agregar el fichero y cambiar la extensión (ya sea a la hora de crearlo como es el ejemplo de la figura 1 o si le cambias posteriormente la extensión, es recomendable cerrarlo y después abrirlo, si no, el Intellisense no se cosca de que es del tipo que tiene la extensión. Esto también es válido para ficheros de código al que inicialmente lo has creado como .TXT y después lo cambias a .CS.

Ese fichero estará vacío, así que… habrá que ponerle algo de código, concretamente este que te muestro para que sea un fichero válido del tipo ResourceDictionary.

<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

</ResourceDictionary>

Aquí voy a definir algunas cosas para ver cómo funciona, tanto en modo diseño (en el código XAML de las páginas) como desde el código (en estos ejemplos solo de C# que es lo que me permite usar loss proyectos de Xamarin.Forms.
Aunque lo mismo hago pruebas con aplicaciones del tipo UWP que ahí sí se pueden crear proyetos de C# o de mi querido Visual Basic 😉

En ese fichero de recursos agrega las siguientes definiciones de colores y estilos de etiquetas para que quede como te muestro a continuación.

<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

    <Color x:Key="Color3Azul">#0073cf</Color>
    <Color x:Key="Color3Rojo">Firebrick</Color>
    <Color x:Key="Color3Blanco">White</Color>

    <Style x:Key="LabelEjemplo3" TargetType="{x:Type Label}">
        <Setter Property="FontSize" Value="Small"/>
        <Setter Property="FontAttributes" Value="None" />
        <Setter Property="HorizontalTextAlignment" Value="Start"/>
        <Setter Property="HorizontalOptions" Value="FillAndExpand"/>
        <Setter Property="Padding" Value="4"/>
        <Setter Property="TextColor" Value="Green"/>
        <Setter Property="BackgroundColor" Value="{DynamicResource Key=Color3Blanco}"/>
    </Style>
    <Style x:Key="LabelEjemplo3Azul" TargetType="{x:Type Label}">
        <Setter Property="FontSize" Value="Small"/>
        <Setter Property="FontAttributes" Value="Italic" />
        <Setter Property="HorizontalTextAlignment" Value="Start"/>
        <Setter Property="HorizontalOptions" Value="FillAndExpand"/>
        <Setter Property="Padding" Value="4"/>
        <Setter Property="TextColor" Value="{StaticResource Color3Azul}"/>
        <Setter Property="BackgroundColor" Value="{StaticResource Color3Blanco}"/>
    </Style>
    <Style x:Key="LabelEjemplo3Rojo" TargetType="{x:Type Label}">
        <Setter Property="FontSize" Value="Small"/>
        <Setter Property="FontAttributes" Value="Bold" />
        <Setter Property="HorizontalTextAlignment" Value="Start"/>
        <Setter Property="HorizontalOptions" Value="FillAndExpand"/>
        <Setter Property="Padding" Value="4"/>
        <Setter Property="TextColor" Value="{StaticResource Color3Rojo}"/>
        <Setter Property="BackgroundColor" Value="{StaticResource Color3Blanco}"/>
    </Style>

</ResourceDictionary>

 

Usar un fichero de recursos (ResourceDictionary) desde una página

Y con eso puedes hacer lo siguiente para incluir el fichero de recursos en una página concreta.
Se supone que la página está en una carpeta (en mi caso en la carpeta elGuille) y el fichero de recursos está en el raíz del proyecto. Por tanto tengo que usar ../ para acceder al fichero que está en un path superior. Esto es como cuando accedes a los ficheros, así que no creo que tengas problemas para entenderlo… o eso espero, porque en esto sí que no voy a profundizar 😉

<ContentPage.Resources>
    <ResourceDictionary Source="../ResourceDictionaryElGuille.xaml"/>
</ContentPage.Resources>

Nota: Si estuviera en otra carpeta, tendrás que indicarlo en el path de la propiedad Source. Por ejemplo si la carpeta está en el raíz del proyecto y se llama Recursos, el valor de Source quedaría así: Source="/Recursos/ResourceDictionary2.xaml".

 

Usar por código un recurso (estilo) definido en ResourceDictionary.

Para usar, en este ejemplo, un estilo definido, habría que hacerlo de esta forma:

if (usarEstiloAzul)
    LabelInternet3.SetDynamicResource(Label.StyleProperty, "LabelEjemplo3Azul");
else
    LabelInternet3.SetDynamicResource(Label.StyleProperty, "LabelEjemplo3Rojo");

Es decir, como en el caso de los colores, pero en lugar de usar TextColorProperty, es decir, una propiedad, uso StyleProperty para indicar que es un estilo lo que quiero aplicar desde el fichero de recursos.

 

Por último voy a explicarte cómo agregar ese fichero de recursos (ResourceDictionary) al fichero App.xaml y así poder usarlo en toda la aplicación.

Usar un fichero de recursos (ResourceDictionary) en App.xaml

Seguramente esto parece no tener mucho sentido, ya que si defines los recursos directamente en el fichero App.xaml ¿por qué hacerlo en otro fichero?

En mi caso, la respuesta es la siguiente:
Yo tengo un proyecto de Xamarin Forms que define las clases a usar en la aplicación móvil (Android, iOS y UWP), llamaré Proyecto1 a ese proyecto base (el que se usa desde los proyectos específicos de cada plataforma).

Ahora creo otro proyecto móvil (que llamaré Proyecto2) que tiene también como punto de entrada el fichero App (es lo habitual) y que usa la DLL del proyecto anterior (Proyecto1). Lo hago así, porque la funcionalidad es la misma, pero por circunstacias que no viene al caso profundizar mucho en ellas, tuve que crear otro proyecto móvil (el que usa lo definido en Proyecto2), pero para no repetir todo el código que ya tengo hecho, añadí una referencia a Proyecto1 en el Proyecto2.

Y lo curioso es que aunque las clases definidas en Proyecto1 se supone que utiliza los recursos que haya en el App.xaml del Proyecto1, al ejecutar la aplicación (que usa Proyecto2) me da error de que no encuentra los recursos, por tanto, tuve que copiar todas las definiciones del fichero App.xaml del Proyecto1 en el App.xaml del Proyecto2.

Hasta aquí todo bien, sin problemas. ¿No?

Pero ahora decido añadir un nuevo estilo o cambiar alguno de los que hay… ¿Qué tengo que hacer? Pues muy fácil: MODIFICAR ambos ficheros App.xaml con esos estilos modificados.

Y la verdad es que para un despistao como yo, eso es unproblema, ya que me puedo tirar un buen rato comprobando porqué no funciona con los nuevos estilos definidos… Hasta caer en la cuenta de que no están definidos en los dos ficheros.
Sí, así de torpe es elGuille 😉

¿Solución? Crear un fichero en el que estén todos los recursos y ese fichero usarlo en los dos proyectos. Y eso es lo que he hecho y como he visto que en la rede de redes no está explicado cómo hacer esto, seguramente porque es algo trivial o fácil, pero la cuestión es que para mí no era tan trivial ni fácil, y como no encontraba la solución… me puse a probar con lo que ya había encontrado y… ahora ya lo tengo claro y para que tú también lo tengas claro, si es que necesitas hacerlo, aquí te lo explico.

En realidad la solución es fácil, lo que me traía de cabeza es que usando esas definiciones con esto: Application.Current.Resources["estilo"], no me funciona (y eso aún no lo he solucionado), así que, tuve que usar lo que te he comentado antes de aplicar los estilos que están en una declaración ResourceDictionary (Acceder desde código a las definiciones de ResourceDictionary), es decir, usando esto: Control.SetDynamicResource(TipoControl.StyleProperty, "estilo"), ya que al fin y al cabo, esos recursos definidos en otro fichero en realidad están definidos como ResourceDictionary.

Vamos con los ejemplos de código, empezando por el código XAML a usar en App.xaml:

<Application.Resources>
    <ResourceDictionary Source="ResourceDictionaryElGuille.xaml"/>

Es decir, se hace de la misma forma que para añadirlo a una página normal.
En este caso no indico ningún path en Source porque ese fichero de recursos está en el mimo directorio que App.xaml.

Si ves el código fuente en GitHub (es el mismo proyecto que los ejemplos de los Trucos para Xamarin.Forms y .NET MAUI en dispositivos) comprobarás que en App.xaml he dejado ese código anterior (el de usar un ResourceDictionary definido en otro fichero) además de otras definiciones que también están en bloques ResourceDictionary.

 

A tener en cuenta

Lo que sí debes tener en cuenta es que si todo lo defines en bloques de ResourceDictionary no podrás acceder a esas definiciones por código usando Application.Current.Resources[«key»].

Es decir, el código usado en el primer ejemplo fallará si esos dos recursos (ColorAzul y ColorRojo) no están directamente definidos en los recursos de la aplicación.

Pero puedes tenerlos definidos en dos sitios diferentes sin conflictos.

Para que todos estos ejemplos funcionen he definido esos dos valores tanto en Application.Resources como en el ResourceDictionary del fichero ese externo.

Por tanto, el código XAML de App.xaml empezaría de esta forma: (sigue con otras definiciones de ResourceDictionary, una que estaba ya en ese fichero cuando se creé el proyecto y los que he definido para usar los colores Color2Azul y Color2Rojo del segundo ejemplo que te mostré antes).
También he definido los recursos ColorAzul y ColorRojo para que el primer ejemplo no de error. Y sí, esas mismas claves están definidas en ambos ficheros, y sin conflictos. 😉

<Application.Resources>
    <ResourceDictionary Source="ResourceDictionaryElGuille.xaml"/>

    <ResourceDictionary>
        <Color x:Key="Color2Azul">#0073cf</Color>
        <Color x:Key="Color2Rojo">Firebrick</Color>
    </ResourceDictionary>

Como ya te he explicado antes, la forma de usar esos valores definidos en un ResourceDictionary es usando el código del segundo ejemplo de este post.

 

Y esto es todo… espero que te haya sido de utilidad.

El código fuente de estos ejemplos (y los del 2 de junio) están en GitHub: ElGuille-Ejemplos.

 

Nos vemos.
Guillermo

He quitado los anuncios de AdSense de Google de elguillemola.com

Pues eso… que ya que no producían ingresos, no sé si porque todo el mundo usa algún sistema de bloqueo de anuncios o simplemente porque nadie pincha en los anuncios, pero la cuestión es que los he quitado, ya que yo no los tengo bloqueados y siempre que veo las publicaciones o busco algo en mi blog, a mí si que me muestra (o mostraba) los anuncios; y no los tengo bloquedados (los anuncios) y tampoco te recomiendo que los bloquees, ya que es una forma de ayudar a financiar los costes de un sitio o un blog; por eso, cuando yo entro en algún sitio o blog y veo que muestran anuncios me gusta hacer clic en alguno de los anuncios, solo un clic cada vez que entro, que sé por experiencia que si abusas de hacer clics en los anuncios, seguramente con la buena intención de ayudar, al final es perjudicial para el autor del sitio (o blog), y es que esos anuncios no se tienen por gusto, si no para ayudar a poder pagar los gastos (no todos) que mantener un sitio o un blog cuesta (lo sé por experiencia desde hace ya casi 25 años). Y ya que no hay anuncios y cualquier ayudita económica nunca está de más, te invito a que pulses en el botón de DONAR con PayPal, no es necesario que sea mucho, lo que estimes y puedas, cualquier cantidad, hasta 1€ es una buena ayuda (de ese euro solo me dan una parte, pero… peor es nada).

En breve, cuando haga algunos cambios que quiero hacer en mi sitio (elguille.info) no en este blog, si no en el sitio (que algunos llamáis blog, pero bueno), también quitaré los anuncios de Google AdSense, porque allí tampoco producen ingresos y a mí me resultan molestos los anuncios, así que… otra razón más para que hagas un donativo 😉
Imagina que te encuentras conmigo (virtualmente) ye te apetece invitarme a un café, un refresco, una cerveza o un cubata, pues… como si lo fuera… pero sin refrescar el gaznate… y costándote la mitad… ya que al no tomarnos nada de verdad, te ahorras lo que tú te tomarías… así que… si me haces un donativo con PayPal… ¡todo son ventajas! tú ganas y yo gano… 😉

No vayas a pensar que esto lo escribo para obligarte a hacerme un donativo, no, ni mucho menos, este blogo y mi sitio siempre han sido gratis (desde hace ya casi 25 años) y lo seguirán siendo, espero que incluso cuando yo ya no esté en este mundo… 😉

Y ya está… ¡que disfrutes de los NO-anuncios!

Por cierto…
No sé cómo pero me habían desaparecido los widgets con lo del donativo, lo que es un blog y algunas otras cosas que tenía puesto en el lateral de las páginas del blog (seguramente al cambiar de hostingo o porque he tocado donde no debía tocar), por suerte los de Internet Archive (Wayback Machine) tienen copias de lo que había en este blog y de ahí he podido recuperarlos.
Sí, a esa gente también he hecho algún que otro donativo… hoy precisamente también, ya que me ha sido de ayuda para recuperar eso que ya no tenía 😉

Nos vemos.
Guillermo

Instalando los proyectos de VS2019 v16.11 Preview 1 para .NET MAUI Preview 4

Pues eso… que he instalado el Visual Studio 2019 versión 16.11 Preview 1 para poder usar los proyectos de .NET MAUI Preview 4 y como no había tipos de proyectos para .NET MAUI, y lo que se indica en esa página para tenerlos no es completo, he tenido que buscar en la WEB cómo hacerlo y aquí te pongo unas capturas de ese proceso de configuración de .NET MAUI para poder tener los tipos de proyectos en Visual Studio 2019 v11 Preview 1.

Lo primero es decirte que al PowerShell deberían cambiarle las combinaciones de colores, porque lo que es un servidor, no me resulta fácil ver algunos de los avisos y comandos/opciones… así que… si tampoco puedes verlos en las capturas… imagina lo que pone… 😀

De todas formas te resumo los pasos:

Tienes que abrir una ventana de comandos o PowerShell y escribir:
dotnet tool install -g redth.net.maui.check
A continuación (esto es lo que no vi en la página del anuncio de .NET MAUI Preview 4, aunque ahora releyéndola si lo he visto) escribir:
maui-check
Aunque antes de esto deberías escibir estos dos comandos:
primero:
dotnet new nugetconfig
y después:
dotnet nuget add source -n maui-preview https://aka.ms/maui-preview/index.json
O al menos así lo hice yo, aunque creo que primero escribí el primero el de dotnet tool install
En cualquier caso, si ya lo has hecho, no habrá problemas, tal como verás en las siguientes capturas, ya que te dirá que ya está hecho 😉

Figura 1. No me muestran los proyectos de .NET MAUI.
Figura 2. Ahí dice que ya lo he instalado… pero yo no veo ese texto… tuve que copiarlo para verlo…
Figura 3. Crear la configuración de NuGet y añadirla… aunque ya lo hice según ahí me indica
Figura 4. La comprobación de si está instalado lo necesario para usar .NET MAUI (tuve que «fix» todo eso…).
Figura 5. Y paciencia mientras instala los SDKs, emuladores, etc.
Figura 6. Paciencia mientras sigue instalando…
Figura 7. Hasta que termine de comprobar e instalar.
Figura 8. Ahora si hay proyectos para .NET MAUI en Visual Studio 2019 v11 Preview 1

Por supuesto, estos pasos no habrá que hacerlos una vez que tanto el .NET MAUI como el Visual Studio 2019 (o 2022) que lo soporte estén más actualizados. O eso espero, si no… pues eso… ¡será un rollo!

Y si quieres saber qué se irá incluyendo en las próximas preview de .NET MAUI, aquí tienes el roadmap mostrado cuando sacaron la preview 4.

No he tenido oportunidad de probarlo, he creado un proyecto nuevo, pero la máquina virtual que tengo parece que falla mucho o es que el Visual Studio 2019 versión 16.11 Preview 1 hace que falle, no lo sé… no tengo la paciencia para averiguarlo, entre otras cosas porque esa máquina virtual (en Hyper-V) va lenta y me ralentiza mi equipo, al menos con las cosas que tengo abiertas y que por ahora son más urgentes que probar el .NET MAUI, pero lo probaré… y cuando lo haga, lo sabrás… si sigues lo que publico aquí en el blog o en mi feis, así que… te invito a que entres en la página de elGuille ne el feis: elGuille.info en Facebook.

Espero que te sea de utilidad… ya sabes que esa es siempre la intención. 😉

Nos vemos.
Guillermo