How the Presentation Model could look like when using Silverlight 2.0 (Part 5)
Maybe the title of my blog post are not the best one now when I write about my little Presentation Model framework for Silverlight.
To day I notice some problems when it comes to switching views and also play movies and animations etc. For example to start playing a movie we need to call the MediaElement’s Play method. With my Framework we can only execute a Action method located in our Presentation Model, and I don’t want to pass a FrameworkElement as an argument to the Presentation Model, so there was no way to make sure an Action method can start playing a movie. So to solve this I created a specific class with the name ActionResult, this ActionResult class:
public class ActionResult { public ActionResult() { this.ActionResultHandler = new DefaultActionResultHandler(); } public IActionResultHandler ActionResultHandler { get; protected set; } }
Action methods can then return a ActionResult:
public class CustomerPresentationModel : Silverlight.Extension.PresentationModel { public ActionResult Show(string customerId) { return ChangeView("About.About", base.PreviousUsetState); } public ActionResult PlayMovie() { return new MovieActionResult(null, MovieAction.Play); } }
If an ActionResult is returned from a Action method, I will use the ActionResult’s ActionResultHandler and invoke the HandleActionResult method, where I pass the FrameworkElement that trigged the Action method and also pass the ActionResult class as an argument:
public interface IActionResultHandler { bool HandleActionResult(FrameworkElement sourceElement, ActionResult returnValue); }
To make sure I can start playing a movie from the Action method, I will pass a MovieActionResult, which will use a MoveActionResultHandler to handle the ActionResult and start playing the movie:
public class MovieActionResult : ActionResult { public MovieActionResult(Stream mediaSource, MovieAction movieAction) { this.MovieAction = movieAction; this.MediaSource = mediaSource; base.ActionResultHandler = new MovieActionResultHandler(); } public MovieAction MovieAction { get; internal set; } public Stream MediaSource { get; internal set; } }
public class MovieActionResultHandler : IActionResultHandler { public bool HandleActionResult(FrameworkElement sourceElement, ActionResult returnValue) { var mediaElement = sourceElement as MediaElement; if (mediaElement == null) throw new Exception(string.Format("The sourceElement ({0},{1}) for the MovieActionResultHandler is not of type MediaElement", sourceElement.Name, sourceElement.GetType().Name)); var actionResult = returnValue as MovieActionResult; if (actionResult == null) throw new Exception("The returnValue agrument is not of type MovieActionResult"); switch (actionResult.MovieAction) { case MovieAction.Play: mediaElement.Play(); break; case MovieAction.Pause: mediaElement.Pause(); break; case MovieAction.Resume: mediaElement.Play(); break; case MovieAction.Stop: mediaElement.Stop(); break; default: throw new Exception("Can't handle MovieAction"); } return true; } }
The MovieResultHandler can now interact with the FrameworkElement that trigged the Action method.
So to play a movie when the MouseLeftButtonUp is trigged we can simply write:
<MediaElement e:Attach.MouseLeftButtonUp="PlayMovie" AutoPlay="False" Source="http://localhost:4317/movie.wmv" Height="200" Width="200"/>
I have also added a ActionResult called DynamicChangeViewActionResult and a handler for it. By using this ActionResult we can dynamically specify a View and make sure our Silverlight applicaiton switches view after an Action method is executed:
public ActionResult Show(string customerId) { return ChangeView("About", customerId); }
The ChangeView is a method added to the base class PresentationModel which can be used to get some helper method, but aren’t needed. The ChangeView will return a DynamicChangeViewActionResult, and will get the About.xaml page and automatically replace the content of the “LayoutRoot” element with the new View. So my Framework can sort of also use the MVC pattern. By passing object as a second argument to the ChangeView, we can pass additional information to the next View’s Presentation Model’s Action methods. We can also specify a name of a ContentControl or Panel located on our View, and the make sure only a part of the View is updated with a new UserControl instead of the whole view.
public ActionResult Show(string customerId) { return ChangeView("About", "MyPanelToUpdate", customerId); }
So the basic ideas of using the ActionResult feature is only to make sure others can return their own ActionResult and handle the result of the Action method, for example to play an animation, or change an image or what ever.