Escenarios de características de Reversi

La muestra de Reversi usa varias características comunes de aplicaciones de la Tienda Windows con XAML y C#. En este tema, describimos la manera en que la muestra usa algunas de estas características y proporcionamos vínculos a temas sobre características clave.

No es necesario que comprendas toda la muestra, pero suponemos que ya conoces XAML y C#, que comprendes los conceptos básicos de cada característica o que deseas aprender sobre ellos leyendo los temas vinculados. Para obtener más información sobre los aspectos básicos del desarrollo de aplicaciones, consulta Crear la primera aplicación de la Tienda Windows con C# o Visual Basic.

Si quieres ver una introducción general a la muestra, consulta Desarrollar Reversi. Para comprender de qué manera varias características trabajan juntas como un todo, consulta Estructura de aplicación de Reversi.

Descarga la aplicación de muestra de Reversi o examina el código fuente.

Icono y pantalla de presentación

El icono de la aplicación y la pantalla de presentación son las primeras cosas que el usuario ve. Puedes usarlos para proporcionar un punto de entrada atractivo y para mostrar tu marca. Los más básicos son triviales, pero puedes hacer cosas más complejas como se describe en la documentación.

Recursos clave:

La compatibilidad de Reversi con iconos y pantalla de presentación es básica. Esta incluye dos tamaños de iconos y una pantalla de presentación, como se muestra aquí en tamaño reducido.

Iconos y pantalla de presentación de Reversi

Los nombres de archivo de imagen se establecen en el archivo Package.appxmanifest. No es necesaria ninguna otra implementación para este uso simple.

Barra de la aplicación

Las barras proporcionan un lugar estándar para poner comandos de aplicación. De manera predeterminada, los usuarios pueden mostrar u ocultar una barra de aplicación según sea necesario, haciendo de ella un buen lugar para comandos usados con menos frecuencia. Esto ayuda a mantener la interfaz de usuario (UI) principal enfocada en interacciones directas con el contenido.

Recursos clave:

Reversi incluye algunos comandos secundarios aptos para la barra de la aplicación: la posibilidad de pausar el reloj y de deshacer o rehacer movimientos. Durante la reproducción normal del juego, la barra de la aplicación se oculta, pero el usuario puede deslizarla desde arriba o abajo de la pantalla para verla u ocultarla.

Barra de la aplicación de Reversi

Este código, de GamePage.xaml, muestra la definición de la barra de la aplicación. Si bien el fondo y el borde son transparentes, la propiedad Background se establece en {x:Null} para evitar que la barra invisible bloquee las pulsaciones y clics. Esta configuración es necesaria, porque la barra de la aplicación se extiende a lo largo de toda la pantalla y se superpone con la fila inferior del panel de juego.


<Page.BottomAppBar>
  <AppBar x:Name="GamePageAppBar" IsSticky="True"
    Background="{x:Null}" BorderBrush="Transparent">
    <StackPanel Orientation="Horizontal">
      <Button Style="{StaticResource PauseAppBarButtonStyle}"
        Command="{Binding Clock.PauseCommand}"
        Visibility="{Binding Clock.IsPauseButtonVisible, 
          Converter={StaticResource BooleanToVisibilityConverter}}"/>
      <Button Style="{StaticResource PlayAppBarButtonStyle}"
        Command="{Binding Clock.PlayCommand}"          
        Visibility="{Binding Clock.IsPauseButtonVisible,
          Converter={StaticResource BooleanToVisibilityConverter}, 
          ConverterParameter=Reverse}"/>
      <Button Style="{StaticResource UndoAppBarButtonStyle}"
        Command="{Binding UndoCommand}"/>
      <Button Style="{StaticResource RedoAppBarButtonStyle}"
        Command="{Binding RedoCommand}"/>
    </StackPanel>
  </AppBar>
</Page.BottomAppBar>


En la barra de la aplicación, Reversi usa estilos de botón definidos en el archivo StandardStyles.xaml, generado por las plantillas de aplicación de Microsoft Visual Studio 2012. Estos estilos estándar proporcionan un círculo, icono, título y vista deshabilitada para cada botón. El comportamiento de un botón y su estado habilitado se proporcionan en los comandos de modelo de vista enlazados a las propiedades Command del botón, como se describe en la sección Comandos.

