Categoría: cosas técnicas

Posts relacionados con la programación o manejo o configuración de los oredenadores (computadores)

  • Dónde poner las opciones de configuración de una aplicación para Windows 8

    Pues eso… que con el nuevo "look & feel" de las aplicaciones de Windows 8 (las de la tienda de Windows o Windows Store, no las de desktop/escritorio) lo "normal" es que si queremos poner algunas opciones de configuración en nuestra aplicación, pues… que lo hagamos donde se supone que están las configuraciones de las aplicaciones para Windows 8… ¿y dónde es eso? en "el coso ese" que se muestra cuando pasas el cursor del ratón por la parte derecha (y superior) de la pantalla, tal como puedes comprobar en la figura 1.

     

    settings_01
    Figura 1. Las configuraciones de las aplicaciones de Windows 8 deberían mostrarse al pulsar en el botón Settings

    Nota (21:07):
    El "coso ese" al que me referí en el párrafo anterior es lo que en inglés se llama "Settings Charm pane" y, según la traducción de la ayuda de MSDN, en español (o castellano) se llama "panel de acceso a Configuración".

    Buscando la traducción de "charm" resulta que es "encanto" (incluso "colgante" según Bing) y poniendo a prueba los traductores con este artículo en inglés que habla de los Charms, ambos traductores (Google y Bing) lo hacen de esta forma: "los encantos" (charms) o "la barra de encantos" (charms bar).
    Es que es un encanto este Windows 8.

    Que sí, que ya sé que lo sabes… pero yo no lo sabía… vamos que no me había percatado de que el "settings" ese que se muestra (en la versión en inglés) podría ser para todas las aplicaciones, ya que yo (iluso o desconocedor) pensaba que sólo era para las configuraciones del propio Windows.

    Y hasta ayer no fui consciente de que era para todas las aplicaciones (las que quieran, por supuesto), más que nada porque estaba buscando información de cómo mostrar cuadros de diálogo y esas cosas que se usan para que el usuario pueda "configurar" nuestra aplicación, pero para Windows 8.

    Y entre las cosas que encontré (mira que es complicao encontrar cosas con los buscadores, sobre todo si no sabes qué poner para encontrar lo que buscas, más que nada si no sabes cómo "se llama" eso que buscas… y no te rías, porque a mi eso de los "tiles" ni de coña me suena a que sea el icono que se muestra en la pantalla de inicio de Windows).

    Estos son los enlaces que estuve mirando (seguramente había más, pero no contenían lo que yo iba buscando):

    Directrices para la configuración de una aplicación (aplicaciones de la Tienda de Windows)
    App settings sample (Centro de desarrollo de Windows)

    Inicio rápido: Agregar la configuración de una aplicación (aplicaciones de la Tienda Windows con C#/VB/C++ y XAML)

    Ese último enlace no lo había visto ayer… lo acabo de "encontrar" hoy…

    Aprovechando que es un ejemplo para C# y VB con XAML quiero decir que no sé porqué narices casi todos los ejemplos que hay (incluyendo en la propia documentación de Visual Studio 2012) son para JavaScript… Que no pasa nada, pero ya podrían poner más para VB/C# (vale, y también para C++).

    Sigo con mis cosas. Pues resulta que primero me pasó con el juego del solitario (el spider) ya que en la versión que tengo para mi smartphone Samsung Galaxy S (el normalillo) puedo indicar el número de palos con los que quiero jugar y el de Windows sólo mostraba un palo… y yo pulsando con el botón derecho del ratón en la pantalla a ver si salían algunas opciones "de configuración" y lo único que conseguía era que me mostrara el menú ese de opciones de la parte inferior (que es lo que supuestamente ahora se muestra si nuestra aplicación ha incluido un AppBar, pulsa en este enlace si quieres saber cómo añadir un AppBar en tu aplicación de Windows 8).
    Lo mismo me pasó con el calendario, que me mostraba los cumpleaños y como lo tengo sincronizado con el Facebook (creo) pues… me muestra un mogollón de cumpleañeros y… pues que quería quitarlos… en el calendario que se muestra en el navegador (el de Hotmail o el de GMail) se puede indicar de forma más o menos sencilla si se quieren o no mostrar los cumpleaños, pero en el de Windows 8 no veía yo como… claro, no se me ocurrió mirar en las opciones de configuración (que yo pensaba que sólo eran) del sistema.

     

    Pues eso… que aquí te muestro un par de pantallazos más con las capturas de las opciones de configuración de la aplicación (en este caso es del solitario spider).

    En la primera (la figura 2) se muestran las opciones de configuración del propio Windows además de las propias de la aplicación.

    settings_02
    Figura 2. La configuración de la aplicación se muestra junto con las de Windows (o casi),
    o dicho de otro modo: se integran con las de Windows.

    Y una vez que elegimos una de esas opciones se mostrará tal y como el autor así lo haya programado, pero siempre en el mismo área de la pantalla tal como podemos comprobar en la figura 3.

    settings_03
    Figura 3. Una vez seleccionada la opción a configurar se muestran las opciones que el autor ha programado.

     

    Y esto es todo… al menos en cuanto a "información" (no creo que haya más gente tan torpe como yo, pero… con la de criaturas que hay en este mundo, cualquiera sabe, jeje… ¡ay zeñó!

    En cuanto haga un panel de estos de configuración ya te contaré cómo hacerlo… de forma fácil, porque algunos de los ejemplos del SDK tienen tarea para entenderlos… al menos cuando quieres hacer algo muy concreto y que nunca antes habías hecho, porque cuando sabes hacerlo (o qué buscar) es fácil entender las cosas que lees… ¿no? pues eso pienso yo… en fin…

     

    Nos vemos.
    Guillermo

  • Actualizar cada minuto el icono (tile) de una aplicación de Windows Store hasta la hora indicada

    Pues eso, un titulo más largo que el del artículo que publiqué hace unos días:
    Actualizar el icono (tile) de una aplicación de Windows Store,
    en el que te contaré cómo indicarle a Windows que actualice lo que se muestra en el icono de la aplicación (tile), pero incluso cuando dicha aplicación ya está cerrada, además esa actualización se hará cada "x" tiempo y hasta cuando tu digas (la cantidad de minutos u horas que quieras que duren esas actualizaciones).

    El código te lo mostraré primero para Visual Basic y cuando lo tenga listo en C# lo agregaré a esta misma "página" (con fecha del domingo 23 de diciembre de 2012 ya está el código de C#, pero lo he puesto al final del todo y sin usar el fondo negro).

    Dicho esto, crea una nueva aplicación para Windows Store (la más básica es suficiente).

    En el código del evento OnNavigatedTo de MainPage añade esta llamada al método que hará todo el trabajo: asignarTiles.

     

    Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
        asignarTiles()
    End Sub
    
    

     

    Y ahora viene cómo hacer esto de modificar (si quieres, llámalo notificar) el contenido del icono de la aplicación (conocido como tile por los que ponen nombres a estas cosas nuevas que van saliendo). Pero para hacer esa modificación no tendremos que usar ningún temporizador (timer) simplemente usaremos una serie de asignaciones a un objeto del tipo TileUpdater creado a través del método CreateTileUpdaterForApplication de la clase TileUpdateManager a través del método AddToSchedule de forma que le digamos lo que se mostrará en el icono (ya sea el grande -ahora hablamos de ese icono- o el pequeño) y, lo más importante, cuándo se mostrará.

    Nota:

    Este código está adaptado del ejemplo Clock Tile de Dave Smits.

    Te dejo el código y espero que lo comprendas… si tienes dudas pregunta en los comentarios de este mismo post… eso si antes no te lo he explicado con más detalle.

    Recuerda que el cuadro del código puede tener scroll y no lo veas al completo…

     

    Lo que sí (o también, si ya te he explicado lo que te iba a explicar) te voy a decir que al crear un nuevo proyecto para Windows Store (al menos del más elemental) el icono ancho no estará y por tanto el icono (o tile) de la aplicación se mostrará en el formato cuadrado (pequeño). Esa imagen es la que se llama Logo.png en la carpeta Assets y su tamaño es de 150×150. Para tener el logo de tamaño ancho, necesitarás una imagen de 310×150 a la que tendrás que darle el nombre WideLogo.png. Si no haces esto, este ejemplo no compilará.

     

    ''' <summary>
    ''' Crear la lista de notificaciones al icono (tile)
    ''' Se crearán los necesarios para las próximas 4 horas
    ''' notificando cada minuto
    ''' </summary>
    ''' <remarks>
    ''' Basado en el código de Clock Tile de Dave Smits
    ''' </remarks>
    Private Sub asignarTiles()
        Dim tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication()
    
        Dim now As DateTime = DateTime.Now
        ' aquí está el truco... crear tiles para un buen rato...
        Dim planTill As DateTime = now.AddMinutes(30) ' .AddHours(4) ' .AddMinutes(15)
    
        Dim updateTime = New DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0).AddMinutes(1)
    
        Dim plannedUpdated = tileUpdater.GetScheduledTileNotifications()
        If plannedUpdated.Count > 0 Then
            ' Asignar a updatetime la última fecha de la colección (o la que sea mayor)
            updateTime = plannedUpdated.Select(Function(x) x.DeliveryTime.DateTime).Union({updateTime}).Max()
        End If
        Const sXml = "<tile><visual>" &
                            "<binding template=""TileSquareText02""><text id=""1"">{0}</text><text id=""2"">{2}</text></binding>" &
                            "<binding template=""TileWideText01""><text id=""1"">{0}</text><text id=""2"">{1}</text>" &
                                "<text id=""3""></text><text id=""4""></text><text id=""5""></text></binding>" &
                    "</visual></tile>"
    
        Dim tileXmlNow = String.Format(sXml, now.ToString("HH:mm"),
                                             now.ToString("dddd, dd MMMM yyyy"),
                                             now.ToString("dd/MMM/yyyy"))
        Dim documentNow As New XmlDocument()
        documentNow.LoadXml(tileXmlNow)
    
        tileUpdater.Update(New TileNotification(documentNow) With {.ExpirationTime = now.AddMinutes(1)})
    
        Dim startPlanning = updateTime
        While startPlanning < planTill
    
            Try
                Dim tileXml = String.Format(sXml, startPlanning.ToString("HH:mm"),
                                                  startPlanning.ToString("dddd, dd MMMM yyyy"),
                                                  startPlanning.ToString("dd/MMM/yyyy"))
                Dim document As New XmlDocument()
                document.LoadXml(tileXml)
    
                Dim deliveryTime = New DateTimeOffset(startPlanning)
                Dim scheduledNotification = New ScheduledTileNotification(document, deliveryTime)
                scheduledNotification.ExpirationTime = startPlanning.AddMinutes(1)
    
                tileUpdater.AddToSchedule(scheduledNotification)
    
            Catch e As Exception
                Debug.WriteLine("exception: " & e.Message)
    
            End Try
    
            startPlanning = startPlanning.AddMinutes(1)
        End While
    
    End Sub
    

     

    Bueno, y esto es todo… si cierras la aplicación (sólo te mostrará una pantalla negra) verás que el icono se sigue actualizando y cuando pase el tiempo indicado (en este ejemplo es de 30 minutos) se asignará el texto original.

    El tiempo total en el que se estarán mostrando las notificaciones es el indicado en la definición de la variable PlanTill:

    Dim planTill As DateTime = now.AddMinutes(30)

     

    Por cierto, creo que el número máximo de "actualizaciones / notificaciones" al tile de la aplicación es de 4096, así que… lo mismo habría que tener en cuenta que no se sobrepase esa cantidad… (tendré que probar si da error o no al pasar de esa cantidad).

     

    Espero que te sea de utilidad.

    Nos vemos.

    Guillermo

    P.S.

    El "estilo" del código es el que Visual Studio 2012 utiliza cuando está en modo "Dark"… a mi no me acaba de convencer…

     

    Nota del 23/Dic/12: el código de C#

    /// <summary>
    /// Crear la lista de notificaciones al icono (tile)
    /// Se crearán los necesarios para las próximas 4 horas
    /// notificando cada minuto
    /// </summary>
    /// <remarks>
    /// Basado en el código de Clock Tile de Dave Smits
    /// </remarks>
    private void asignarTiles()
    {
        var tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
    
        DateTime now = DateTime.Now;
        // aquí está el truco... crear tiles para un buen rato...
        DateTime planTill = now.AddMinutes(30); // .AddHours(4)
    
        var updateTime = new DateTime(now.Year, now.Month, now.Day, 
                                      now.Hour, now.Minute, 0).AddMinutes(1);
    
        var plannedUpdated = tileUpdater.GetScheduledTileNotifications();
        if (plannedUpdated.Count > 0)
        {
            // Asignar a updatetime la última fecha de la colección (o la que sea mayor)
            updateTime = plannedUpdated.Select(
                x => x.DeliveryTime.DateTime).Union(new[] { updateTime }).Max();
        }
    
        const string sXml = 
            @"<tile><visual>
                <binding template=""TileSquareText02"">
                    <text id=""1"">{0}</text><text id=""2"">{2}</text>
                </binding>
                <binding template=""TileWideText01"">
                    <text id=""1"">{0}</text><text id=""2"">{1}</text>
                    <text id=""3""></text><text id=""4""></text><text id=""5""></text>
                </binding>
            </visual></tile>";
    
        var tileXmlNow = String.Format(sXml, now.ToString("HH:mm"),
                                             now.ToString("dddd, dd MMMM yyyy"),
                                             now.ToString("dd/MMM/yyyy"));
        XmlDocument documentNow = new XmlDocument();
        documentNow.LoadXml(tileXmlNow);
    
        tileUpdater.Update(new TileNotification(documentNow) { ExpirationTime = now.AddMinutes(1) });
    
        // Este bucle while se puede cambiar por este for:
        // for (var startPlanning = updateTime; startPlanning < planTill; startPlanning = startPlanning.AddMinutes(1))
        var startPlanning = updateTime;
        while (startPlanning < planTill)
        {
            try
            {
                var tileXml = String.Format(sXml, startPlanning.ToString("HH:mm"),
                                                  startPlanning.ToString("dddd, dd MMMM yyyy"),
                                                  startPlanning.ToString("dd/MMM/yyyy"));
                XmlDocument document = new XmlDocument();
                document.LoadXml(tileXml);
    
                var deliveryTime = new DateTimeOffset(startPlanning);
                var scheduledNotification = new ScheduledTileNotification(document, deliveryTime);
                scheduledNotification.ExpirationTime = startPlanning.AddMinutes(1);
    
                tileUpdater.AddToSchedule(scheduledNotification);
            }
            catch (Exception e)
            {
                Debug.WriteLine("exception: " + e.Message);
            }
            startPlanning = startPlanning.AddMinutes(1);
        }
    }
    

     

  • Error al usar inadecuadamente el XAML

    Pues eso… que no es un error que sepas por dónde "meterle mano", o al menos eso me pasó a mí cuando me ocurrió. Me estoy refiriendo a un "Break" que se toma el Debugger de Visual Studio 2012 concretamente cuando llega a la línea que contiene la siguiente cadena: DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION.

    El error ocurre porque hay código XAML que no es correcto.
    Y cuando digo que "no es correcto" no me refiero a que haya un fallo de que falte un cierre de elemento o algo así, me refiero a que, por ejemplo, estás usando código Xaml en el sitio inadecuado.

    Te explico uno de los casos en los que me ocurrió a mí.

    En la aplicación del Reloj para Windows 8 que estoy haciendo, y la que te he ido mostrando paso a paso, he creado unas cadenas para usar en el código XAML, concretamente para el ToolTip, etcétera.
    Esas cadenas las utilizo (o esa era la intención inicial) para no tener que andar repitiendo el mismo texto en varios sitios y así poder modificarlas una sola vez y se usará esa modificación en las distintas partes de la aplicación en las que la utilizo.
    Pues bien, las cadenas las tengo definidas con este código:

    <x:String x:Key="AboutClock">Un reloj…</x:String>

    Y para usarla lo hago de esta forma (en el código XAML, en este ejemplo de la página principal):

    ToolTipService.ToolTip="{StaticResource AboutClock}"

    El problema que tuve es que al usar esto último en la definición del estilo de un botón en el que quiero que se muestre un ToolTip me daba ese error.

    La definición de la cadena está en App.xaml y el estilo en StandardStyles.xaml y lo usaba de esta forma:

    <Setter Property="ToolTipService.ToolTip" Value="{StaticResource AboutClock}" />

     

    Pues bien, eso no funciona (a mí no me funciona) y lo tengo que definir directamente en el estilo (de esa forma al aplicar el estilo al botón también se asigna el ToolTip).

     

    Bueno, pues esto es todo… espero que te sea de utilidad.

     

    Nos vemos.
    Guillermo