Silverlight Media Framework y MVVM – Play Silverlight

En la primera entrada de este blog, hablaba del patrón Modelo-Vista-ModeloVista (MVVM) como ejemplo de buenas prácticas en el desarrollo de aplicaciones Silverlight. Por otro lado, en el post anterior, el tema era Silverlight Media Framework como librería de referencia para reproducción de contenido multimedia.

Pues bien, a la hora de hacer confluir ambos aspectos en un mismo proyecto, ha aparecido un problema que obliga a hacer un “workaround” para poder seguir el patrón MVVM. Este problema surgió cuando intentaba asociar la propiedad Position de la clase CoreSmoothStreamingMediaElement, que representa el instante donde se encuentra la reproducción,  a un objeto en la clase Vista Modelo. Sin embargo, el binding no se hace correctamente y al modificar la propiedad desde la Vista Modelo, no tiene influencia sobre el reproductor.

Aspectos como este podrían resolverse en la release (v.2) que se está preparando para este mismo verano, pero vamos a ver cómo solucionarlo utilizando la actual versión de SMF, la 1.1.

Solución al problema

Para resolver esta problemática es necesario llevar a cabo tres acciones. En primer lugar, se ha de extender la clase CoreSmoothStreamingMediaElement para añadir una nueva propiedad de dependencia, que llamaremos PositionOverride.

La idea es hacer que cuando se modifique la propiedad PositionOverride, sea Position la que cambie. De ahí, que cuando se registra la propiedad de dependencia PositionOverride, se asigne una función de callback que será ejecutada cuando el valor de la propiedad cambie y que modificará Position. Así quedaría la clase resultante:


public class CoreMediaElement :
 CoreSmoothStreamingMediaElement
 {
      public TimeSpan PositionOverride
      {
           get { return (TimeSpan)GetValue(PositionOverrideProperty); }
           set { SetValue(PositionOverrideProperty, value); }
      }

      public static readonly DependencyProperty PositionOverrideProperty =
             DependencyProperty.Register(
                                "PositionOverride",
                                typeof(TimeSpan),
                                typeof(CoreSmoothStreamingMediaElement),
                                new PropertyMetadata(CoreMediaElement.OnPositionOverridePropertyChanged));

      private static void OnPositionOverridePropertyChanged(
      DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
           CoreMediaElement source = d as CoreMediaElement;
           source.OnPositionOverrideChanged();
      }

      private void OnPositionOverrideChanged()
      {
           if (Position != PositionOverride)
                Position = PositionOverride;
      }
 }

El siguiente paso sería utilizar la clase recién creada en el .xaml de la manera en que se ve en este código.


<p:Player x:Name="player" MarkerData="{Binding MyMarkerData}"  Style="{StaticResource PlayerStyle1}">
      <mytrivia:CoreMediaElement SmoothStreamingSource="{Binding  VideoUri}"
           PositionOverride="{Binding MarkerPosition}"
           Position="{Binding PlayerPosition, Mode=TwoWay}"
           AutoPlay="True" CanSeek="True" />
</p:Player>

El último paso es crear la clase modelo vista, que incluirá las propiedades con las que se hará el binding con el reproductor. Por un lado, PlayerPosition cuyo binding se hace en doble sentido y que en su set también modificará la otra propiedad que utilizaremos, MarkerPosition.


 public TimeSpan playerPosition;
 public TimeSpan PlayerPosition
 {
        get
        {
              return playerPosition;
        }
        set
        {
              playerPosition = value;
              MarkerPosition = value;
        }
 }

Por otro, la propiedad MarkerPosition con la que se hará el binding con la propiedad de dependencia creada (PositionOverride).


 private TimeSpan markerPosition;
 public TimeSpan MarkerPosition
 {
      get
      {
           return markerPosition;
      }
      set
      {
           this.markerPosition = value;
           OnPropertyChanged("MarkerPosition");
      }
 }

Así, finalmente, cuando hagamos un set sobre MarkerPosition, será la propiedad Position del MediaElement quien cambie de valor y el reproductor se posicionará sobre el instante de tiempo indicado.

Es evidente que no es la mejor forma de trabajar, ya que el simple hecho de tener que añadir dos propiedades para cambiar solo una, dificulta la mantenibilidad además de quedar un código algo ofuscado. Porque aunque el SMF es código abierto, veo preferible implementar nuevas funcionalidad extendiendo el framework, dada la evolución continua de la librería con la salida de nuevas versiones. Por ello, esperemos que la versión 2, que saldrá en poco tiempo, lo solucione.

Por último, en el próximo post explicaré más detalladamente cómo implementar el patrón MVVM en una pequeña aplicación de reproducción en la que además personalizaré el reproductor añadiendo marcadores, controles embebidos y cambiando el aspecto del propio reproductor.

Referencias:

Anuncios
Esta entrada fue publicada en Silverlight y etiquetada , , . Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s