5
\$\begingroup\$

Information

I have a Multiscreen Application written for a Client that basically is displaying Video content with MediaElements bind to a ContentControl on 5 Screens horizontally(5 splittet Videos). Depending on wich view the User is im playing different 5 Videos and Stopping the Other Videos.

I've put the MediaElements in a library and at App Start I'm loading the 5x5 Videos with 1920x1080(mp4). The App runs ok but I'm not happy with my Code, and I have the feeling that this could be done much better and I always keep questioning myself because of my Code.

Since I'm working alone and I don't know other Devs I would love to hear criticism about my Code because I want to learn to get better

The Code

 public class VideoWallViewModel : BindableBase {
        public VideoWallViewModel() {
            Initialize();
        }

        #region Functions

        private void Initialize() {
            _iEventAggregator = Event.EventInstance.EventAggregator;

            MediaElement0 = new MediaElement();
            MediaElement1 = new MediaElement();
            MediaElement2 = new MediaElement();
            MediaElement3 = new MediaElement();
            MediaElement4 = new MediaElement();

            MediaElement0.BeginInit();
            MediaElement1.BeginInit();
            MediaElement2.BeginInit();
            MediaElement3.BeginInit();
            MediaElement4.BeginInit();
            MediaElement0.LoadedBehavior = MediaState.Manual;
            MediaElement1.LoadedBehavior = MediaState.Manual;
            MediaElement2.LoadedBehavior = MediaState.Manual;
            MediaElement3.LoadedBehavior = MediaState.Manual;
            MediaElement4.LoadedBehavior = MediaState.Manual;

            MediaElement0.Loaded += MediaElementOnLoaded;
            MediaElement1.Loaded += MediaElementOnLoaded;
            MediaElement2.Loaded += MediaElementOnLoaded;
            MediaElement3.Loaded += MediaElementOnLoaded;
            MediaElement4.Loaded += MediaElementOnLoaded;

            MediaElement0.MediaOpened += MediaElementOnMediaOpened;
            MediaElement1.MediaOpened += MediaElementOnMediaOpened;
            MediaElement2.MediaOpened += MediaElementOnMediaOpened;
            MediaElement3.MediaOpened += MediaElementOnMediaOpened;
            MediaElement4.MediaOpened += MediaElementOnMediaOpened;

            MediaElement0.MediaEnded += MediaElementOnMediaEnded;
            MediaElement1.MediaEnded += MediaElementOnMediaEnded;
            MediaElement2.MediaEnded += MediaElementOnMediaEnded;
            MediaElement3.MediaEnded += MediaElementOnMediaEnded;
            MediaElement4.MediaEnded += MediaElementOnMediaEnded;

            MediaElement0.MediaFailed += MediaElement0OnMediaFailed;
            MediaElement1.MediaFailed += MediaElement0OnMediaFailed;
            MediaElement2.MediaFailed += MediaElement0OnMediaFailed;
            MediaElement3.MediaFailed += MediaElement0OnMediaFailed;
            MediaElement4.MediaFailed += MediaElement0OnMediaFailed;

            MediaElement0.EndInit();
            MediaElement1.EndInit();
            MediaElement2.EndInit();
            MediaElement3.EndInit();
            MediaElement4.EndInit();

            MediaElement0.Volume = 0;
            MediaElement1.Volume = 0;
            MediaElement2.Volume = 0;
            MediaElement3.Volume = 0;
            MediaElement4.Volume = 0;


            OutroTimer = new DispatcherTimer{
                Interval = new TimeSpan(0, 0, 0, 60)
            };
            OutroTimer.Tick += DispatcherTimerOnTick;
        }

        private static void MediaElement0OnMediaFailed(object sender, ExceptionRoutedEventArgs exceptionRoutedEventArgs) {
            var errorException = exceptionRoutedEventArgs.ErrorException;
            var media = exceptionRoutedEventArgs.Source as MediaElement;
            MessageBox.Show($"Screen:\n{media?.Source}\nException:\n{errorException.StackTrace}", "Media Failed",
                MessageBoxButton.OK, MessageBoxImage.Error);
        }

        private void DispatcherTimerOnTick(object sender, EventArgs eventArgs) {
            State = State.Stop;
            OutroTimer.Stop();
            TimerCompletedEventHandler?.Invoke();
        }

        private void ApplyState() {
            switch (State) {
                case State.Stop:
                    Stop();
                    Visibility = Visibility.Hidden;
                    break;

                case State.Play:
                    Play();
                    Visibility = Visibility.Visible;
                    break;

                case State.Pause:
                    Pause();
                    Visibility = Visibility.Visible;
                    break;

                case State.None:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        private void MediaChanged(VideoWallMedia media) {
            MediaElement0.Source = media.Video0;
            MediaElement1.Source = media.Video1;
            MediaElement2.Source = media.Video2;
            MediaElement3.Source = media.Video3;
            MediaElement4.Source = media.Video4;

            switch (State) {
                case State.Stop:
                    Stop();
                    break;

                case State.Play:
                    Play();
                    break;

                case State.Pause:
                    Pause();
                    break;

                case State.None:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        private static void MediaElementOnLoaded(object sender, RoutedEventArgs routedEventArgs) {
            var mediaElement = sender as MediaElement;
            mediaElement?.Stop();
        }

        private void MediaElementOnMediaEnded(object sender, RoutedEventArgs routedEventArgs) {
            var mediaElement = sender as MediaElement;
            if (StopAtLastFrame) {
                mediaElement.Position = new TimeSpan(12);
                mediaElement.Pause();

                if (!OutroTimer.IsEnabled) {
                    OutroTimer.Start();
                }

                if (!fired) {
                    _iEventAggregator.GetEvent<PubSubEvent>().Publish();
                    fired = true;
                }
            }
            else {
                if (Loop) {
                    mediaElement?.Stop();
                    mediaElement?.Play();
                }
                else {
                    State = State.Stop;
                    _iEventAggregator.GetEvent<PubSubEvent>().Publish();
                }
            }
        }

        private void MediaElementOnMediaOpened(object sender, RoutedEventArgs routedEventArgs) {
            var mediaElement = sender as MediaElement;
            if (mediaElement == null) {
                return;
            }

            _loadedMediaElements.Add(mediaElement);
            if (_loadedMediaElements.Count != 5 || State != State.Play) {
                return;
            }

            foreach (var element in _loadedMediaElements) {
                element.Play();
            }

            _loadedMediaElements = new List<MediaElement>();
        }

        private void Pause() {
            MediaElement0.Pause();
            MediaElement1.Pause();
            MediaElement2.Pause();
            MediaElement3.Pause();
            MediaElement4.Pause();
        }

        private void Play() {
            MediaElement0.Play();
            MediaElement1.Play();
            MediaElement2.Play();
            MediaElement3.Play();
            MediaElement4.Play();
        }

        private void Stop() {
            MediaElement0.Stop();
            MediaElement1.Stop();
            MediaElement2.Stop();
            MediaElement3.Stop();
            MediaElement4.Stop();
        }

        #endregion
\$\endgroup\$
2
  • \$\begingroup\$ Do you really want to play all media elements at the same time? \$\endgroup\$
    – t3chb0t
    Commented Mar 3, 2017 at 12:09
  • \$\begingroup\$ yes this are basically 5 screens with one whole video splitet on 5 screens so 5 videos. \$\endgroup\$
    – iNCEPTiON_
    Commented Mar 3, 2017 at 20:14

1 Answer 1

7
\$\begingroup\$

A way to reduce the amount of code in initialize and allow it to be more flexible is by putting your MediaElements into an array:

var mediaElems = new[]{
    new MediaElement(),
    new MediaElement(),
    new MediaElement(),
    new MediaElement(),
    new MediaElement()
}

foreach(var elem in mediaElems){
    elem.BeginInit();
    elem.LoadedBehavior = MediaState.Manual;
    elem.Loaded += MediaElementOnLoaded;
    elem.MediaOpened += MediaElementOnMediaOpened;
    elem.MediaEnded += MediaElementOnMediaEnded;
    elem.MediaFailed += MediaElement0OnMediaFailed;
    elem.EndInit();
    elem.Volume = 0;
}

If you let this be a field of your class this._mediaElems you can also reduce Pause, Play and Stop

private void Pause() {
    foreach(var elem in _mediaElems){
        elem.Pause();
    }
}

private void Play() {
    foreach(var elem in _mediaElems){
        elem.Play();
    }
}

private void Stop() {
    foreach(var elem in _mediaElems){
        elem.Stop();
    }
}

You defined ApplyState but you forgot to use it on MediaChanged. You should apply the same array idea to VideoWallMedia, however I would first start by looking at VideoWallMedia and MediaElement and see how they are related, it seems they are not modeled correctly.

This method is not being referenced anywhere, maybe you can delete the code?

private void MediaChanged(VideoWallMedia media) {
    _mediaElems[0].Source = media.Video0;
    _mediaElems[1].Source = media.Video1;
    _mediaElems[2].Source = media.Video2;
    _mediaElems[3].Source = media.Video3;
    _mediaElems[4].Source = media.Video4;

    ApplyState();
}
\$\endgroup\$
2
  • \$\begingroup\$ Thanks for this Nice Review. I cant put those MediaElements in an Array because im binding them to a ContentControl. Or would this be possible? \$\endgroup\$
    – iNCEPTiON_
    Commented Mar 3, 2017 at 20:35
  • 1
    \$\begingroup\$ @iNCEPTiON_ If I am not mistaken there's nothing stopping you from putting them into an array even if you use binding. \$\endgroup\$ Commented Mar 3, 2017 at 21:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.