Categoría: cosas técnicas

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

  • Utilizar el mismo control en dos sitios (Windows Store)

     

    Pues eso… que quería usar el mismo control en dos sitios diferentes (según se muestre o no el AppBar) y como no quería crear otro control para que haga lo mismo que el que ya tenía, pues… a hacer lo que "supuestamente" había que hacer… es decir, cambiarlo de contenedor.

    Lo que pasa con las aplicaciones de la Tienda de Windows (Windows Store) o lo mismo es cosa de XAML, ¡vaya usted a saber!, es que el mismo control (incluso un clon referenciado, vamos que no es una copia) no puede estar en dos sitios a la vez.

    Esto es lógico, pero creo que con los controles de VB6 o de Windows Forms cuando lo "emparentabas" en otro control ya perdía toda la familiaridad con el que antes hacía de padre… pero hace unas semanas que comprobé que en XAML/Windows Store no es así.

    ¿No te estás enterando verdad? No te preocupes, es que cuando no duermo, pues… pasa lo que pasa… la cuestión es que te voy a explicar cómo usar el mismo control para que "parezca" que es una copia ya que unas veces se mostrará en la pantalla de la aplicación y si cuando se muestre el AppBar ese mismo control estará en la barra de la aplicación.

    El código te lo voy a mostrar en Visual Basic y también en C# (para que no te quejes).

    Pero primero voy a mostrarte el código XAML.

     

    <Page.BottomAppBar>
        <AppBar x:Name="mainBottomAppBar" Style="{StaticResource ClockAppBarBackground}" Padding="10,0,10,0"
                Closed="mainBottomAppBar_Closed" Opened="mainBottomAppBar_Opened">
            <Grid>
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                    <Button x:Name="buttonAlarmas"  
                            Style="{StaticResource AlarmasAppBarButtonStyle}" Click="buttonAlarmas_Click" />
                </StackPanel>            
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                    <Button x:Name="buttonClock"
                            Style="{StaticResource AboutClockAppBarButtonStyle}" Click="button_Clock" />
                    <StackPanel x:Name="spAppBarSettings" Margin="0,0,-10,0">
                        <Button x:Name="buttonSettings"  
                                Style="{StaticResource SettingsAppBarButtonStyle}" Click="button_Settings" />
                    </StackPanel>
                </StackPanel>
            </Grid>
        </AppBar>
    </Page.BottomAppBar>
    
    

     

    Nota:

    Los estilos usados en el código XAML son modificaciones de los que hay en el fichero StandardStyles.xaml, salvo el estilo de la barra de la aplicación que lo que contiene es la definición del color de fondo y del borde.

    De todas formas, pondré el código de muestra de la página XAML en pastebin.com y así no tendrás problema con los estilos y esas cosas.

     

    utilizar mismo control

     

    Este código es la definición de la AppBar en la que hay tres botones, uno de ellos muestra el panel de configuración (settings charm) y los otros dos hacen lo mismo que si eligiéramos esas dos opciones en el propio panel de configuración, aquí no te muestro el código, pero te lo explico para que sepas porqué el control AppBar tiene esos dos eventos.

    En esos dos eventos es donde hago el cambio de contenedor del control buttonSettings (el de configuración) ya que es el que me interesa que esté "aparentemente" en dos sitios a la vez.

    Este es el código de Visual Basic y el de C# está convertido, así que… aunque supongo que funcionará, comprueba que lo hace… (es que tendría que crear un proyecto para probarlo yo, y… pues eso… )

    VB:

     

    ' Añadir el botón de configuración al panel inferior    (04/Feb/13)
    ' para que siempre esté visible
    ' Pero sólo cuando se cierre la AppBar
    Private Sub mainBottomAppBar_Opened(sender As Object, e As Object)
        spRow2.Children.Remove(buttonSettings)
        spAppBarSettings.Children.Add(buttonSettings)
    End Sub
    
    Private Sub mainBottomAppBar_Closed(sender As Object, e As Object)
        spAppBarSettings.Children.Remove(buttonSettings)
        spRow2.Children.Add(buttonSettings)
    

     

    C#:

     

    // Añadir el botón de configuración al panel inferior    (04/Feb/13)
    // para que siempre esté visible
    // Pero sólo cuando se cierre la AppBar
    private void mainBottomAppBar_Opened(object sender, object e)
    {
        spRow2.Children.Remove(buttonSettings);
        spAppBarSettings.Children.Add(buttonSettings);
    }
    
    private void mainBottomAppBar_Closed(object sender, object e)
    {
        spAppBarSettings.Children.Remove(buttonSettings);
        spRow2.Children.Add(buttonSettings);
    }
    
    

     

    Es importante que el control que queremos mover esté primero en el contenedor spRow2, ya que al abrir la AppBar se intentará quitar de la colección de este panel y si o está… ¡ganaremos un hermoso error!

    Esto lo podemos hacer por código (por ejemplo asignándolo en algunos de los eventos iniciales de la página o mejor aún, a la hora del diseño. Es decir, en vez de ponerlo donde yo lo he puesto (en la AppBar, más que nada para que vieras el código completo de la barra) debería estar en el control spRow2.

     

    Otro problema con el que me he encontrado es que resulta que cuando el usuario pulsa en buttonSettings la barra de la aplicación se oculta, pero cuando se pulsa en cualquiera de los otros dos… pues… no se oculta, así que… lo que he hecho es cerrar por medio de código la barra, pero no he usado la propiedad "Visibility" para ocultarla, ya que eso haría que no se volviera a ver. Lo que he hecho es asignarle un valor falso a la propiedad IsOpen, de forma que se cierra pero sin más problemas. Esa asignación la hago en los dos botones que me daban problema, es decir, cuando el usuario pulsa en uno de esos botones, le asigno el valor falso a esa propiedad (IsOpen) y después muestro el panel de configuración y todo lo que haya que hacer.

    En este caso, el código es muy simple (adivina cuál es el de VB y cuál el de C#):

     

    mainBottomAppBar.IsOpen = False
    
    mainBottomAppBar.IsOpen = false
     ;

     

    Bueno, después de este inciso, sigamos con lo de "mover" el control de sitio.

    Como ya te comenté hace un rato, el control para mostrar el panel de configuración (settings charm) también debe estar en el panel al que he llamado spRow2 y que estará situado al pie de la página (concretamente el control ese parecerá que está en el mismo sitio).

    Y como ese StackPanel sólo tendrá el botón en cuestión hay un problema añadido, y es que cuando lo quitamos de ahí para ponerlo en el AppBar, el resto de la pantalla se baja… así que… ¡hay que arreglarlo! y eso lo he arreglado indicando la altura mínima del panel que lo contiene, de forma que ese tamaño sea el mismo que el que tiene el botón.

    Mir el código y cuando lo pruebes, quita la asignación de MinHeight y verás lo que ocurre.

     

    <!-- el MinHeight es para que al quitar el botón (por código)
         no se mueva lo que haya en medio 
         que se iba para abajo al abrir la appBar -->
    <StackPanel x:Name="spRow2" Grid.Column="2" Orientation="Horizontal" MinHeight="90">
        <!-- poner aquí el botón de configuración, pero por código -->
    </StackPanel>
    
    
    

     

    Y creo que con esto ya está bien…

    Te resumo las cosillas que creo que tiene de interesante este rollo que te he soltado, perdona si no me he sabido explicar bien o lo ves algo poco claro y enredado, pero es que llevo más de 24 horas sin pegar ojo y… eso se nota…  No es una excusa, pero… si no entiendes todo lo que te he dicho, para que sepas que no es culpa tuya, al menos el 100% jejeje (¡qué malo soy!).

     

    En este ejemplo hemos visto:

    – Cómo añadir una AppBar en la parte inferior de nuestra página (se mostrará al pulsar con el botón secundario del ratón).

    – Hacer que se cierre la AppBar en caso de que se quedara abierta al pulsar en uno de los botones.

    – Cuando veas el código XAML completo del ejemplo, sabrás cómo agregar estilos para usarlos sólo en la página en la que se definen.

    – Utilizar los eventos de apertura y cierre de la AppBar para cambiar un botón de un contenedor a otro, concretamente de la colección Children de un control StackPanel.

    – Cómo mantener las cosas en su sitio cuando el tamaño de un panel o contenedor cambia de tamaño (normalmente de la altura).

    – Y si te fijas en el código verás que está el botón de ir hacia atrás, pero como esta página no lo utiliza (y tampoco la página en la que utilizo el código este que estoy mostrándote), lo he ocultado, pero con idea de que el título no se desplace a la izquierda, he puesto que la columna en la que está el botón de ir hacia atrás en lugar de tener un ancho automático (<RowDefinition Height="Auto"/> ) lo he puesto para que tenga un tamaño fijo, que es el que he calculado teniendo en cuenta el ancho del botón más los márgenes, en mi caso (y generalmente si usas ese diseño) es de 110 (<RowDefinition Height="110"/> ).

    – Y seguramente más cosas, pero lo principal es lo que te he relacionado.

     

    Recuerda que en mi cuenta de Pastebin tienes el código completo (o casi) del ejemplo (que al final he hecho), tanto para Visual Basic como para C#.

     

     

    Espero que te haya sido de utilidad.

    Nos vemos.

    Guillermo

  • y yo pensaba que convertir fechas y horas ya no sería más un calentamiento de cabeza

     

    Pues eso… que sigue siendo… al menos si utilizas "tu formato preferido", aunque sea con otro "locale"… en fin… que no recuerdo yo desde cuando no tenía problemas para convertir una cadena con el formato de una fecha (supuestamente de forma correcta) a un objeto de tipo DateTime. A la memoria me vienen los tiempos del VB6 (o cualquier otro anterior a VB.NET) y sobre todo me acuerdo de cuando estaba escribiendo el código de mis foros con Visual Studio 2005 (ASP.NET 2.0).

    Y hoy va y me da este regalito el Visual Studio 2012:

     

    error al convertir fechas
    Figura 1. Error al convertir 31/01/2013 20:40:00 a una fecha…

    Así que… he tenido que optar por "salir del paso" convirtiendo "a mano" esas fechas erróneas y a usar el formato "yankee" para no tener problemas posteriores… espero que así sea…

     

    Te explico que todo ese "follón" es porque quiero guardar el contenido de una clase definida por mí mismo en los "settings" de Windows 8, con idea de poder usarla la próxima vez que ejecute la aplicación.

    En mi clase he sobrescrito el método ToString para que devuelva una cadena que posteriormente la pueda pasar desde lo que es, un tipo string, al tipo que he definido. Y ese ToString tiene el equivalente FromString para que devuelva un objeto usando el contenido de una cadena (con el formato que previamente he definido… o casi).

    El "problema" era que yo dejaba que el propio .NET se encargara de convertir la fecha en cadena, es decir, no usaba ningún formato específico, por tanto el formato devuelto es: #d/M/yyyy h:m:sAM/PM# (o más o menos) y claro, la cadena usada era diferente… total un follón.

    Así que… además de la comprobación manual, ahora lo que he hecho es que el método ToString devuelve la fecha con este formato: Fecha.ToString("#M/d/yyyy HH:mm:00#") y que salga el sol por Antequera

    El "00" para los segundo es porque en este caso quiero que los segundos siempre sean 00, ya que es para una alarma en la que ese espacio de tiempo no se tiene en cuenta…

     

    Te muestro parte del código que ahora estoy usando y lo que he tenido que hacer para salir del paso… (sabiendo que el error es porque el formato es dd/MM/yyyy HH:mm:ss, por eso no hay más comprobaciones en el caso de que falle la conversión del DateTime.TryParse.

     

    Private Const elSeparador As String = ","
    
    ''' <summary>
    ''' Devuelve una cadena con los datos básicos:
    ''' Fecha y Mensaje.
    ''' Si se devuelven más datos, 
    ''' devolver el mensaje siempre al final.
    ''' </summary>
    Public Overrides Function ToString() As String
        Return String.Format("{0}{2} {1}", Fecha.ToString("#M/d/yyyy HH:mm:00#"), Mensaje, elSeparador)
    End Function
    
    ''' <summary>
    ''' Devuelve un objeto Alarma a partir del contenido
    ''' de una cadena, en el formato: "Fecha, Mensaje"
    ''' (el devuelto por <see cref="ToString"/>)
    ''' En lugar de la coma se usará el caracter indicado en <see cref="elSeparador"/>
    ''' </summary>
    Public Shared Function FromString(s As String) As Alarma
        Dim it As New Alarma
    
        Dim i = s.IndexOf(elSeparador)
        If i = -1 Then
            Return Nothing
        End If
    
        If DateTime.TryParse(s.Substring(0, i), it.Fecha) = False Then
            Dim s1 = s.Substring(0, i)
            ' si da el error es porque está en formato dd/MM/yyyy HH:mm:ss
            Dim dia = CInt(s1.Substring(0, 2))
            Dim mes = CInt(s1.Substring(3, 2))
            Dim año = CInt(s1.Substring(6, 4))
            Dim hora = CInt(s1.Substring(11, 2))
            Dim minuto = CInt(s1.Substring(14, 2))
            it.Fecha = New DateTime(año, mes, dia, hora, minuto, 0)
        End If
        'it.Fecha = CDate(s.Substring(0, i))
        it.Mensaje = s.Substring(i + 1).TrimStart()
    
        Return it
    End Function
    
    

     

    Sólo lo muestro en VB porque en C# no lo estoy usando para este programa, pero como comprobarás no es un código demasiado complicado… creo… 😉

     

    Pues ya está… ahí queda eso… para que no te confíes con las fechas desde cadena… 😉

     

    Nos vemos.

    Guillermo

  • Usar el corrector ortográfico del control TextBox (Windows Store)

     

    Pues eso… que el control TextBox que viene en el Visual Studio 2012 para las aplicaciones de la Tienda de Windows (Windows Store / Windows 8 / estilo Metro) tiene una propiedad llamada IsSpellCheckEnabled que si le asignamos un valor verdadero utilizará el corrector ortográfico y nos marcará las palabras que no reconozca, que no quiere decir que no estén bien…

    La asignación la podemos hacer en modo de diseño (y supongo que por medio de código en el constructor de la clase / página en la que esté definido esa caja de textos que queremos que use el corrector ortográfico).

    Este es el código que he usado en la aplicación en el que lo voy a utilizar (es la primera vez que uso un control con corrección ortográfica, al menos de forma consciente).

     

    <TextBox x:Name="txtTexto" Grid.Column="1" Grid.Row="1" Text="" 
         Width="Auto" MinWidth="200" Margin="0,6" IsSpellCheckEnabled="True" 
             TextWrapping="Wrap" Height="80"/>
    
    

     

    Y en esta captura lo puedes ver en acción:

     

    IsSpellCheckEnabled

    Figura 1.

     

    Algunas palabras las corrige automáticamente y otras, simplemente te las marca como no válidas.

    Y por supuesto te da la opción de corregirla (figura 2)… siempre que el corrector "sepa" cómo hacerlo.

     

    IsSpellCheckEnabled 02

    Figura 2. Opciones del corrector ortográfico

     

     

    Nos vemos.

    Guillermo