Etiqueta: Windows Store

  • Presuntamente algunas funciones de Microsoft.VisualBasic no son compatibles con las aplicaciones para Windows Store

     

    Pues eso… que en un proyecto DLL (biblioteca de clases) para Windows Store no me ha reconocido ciertas funciones de manipulación de cadenas que están definidas en el módulo Strings del espacio de nombres Microsoft.VisualBasic (que es como si dijéramos el "runtime" de Visual Basic para .NET).

    Lo de presuntamente es por si he hecho algo mal y por eso no me reconocía algunas funciones… al menos en un proyecto del tipo biblioteca de clases (class library), en la figura 1 tienes las cosas que se pueden usar de ese módulo con las funciones de cadena.

     

    Microsoft.VisualBasic.Strings en app store class library
    Figura 1. Las funciones que muestra Strings en un proyecto del tipo Class library para Windows store

     

    Nota:
    En una aplicación para Windows Store (no una librería de clases) también muestra los mismos métodos. En una aplicación/librería para el escritorio (incluso de Windows 8) muestra las que estamos habituados a usar.

     

    Así que… me las he tenido que fabricar, al menos las que me han hecho falta para este caso concreto, que no es otro que una actualización de mi librería (perdón, biblioteca) para colorear código: gsColorearCodigo.

    Aquí te dejo un módulo de Visual Basic para hacer las conversiones… lo mismo ya tenía algo publicado sobre algo parecido, pero…

     

    '------------------------------------------------------------------------------
    ' VBStrings                                                         (01/Ene/13)
    '
    ' Para simular las funciones de cadena de Visual Basic
    ' ya que parece que el runtime para Windows Store no incluye algunas funciones
    '
    ' ©Guillermo 'guille' Som, 2013
    '------------------------------------------------------------------------------
    Option Strict On
    Option Infer On
    
    
    Public Module VBStrings
        ''' <summary>
        ''' Devuelve la posición (en base 1) de cadena1 en cadena2
        ''' </summary>
        ''' <remarks></remarks>
        Public Function InStr(cadena1 As String, cadena2 As String) As Integer
            Try
                Dim i = cadena1.IndexOf(cadena2)
                Return i + 1
            Catch ex As Exception
                Return 0
            End Try
        End Function
    
    
        ''' <summary>
        ''' Devuelve la posición en base 1 de cadena1 en cadena2
        ''' se comprueba a partir de la posición desde
        ''' </summary>
        ''' <remarks></remarks>
        Public Function InStr(desde As Integer, cadena1 As String, cadena2 As String) As Integer
            Try
                Dim i = cadena1.IndexOf(cadena2, desde - 1)
                Return i + 1
            Catch ex As Exception
                Return 0
            End Try
        End Function
    
        ''' <summary>
        ''' Devuelve una cadena con los cuantos primeros caracteres de cadena1
        ''' El primer caracter es el 1 y se devuelve en base 1
        ''' </summary>
        ''' <remarks></remarks>
        Public Function Left(cadena1 As String, cuantos As Integer) As String
            If String.IsNullOrWhiteSpace(cadena1) OrElse cuantos < 1 Then
                Return ""
            End If
    
            Dim s = cadena1.Substring(0, cuantos - 1)
            Return s
        End Function
    
        ''' <summary>
        ''' Devuelve la cantidad de caracteres que tiene cadena1
        ''' </summary>
        ''' <remarks></remarks>
        Public Function Len(cadena1 As String) As Integer
            If String.IsNullOrWhiteSpace(cadena1) Then
                Return 0
            End If
    
            Return cadena1.Length
        End Function
    
        ''' <summary>
        ''' Devuelve una cadena nueva después de quitarle
        ''' los espacios del principio y del final
        ''' </summary>
        ''' <remarks></remarks>
        Public Function Trim(cadena1 As String) As String
            If String.IsNullOrWhiteSpace(cadena1) Then
                Return ""
            End If
    
            Return cadena1.Trim()
        End Function
    
        ''' <summary>
        ''' Devuelve una cadena a partir de la posición desde
        ''' La pirmera posición es la 1
        ''' </summary>
        ''' <remarks></remarks>
        Public Function Mid(cadena1 As String, desde As Integer) As String
            If String.IsNullOrWhiteSpace(cadena1) OrElse desde < 1 Then
                Return ""
            End If
    
            Return cadena1.Substring(desde - 1)
        End Function
    
        ''' <summary>
        ''' Devuelve una cadena con cuantos caracteres de cadena1 
        '''  a partir de desde
        ''' La primera posición es la 1
        ''' </summary>
        ''' <remarks></remarks>
        Public Function Mid(cadena1 As String, desde As Integer, 
                                                cuantos As Integer) As String
            If String.IsNullOrWhiteSpace(cadena1) OrElse desde < 1 Then
                Return ""
            End If
    
            Return cadena1.Substring(desde - 1, cuantos)
        End Function
    
        ''' <summary>
        ''' Trocea una cadena usando los caracteres indicados
        ''' </summary>
        ''' <remarks></remarks>
        Public Function Split(cadena1 As String, caracteres As String) As String()
            Return cadena1.Split(caracteres.ToCharArray, 
                                  StringSplitOptions.RemoveEmptyEntries)
        End Function
    End Module
    
    
    

     

    Espero que te sea de utilidad.

     

    Nos vemos.

    Guillermo

    …

  • Como usar GetFileFromApplicationUriAsync (para que no se te cuelgue la aplicación)

     

    Pues eso… que este post iba a ser una especie de declaración de «mi» incapacidad a la hora de trabajar de forma asíncrona con los ficheros de una aplicación de Windows Store, y al final será una especie de truco o consejo de cómo hacer las cosas con todo esto de el acceso a ficheros de forma asíncrona (la única que conozco para Windows Store).

    Y la solución no es porque «yo» haya dado con la respuesta, bueno, un poco sí, ya que si no hago un par de búsquedas en Google lo mismo no hubiese dado con la respuesta.

    Y digo «un par» de búsquedas por no decir tres, ya que es complicado algunas veces encontrar respuestas, sobre todo porque la mayoría de las preguntas con respuestas están en inglés y después porque no sabes con certeza cómo «plantear» la búsqueda…

    Y lo curioso es que al tercer intento con esto: «GetFileFromApplicationUriAsync don’t» es cuando ha salido la respuesta, y precisamente en el primer lugar:

     

    getfilefromapplicationuriasync don t  Buscar con Google

     

    Y eso que en la búsqueda anterior lo puse un poco más concreto, en fin… estos buscadores y/o los usuarios de los mismos… ¡habrá que apañarlos! 😉

     

    Te explico de qué va la cosa:

    Estoy haciendo una aplicación para Windows 8 (Windows Store) en la que quiero mostrar el contenido de unos ficheros de textos. Para ello estoy usando una versión adaptada del tipo de proyecto Split App en el que todo el contenido está basado en «bindings», pero ese no es el problema, el problema es que en la clase SampleDataSource estoy haciendo una serie de cambios para que se adapte a lo que yo quiero, y como el texto a mostrar es bastante grande como para «pegarlo» en la propia clase (tal como hacen en el proyecto de ejemplo) me puse a crear un código que leyera el contenido del fichero y lo asignara adecuadamente a una propiedad de la clase usada como «binding» que es la que muestra el texto final.

    Así que… se me ocurrió usar este código (y algún otro con distintas pruebas):

     

    Dim ficUri = New Uri("ms-appx:///contenido/" & fic)
    
    ' aquí se queda colgado (algunas veces)
    ' las veces que pasa de aquí es en modo debug y haciendo un break
    ' (pero no siempre)
    Dim file = Await StorageFile.GetFileFromApplicationUriAsync(ficUri)
    
    ' Aquí también se para, y pasa si hay un breakpoint
    Dim sf = Await file.OpenStreamForReadAsync
    
    Using sr As New StreamReader(sf, Encoding.UTF8, True)
        sBody = sr.ReadToEnd()
    End Using
    
    Return sBody
    
    
    

     

    Y tal como comento en los comentarios (valga la redundancia) cuando estaba en funcionamiento «natural» no pasaba de ahí y se quedaba colgada la aplicación.

    Ya estaba por desistir cuando me ha dado el punto de buscar en Google ya que suponía que no sería cosa mía y que seguramente a alguien más le habrá ocurrido… ¡y así es!

    Nota: antes de buscar en Google ya busqué información en la documentación de Visual Studio, pero no encontré nada, aparte de los ejemplos triviales que suelen poner que que dan por hecho de que prácticamente te lo sabes todo, todo, todo… en fin…

    No me voy a enrollar más de la cuenta y te pongo el código correcto para hacer esa tarea de leer un fichero de forma asíncrona y que no se quede colgada la aplicación de Windows Store.

     

    También te pondré el enlace a esa pregunta y un artículo del autor de la respuesta donde explica porqué pasa eso, no, mejor dicho: «porqué nos pasa eso a los principiantes» del acceso asíncrono, o eso he entendido yo de este párrafo:

    «I think it’s the most-asked question by async newcomers once they’ve learned the basics.»

    Y tiene razón ya que reconozco que soy un newcomer en esto de el acceso asíncrono, al menos para los ficheros en el directorio de la aplicación, ya que antes he estado accediendo de forma asíncrona a otros ficheros (del Local storage) y ha funcionado… en fin…

     

    Dim ficUri = New Uri("ms-appx:///contenido/" & fic)
    
    Dim file = Await StorageFile.GetFileFromApplicationUriAsync(ficUri).AsTask().ConfigureAwait(False)
    
    Dim sf = Await file.OpenStreamForReadAsync().ConfigureAwait(False)
    
    Using sr As New StreamReader(sf, Encoding.UTF8, True)
        sBody = sr.ReadToEnd()
    End Using
    
    
    Return sBody
    

     

    Como puedes ver, la solución es agregar .AsTask().ConfigureAwait(False) al final del método GetFileFromApplicationUriAsync que es el que se encarga de obtener el fichero desde el directorio de la aplicación, y de ConfigureAwait(False) al método OpenStreamForReadAsync que es el que se encarga de convertir dicho fichero en un Stream de lectura.

     

    La explicación del porqué del uso de esos métodos está en el comentario que hizo Nito al preguntarle el «buscador de respuestas» porqué era necesario hacer eso:

    (te lo pego en inglés que la traducción automática como que no me convence)

    Explanation is quite simple: when you use task.Result ortask.Wait() on GUI thread in conjunction with await keyword you’re causing deadlock. This happens because after awaiting code is resumed on the same context it was invoked (in your case – GUI thread). And because GUI thread currently waiting for task to complete (via Result or Wait()) deadlock arises and code after await keyword will never be invoked. ConfigureAwait(false)specifies that current context can be ignored and thus allows your code to complete successfully. More details on this here: http://nitoprograms.blogspot.com/2012/07/dont-block-on-async-code.html

     

    Este es el enlace a la pregunta/respuesta esa que te comentaba y este otro es al artículo de Nito Programming.

     

    Espero que te sea de utilidad.

     

    Nos vemos.

    Guillermo

    …

  • En ocasiones Visual Studio no avisa de los errores en XAML

     

    Pues eso… aunque al leer el título: "en ocasiones…" parece lo del niño ese de la peli Sexto Sentido (no del disco de Melendi), pero la realidad es que es así… y lo de "en ocasiones" lo he puesto como quien dice "presunto" asesino, por aquello de no pillarse los dedos…

    Te cuento… como últimamente estoy aburrío (jeje), pues me puse a trastear en los estilos de una de las páginas incluidas en los proyectos de tipo Windows Store, ya que en la ayuda vi que puedes modificar un estilo existente y agregarlo a varios sitios: la propia página en la que está el estilo original, en App.xaml y en otra página (del tipo resource dictionary) que tengas en tu proyecto.

    Todo esto es porque no daba con la tecla de cómo usar mi propio fichero de estilos que define estilos que usan otros estilos que están definidos en otra página… ¡QUIETOOOORRRR!
    ¡No te vayas!, que no es que te esté intentando liar… es que es así… sí, además, si estás leyendo esto lo mismo ya has leído lo que he publicado hace unos minutos y que precisamente soluciona el problema ese que te comento en este mismo párrafo:

    Crear un fichero de estilos XAML y acceder a estilos definidos en otro fichero

     

    Sigamos, pero veamos "gráficamente" lo que te comento, por ejemplo, abrimos (en modo diseño) la página SplitPage.xaml de un proyecto del tipo SplitApp (vale cualquier otra que tenga el botón para ir atrás), si seleccionas el botón de ir atrás y vas a las propiedades para acceder a la propiedad Styles (que está en el grupo Miscellaneous) verás que el estilo actual está indicado con un puntito verde a la derecha (ver figura 1), si pulsas en ese "punto" te mostrará un menú con varias opciones (ver figura 2)

    propiedades 1 – propiedades 2
    Figuras 1 y 2. Propiedades del estilo y convertir a nuevo recurso

     

    Si seleccionas Convert to New Resource te permitirá hacer una copia de ese recurso en el fichero que indiques, en mi caso (tal como vemos en la figura 3) lo quiero incluir en mi fichero de estilos.

     

    propiedades 3
    Figura 3. El cuadro de diálogo para indicar dónde estará el nuevo recurso

     

    Nota:
    Los ficheros mostrados en esa lista desplegable del cuadro de diálogo de crear un nuevo recurso de estilos, deben estar previamente agregados a MergedDictionary de App.xaml.
    Para saber cómo hacer esto que te comento, mira el enlace que te puse más arriba.

     

    Pues bien, eso hice yo. Agregué el nuevo recurso a mi fichero, e hice todo lo que te comenté en el post anterior. Ahora voy a probar los cambios (que no había sido nada, sólo lo de crear el recurso en otro fichero) y no funciona la aplicación.
    Bueno, funcionar si que funciona, de hecho me mostraba la página principal (ItemsPage) pero al pulsar en una de las opciones mostradas no me mostraba la otra página con los detalles… ¿adivinas cómo se llama la otra página! ¡BINGO! SplitPage.
    Pero claro, yo como iba a pensar que "yo" era el culpable (¿he sido yo? que diría Steve Urkel), así que… me puse a "debuguear" y nada, se quedaba en la llamada a esa página, pero no mostraba nada, ni daba error, ni ná de ná.
    Así que… aburrido (esta vez de probar y probar y no saber qué pasaba) quité ese proyecto y volví a crear otro del mismo tipo, pero sin cambiar nada del recurso… La pruebo y, claro, como es de esperar: ¡funciona!
    Eso sí, se paró en el mismo punto de interrupción que puse en la aplicación anterior ¿por qué? ni idea, lo que si te digo es que las dos aplicaciones se llamaban igual (sólo renombre el directorio para que no me diese error).

    Volví a probar sin el breakpoint y seguía funcionando. Así que… descargue ese proyecto y volví a cargar el anterior (el que estuve trasteando). Y me fije en cómo se llamaba el recurso que utilizaba el botón ese de la página SplitPage, y como era de esperar al hacer la copia del recurso se había cambiado el nombre y como resulta que yo había eliminado (en realidad quitado del proyecto) el fichero en el que se creó dicho recurso de estilos, pues… ¡no existía!

    Resumen, que ya es noche y me estoy alargando más de lo necesario:
    Si usas un estilo que no existe en un control XAML, "es posible" que Visual Studio no te alerte de ese "pequeño detalle".

    Y lo de es posible lo digo porque a mi otras veces si me ha avisado de que no existe, pero no avisando con un mensaje de alerta, si no , detallándolo en la ventana de errores, ya que si compilas y ejecutas si que funciona… es decir, no se para porque haya un error en el código XAML.

    Aunque también está la contrapartida, la de que te muestre cuadro de diálogo con un error (o que se pare la aplicación en el código oculto de la clase App) pero no veas el error en ningún sitio (ni en la ventana de errores), eso sí, con suerte puedes ver que el mensaje de error es:
    DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
    como ya te comenté en su día: Error al usar inadecuadamente el XAML.

     

    Pues nada, creo que ya está bien por hoy… y si esto te sirve para no tener los quebraderos de cabeza que he tenido por "no saber", pues… mejor, eso es de lo que se trata algunas veces: que los demás solucionen antes los errores que yo ya tuve… 😉

     

    Nos vemos.
    Guillermo

    …