Los botones Reproducir y Pausar funcionan como un botón de alternancia único; pero, en lugar de usar un control ToggleButton, Reversi usa botones estándar con propiedades Visibility enlazadas a la misma propiedad de modelo de vista. Estos enlaces usan BooleanToVisibilityConverter, pero uno de ellos también tiene configurada una propiedad ConverterParameter que invierte el efecto del enlace. De esta forma, cada botón es visible solo cuando el otro no lo es. Para obtener información, consulta la sección Enlace de datos.

Notificaciones del sistema

Las notificaciones del sistema alertan a los usuarios cuando se produce un evento importante en la aplicación, aun cuando otra aplicación esté activa.

Recursos clave:

En Reversi, el equipo puede demorar un poco para hacer un movimiento. Si cambias a otra aplicación mientras esperas, una notificación del sistema te avisará cuando sea tu turno.

Notificación del sistema de Reversi

Reversi usa el mínimo código requerido para notificaciones del sistema y establece el campo Capacidad de aviso en , en el diseñador Package.appxmanifest. Dado que el código de las notificaciones del sistema es fácilmente reutilizable, se encuentra en una clase auxiliar, en la carpeta Common.

En GameViewModel.cs:


if (!Windows.UI.Xaml.Window.Current.Visible && !IsCurrentPlayerAi)
{
    Toast.Show("It's your turn!");
}


En Toast.cs:


public static void Show(string text)
{
    const string template = "<toast duration='short'><visual>" +
        "<binding template='ToastText01'><text id='1'>{0}</text>" +
        "</binding></visual></toast>";
    var toastXml = new XmlDocument();
    toastXml.LoadXml(String.Format(template, text));
    var toast = new ToastNotification(toastXml);
    ToastNotificationManager.CreateToastNotifier().Show(toast);
}


Controles flotantes de configuración

El acceso a Configuración proporciona acceso normalizado a la configuración de la aplicación.

Recursos clave:

Reversi tiene dos controles flotantes de configuración, uno para las opciones de pantalla y otro para las opciones de juego nuevo.

Controles flotantes de configuración de Reversi

Este código de App.xaml.cs muestra la manera en que Reversi controla el evento SettingsPane.CommandsRequested para crear objetos SettingsCommand. Estos comandos hacen referencia a métodos que crean y abren los controles flotantes.


SettingsPane.GetForCurrentView().CommandsRequested += OnCommandsRequested;



private void OnCommandsRequested(SettingsPane sender,
    SettingsPaneCommandsRequestedEventArgs args)
{
    args.Request.ApplicationCommands.Add(new SettingsCommand("Display",
        "Display", _ => ShowDisplaySettingsFlyout()));
    args.Request.ApplicationCommands.Add(new SettingsCommand("NewGame",
        "New game options", _ => ShowNewGameSettingsFlyout()));
}


Enlace de datos

El enlace de datos permite conectar controles de la interfaz de usuario con los datos que muestran. Si se modifica uno, se actualizará el otro. El enlace de datos es común en formularios de entrada de datos, pero también puede usarse para controlar toda la interfaz de usuario y mantenerla separada de la lógica de la aplicación.

Recursos clave:

Reversi usa enlaces de datos para conectar la interfaz de usuario (o capa "vista") con la lógica de la aplicación (o capa "modelo de vista"). Estas capas ayudan a separar la interfaz de usuario de otro código y se conocen como el patrón Model-View-ViewModel. Para obtener más información sobre el uso de este patrón en Reversi, consulta Estructura de aplicación de Reversi.

La mayoría de los enlaces en Reversi se definen en XAML por medio de la extensión de marcado de enlace; aunque, en pocos casos, se usa el código subyacente (por ejemplo, en el archivo Board.xaml.cs). Cada página establece su propiedad DataContext que todos sus elementos usan como origen de datos en los enlaces.

Actualizaciones de la interfaz de usuario

Los enlaces de datos controlan la interfaz de usuario de Reversi. Las interacciones de la interfaz de usuario producen cambios en las propiedades de los orígenes de datos y los enlaces de datos responden a esos cambios actualizando la interfaz de usuario.

