Click here to Skip to main content
15,886,075 members
Articles / Web Development / ASP.NET

Windows Phone 7 View Model Style Video Player

,
Rate me:
Please Sign up or sign in to vote.
4.95/5 (82 votes)
14 Nov 2010CPOL72 min read 195.6K   3.9K   91  
A Designer/Developer collaboration in an example of a Windows Phone 7 View Model Style Video Player
// From:
// WPBehaviorsLibrary
// http://aimeegurl.com/2010/03/18/panoramic-navigation-on-windows-phone-7-with-no-code/
//

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Controls.Primitives;

namespace BehaviorsLibrary
{

    /// <summary>
    /// Action to implement VisualStateManager.GoToState.
    /// Navigates the context which this action resides.
    /// </summary>
    [DefaultTrigger(typeof(ButtonBase), typeof(System.Windows.Interactivity.EventTrigger), new object[] { "Click" }),
     DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), new object[] { "MouseLeftButtonDown" })]
    public class GoToState : TargetedTriggerAction<FrameworkElement>
    {

        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty StateNameProperty = DependencyProperty.Register("StateName", typeof(string), typeof(GoToState), new PropertyMetadata(null));

        /// <summary>
        /// The name of the state which is to be activated.
        /// </summary>
        public string StateName
        {
            get { return (string)this.GetValue(GoToState.StateNameProperty); }
            set { this.SetValue(GoToState.StateNameProperty, value); }
        }

        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty UseTransitionsProperty = DependencyProperty.Register("UseTransitions", typeof(bool), typeof(GoToState), new PropertyMetadata(true));

        /// <summary>
        /// True if transitions are to be used for the state change.
        /// </summary>
        public bool UseTransitions
        {
            get { return (bool)this.GetValue(GoToState.UseTransitionsProperty); }
            set { this.SetValue(GoToState.UseTransitionsProperty, value); }
        }

        /// <summary>
        /// Implementation of the Invoke.
        /// </summary>
        /// <param name="arguments"></param>
        protected override void Invoke(object arguments)
        {
            Control targetControl = this.TargetControl;
            if (targetControl != null && !string.IsNullOrEmpty(this.StateName))
            {
                VisualStateManager.GoToState(targetControl, this.StateName, this.UseTransitions);
            }

        }

        /// <summary>
        /// Get the control which this action should be changing the state of.
        /// The control is always the parent in the logical tree which contains a VSM. If this
        /// action is attached to a button in UserControl.xaml, then the state group should be the
        /// UserControl's state group- not the Button's.
        /// </summary>
        private Control TargetControl
        {
            get
            {
                FrameworkElement parent = this.Target as FrameworkElement;
                bool foundVSM = false;

                while (parent != null)
                {
                    if (!foundVSM)
                    {
                        IList vsgs = VisualStateManager.GetVisualStateGroups(parent);
                        if (vsgs != null && vsgs.Count > 0)
                            foundVSM = true;
                    }

                    if (foundVSM)
                    {
                        Control parentControl = parent as Control;
                        if (parentControl != null)
                            return parentControl;
                    }
                    parent = parent.Parent as FrameworkElement;
                }

                return null;
            }
        }

    }

    /// <summary>
    /// Base class for a number of GoToState triggers.
    /// </summary>
    public abstract class GoToStateBase : TargetedTriggerAction<FrameworkElement>
    {

        private int currentStateIndex = 0;

        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty UseTransitionsProperty = DependencyProperty.Register("UseTransitions", typeof(bool), typeof(GoToStateBase), new PropertyMetadata(true));

        /// <summary>
        /// True if transitions should be used for the state change.
        /// </summary>
        public bool UseTransitions
        {
            get { return (bool)this.GetValue(GoToStateBase.UseTransitionsProperty); }
            set { this.SetValue(GoToStateBase.UseTransitionsProperty, value); }
        }

        /// <summary>
        /// Hooks up necessary handlers for the state changes.
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

            Control control = this.TargetControl;
            if (control != null)
            {
                foreach (VisualStateGroup vsg in this.TargetVSM)
                {
                    vsg.CurrentStateChanged += this.HandleStateChanged;
                }
            }
            else
            {
                Dispatcher.BeginInvoke(delegate
                {
                    this.OnAttached();
                });
            }
        }

        /// <summary>
        /// Cleans up when getting removed.
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            Control control = this.TargetControl;
            if (control != null)
            {
                foreach (VisualStateGroup vsg in this.TargetVSM)
                {
                    vsg.CurrentStateChanged -= this.HandleStateChanged;
                }
            }
        }

        private void HandleStateChanged(object sender, VisualStateChangedEventArgs e)
        {
            int index = 0;
            foreach (VisualStateGroup vsg in this.TargetVSM)
            {
                foreach (VisualState state in vsg.States)
                {
                    if (state == e.NewState)
                    {
                        this.currentStateIndex = index;
                    }
                    ++index;
                }
            }
        }

        /// <summary>
        /// The total number of states in the targetted VSM.
        /// </summary>
        protected int StateCount
        {
            get
            {
                int count = 0;
                foreach (VisualStateGroup vsg in this.TargetVSM)
                    foreach (VisualState state in vsg.States)
                        ++count;
                return count;
            }
        }

        /// <summary>
        /// The index of the current state in the targetted VSM.
        /// </summary>
        protected int CurrentStateIndex
        {
            get { return this.currentStateIndex; }
        }

        /// <summary>
        /// Goes to the specified state on the targetted VSM.
        /// </summary>
        /// <param name="targetIndex">index of the state to be activated</param>
        /// <param name="useTransitions">True if transitions should be used.</param>
        protected void GoToState(int targetIndex, bool useTransitions)
        {

            Control targetControl = this.TargetControl;
            if (targetControl == null)
                return;

            int index = 0;
            foreach (VisualStateGroup vsg in this.TargetVSM)
            {
                foreach (VisualState state in vsg.States)
                {
                    if (index == targetIndex)
                    {
                        VisualStateManager.GoToState(targetControl, state.Name, useTransitions);
                        break;
                    }
                    ++index;
                }
            }
        }

        /// <summary>
        /// Get the control which this action should be changing the state of.
        /// The control is always the parent in the logical tree which contains a VSM. If this
        /// action is attached to a button in UserControl.xaml, then the state group should be the
        /// UserControl's state group- not the Button's.
        /// </summary>
        private Control TargetControl
        {
            get
            {
                return GoToStateBase.FindTargetControl(this.Target);
            }
        }

        private IList<VisualStateGroup> TargetVSM
        {
            get
            {
                return GoToStateBase.FindVSM(this.Target);
            }
        }

        internal static Control FindTargetControl(FrameworkElement element)
        {
            FrameworkElement parent = element;
            bool foundVSM = false;

            while (parent != null)
            {
                if (!foundVSM)
                {
                    IList vsgs = VisualStateManager.GetVisualStateGroups(parent);
                    if (vsgs != null && vsgs.Count > 0)
                        foundVSM = true;
                }

                if (foundVSM)
                {
                    Control parentControl = parent as Control;
                    if (parentControl != null)
                        return parentControl;
                }
                parent = parent.Parent as FrameworkElement;
            }

            return null;
        }

        internal static IList<VisualStateGroup> FindVSM(FrameworkElement element)
        {
            FrameworkElement parent = element;
            bool foundVSM = false;

            List<VisualStateGroup> stateGroups = new List<VisualStateGroup>();

            while (parent != null)
            {
                if (!foundVSM)
                {
                    IList vsgs = VisualStateManager.GetVisualStateGroups(parent);
                    if (vsgs != null && vsgs.Count > 0)
                    {
                        foreach (VisualStateGroup vsg in vsgs)
                            stateGroups.Add(vsg);
                        return stateGroups;
                    }
                }
                parent = parent.Parent as FrameworkElement;
            }

            return stateGroups;
        }

        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty LoopProperty = DependencyProperty.Register("Loop", typeof(bool), typeof(GoToStateBase), new PropertyMetadata(false));

        /// <summary>
        /// True if this should loop around when it gets to the end.
        /// </summary>
        public bool Loop
        {
            get { return (bool)this.GetValue(GoToStateBase.LoopProperty); }
            set { this.SetValue(GoToStateBase.LoopProperty, value); }
        }

    }

    /// <summary>
    /// Go to the next state in the targetted VSM.
    /// </summary>
    [DefaultTrigger(typeof(ButtonBase), typeof(System.Windows.Interactivity.EventTrigger), new object[] { "Click" }),
        DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), new object[] { "MouseLeftButtonDown" })]
    public class GoToNextState : GoToStateBase
    {

        /// <summary>
        /// Does the state transition.
        /// </summary>
        /// <param name="parameter"></param>
        protected override void Invoke(object parameter)
        {

            int index = this.CurrentStateIndex + 1;
            if (index >= this.StateCount && this.Loop)
                index = 0;

            this.GoToState(index, this.UseTransitions);
        }
    }

    /// <summary>
    /// Go to the previous state in the targetted VSM.
    /// </summary>
    [DefaultTrigger(typeof(ButtonBase), typeof(System.Windows.Interactivity.EventTrigger), new object[] { "Click" }),
        DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), new object[] { "MouseLeftButtonDown" })]
    public class GoToPreviousState : GoToStateBase
    {

        /// <summary>
        /// Does the state transition.
        /// </summary>
        /// <param name="parameter"></param>
        protected override void Invoke(object parameter)
        {
            int index = this.CurrentStateIndex - 1;
            if (index < 0 && this.Loop)
                index = this.StateCount - 1;

            this.GoToState(index, this.UseTransitions);
        }
    }

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) http://ADefWebserver.com
United States United States
Michael Washington is a Microsoft MVP. He is a ASP.NET and
C# programmer.
He is the founder of
AiHelpWebsite.com,
LightSwitchHelpWebsite.com, and
HoloLensHelpWebsite.com.

He has a son, Zachary and resides in Los Angeles with his wife Valerie.

He is the Author of:

Written By
User Interface Analyst
United Kingdom United Kingdom
I've been playing with computers since my first Acorn Electron, & after blowing up a few ZX Spectrums. I moved on to the C64 & Amiga, & eventually reluctantly on to the PC.

I have learnt a wide set of skills during my 38 years of existence, living in the UK, on the sunny south coast.

My main area of expertise is Graphic/Visual Design, Usability & UI Design. I am not a programmer, but am fairly technically minded due to studying Mechanical Engineering at Uni.

I have work both Freelance & for IBM as a Graphic Designer, & am skilled in the usual graphics packages like, PhotoShop, CorelDraw or Illustrator, Premier, Dreamweaver, Flash etc.
But I originally started with Lightwave & 3D animation.

Comments and Discussions