Estas actualizaciones funcionan porque las clases de modelo de vista de Reversi heredan la clase BindableBase generada por las plantillas de aplicación y elemento de Visual Studio 2012 (sin incluir las plantillas en blanco). BindableBase proporciona una implementación INotifyPropertyChanged estándar y algunos métodos de soporte. El método SetProperty actualiza el valor de respaldo de una propiedad, además de la interfaz de usuario asociada, mediante una llamada a un método único. El método OnPropertyChanged actualiza la interfaz de usuario enlazada a las propiedades especificadas. Esto es útil para controlar el intervalo de las actualizaciones y para las propiedades que obtienen valores a partir de otras propiedades.

Este código de GameViewModel.cs muestra el uso básico de SetProperty y OnPropertyChanged.


private State _currentPlayer = State.One;
public State CurrentPlayer 
{ 
    get { return _currentPlayer; } 
    set 
    { 
        SetProperty(ref _currentPlayer, value);
        OnPropertyChanged("IsCurrentPlayerAi");
        OnPropertyChanged("IsPlayerOneAi");
        OnPropertyChanged("IsPlayerTwoAi");
        OnPropertyChanged("CurrentPlayerAiSearchDepth");
    } 
}


Conversión de valores

Puedes convertir todos los valores de una propiedad para adecuarlos al enlace, creando propiedades calculadas; es decir, propiedades que obtienen sus valores a partir de otras propiedades.

Este código de GameViewModel.cs muestra una propiedad calculada simple. La interfaz de usuario que se encuentra enlazada a esta propiedad se actualiza mediante la llamada OnPropertyChanged coincidente del ejemplo anterior.


public bool IsPlayerOneAi
{
    get { return (int)PlayerOne > 0; }
}


Las propiedades calculadas son fáciles de crear para cualquier tipo de conversión que necesites, pero tienden a desordenar el código. Para conversiones comunes, recomendamos poner el código de conversión en una implementación IValueConverter reutilizable. Reversi usa las clases NullStateToVisibilityConverter y BooleanToVisibilityConverter en la carpeta Common/Converters para enlaces que muestran y ocultan varios elementos de la interfaz de usuario.

Este enlace de StartPage.xaml muestra u oculta un panel, en función de si una propiedad tiene o no un valor.


<StackPanel Visibility="{Binding Path=GameViewModel, 
  Converter={StaticResource NullStateToVisibilityConverter}}">


Este enlace de NewGameSettings.xaml muestra u oculta un panel, en función del estado de un control ToggleSwitch.


<StackPanel Orientation="Horizontal" 
  Visibility="{Binding IsOn, ElementName=PlayerOneSwitch, 
    Converter={StaticResource BooleanToVisibilityConverter}}">


Para ver más ejemplos, consulta Barra de la aplicación.

Comandos

Los comportamientos de Button, por lo general, se implementan con controladores de evento Click en archivos de código subyacente. Reversi hace esto con los botones de navegación, pero para otros botones, separa el código de botón UI del no UI que el botón invoca. Para ello, las propiedades Button.Command se enlazan a propiedades de modelo de vista que devuelven implementaciones ICommand.

Las propiedades de comandos de Reversi son de tipo DelegateCommand o DelegateCommand<T>. Estas clases están en el archivo Common/DelegateCommand.cs y proporcionan implementaciones ICommand estándar y reutilizables. Puedes usar estas clases para simplificar la creación de comandos de uso único y mantener el código necesario recluido en implementaciones de propiedades únicas.

Este código de GameViewModel.cs muestra el comando de movimiento usado por los espacios de panel, que son botones personalizados. El operador ?? o "fusión nula" significa que el valor del campo se devuelve siempre que no sea null; de lo contrario, se establece el campo y se devuelve un valor nuevo. Esto significa que un objeto de comando único se crea la primera vez que se accede a una propiedad y el mismo objeto se reutiliza para todos los accesos futuros. El objeto de comando se inicializa configurando sus propiedades CanExecute y Execute en expresiones lambda, que por lo general llaman a otros métodos.


private DelegateCommand<Space> _moveCommand;
public DelegateCommand<Space> MoveCommand
{
    get
    {
        return _moveCommand ?? ( _moveCommand =
            new DelegateCommand<Space>
            {
                CanExecute = space => 
                    IsValidMove(space) && !IsCurrentPlayerAi,
                Execute = async space => await Move(space)
            });
    }
}


El enlace de datos llama al método CanExecute para actualizar el estado habilitado del botón. Sin embargo, los enlaces de comandos dependen de la notificación de cambio similar a la de otros enlaces (explicado en Actualizaciones de la interfaz de usuario). Este código de GameViewModel.cs muestra la manera en que el método NextMove sincroniza el estado de modelo de vista con el estado de modelo y luego llama a OnCanExecuteChanged para cada comando, antes de continuar con el siguiente movimiento.


public async Task NextMove()
{
    IsGameOver = Game.IsGameOver();
    CurrentPlayer = IsGameOver ? Winner : Game.CurrentPlayer;
    Score = Game.GetScore();
    UpdateBoard();
    UndoCommand.OnCanExecuteChanged();
    RedoCommand.OnCanExecuteChanged();
    MoveCommand.OnCanExecuteChanged();
    if ((IsGameAiVersusAi && Clock.IsPaused) || IsGameOver) return;
    if (IsValidMove(null)) await Pass();
    else if (IsCurrentPlayerAi) await AiMove();
}


Propiedades de dependencia personalizadas

Reversi usa propiedades de dependencia personalizadas en sus controles personalizados, para poder usar actualizaciones de enlaces de datos y cambiar estados visuales. Los estados visuales y las transiciones animadas se definen en XAML mediante la clase VisualStateManager. Pero no hay forma de enlazar un estado visual directamente a una propiedad de modelo de vista. Las propiedades de dependencia personalizas proporcionan destinos para enlazar a propiedades de vista de modelo. Las propiedades de dependencia incluyen devoluciones de llamadas de propiedad cambiada que hacen las llamadas necesarias al método VisualStateManager.GoToState.

Este código muestra la manera en que el control PlayerStatus usa código subyacente, para enlazar sus propiedades de dependencia personalizadas a propiedades de modelo de vista. Aquí solo se muestra una de las propiedades de dependencia, incluido el método de la devolución de llamada de propiedad cambiada. La devolución de llamada y la invalidación de método OnApplyTemplate llaman al método de actualización. Sin embargo, la llamada OnApplyTemplate inicializa el control para su primera aparición en pantalla, por lo cual no usa transiciones animadas.


public PlayerStatus()
{
    DefaultStyleKey = typeof(PlayerStatus);
    SetBinding(CurrentPlayerProperty,
        new Binding { Path = new PropertyPath("CurrentPlayer") });
    SetBinding(IsClockShowingProperty,
        new Binding { Path = new PropertyPath("Settings.IsClockShowing") });
    SetBinding(IsGameOverProperty,
        new Binding { Path = new PropertyPath("IsGameOver") });
    SetBinding(WinnerProperty,
        new Binding { Path = new PropertyPath("Winner") });
}

protected override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    UpdatePlayerState(false);
    UpdateClockState(false);
    UpdateGameOverState(false);
}

public bool IsClockShowing
{
    get { return (bool)GetValue(IsClockShowingProperty); }
    set { SetValue(IsClockShowingProperty, value); }
}

public static readonly DependencyProperty IsClockShowingProperty =
    DependencyProperty.Register(
        "IsClockShowing", typeof(bool), typeof(PlayerStatus), 
        new PropertyMetadata(true, IsClockShowingChanged));

private static void IsClockShowingChanged(DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
    (d as PlayerStatus).UpdateClockState(true);
}

private void UpdateClockState(bool useTransitions)
{
    GoToState(IsClockShowing ? "ClockShowing" : "ClockHidden",
        useTransitions);
}

private void GoToState(string state, bool useTransitions)
{
    VisualStateManager.GoToState(this, state, useTransitions);
}


Temas relacionados

Desarrollar juegos
Aplicación de muestra de Reversi
Desarrollar Reversi
Estructura de aplicación de Reversi
Crear la primera aplicación de la Tienda Windows con C# o Visual Basic
Guía básica para crear aplicaciones de la Tienda Windows con C# o Visual Basic
Enlace de datos
Diseñar juegos espectaculares para Windows

 

 

Mostrar:
© 2014 Microsoft