My code has the following code:
public partial class MainWindow { private Track _movieSkipSliderTrack; private Slider sMovieSkipSlider = null; private Label lbTimeTooltip = null; private MediaElement Player = null; public VideoPlayerViewModel ViewModel { get { return DataContext as VideoPlayerViewModel; } } public MainWindow() { InitializeComponent(); } private void SMovieSkipSlider_OnLoaded(object sender, RoutedEventArgs e) { _movieSkipSliderTrack = (Track)sMovieSkipSlider.Template.FindName("PART_Track", sMovieSkipSlider); _movieSkipSliderTrack.Thumb.DragDelta += Thumb_DragDelta; _movieSkipSliderTrack.Thumb.MouseEnter += Thumb_MouseEnter; } private void Thumb_MouseEnter(object sender, MouseEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed && e.MouseDevice.Captured == null) { var args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left) { RoutedEvent = MouseLeftButtonDownEvent }; SetPlayerPositionToCursor(); _movieSkipSliderTrack.Thumb.RaiseEvent(args); } } private void Thumb_DragDelta(object sender, DragDeltaEventArgs e) { SetPlayerPositionToCursor(); } private void SMovieSkipSlider_OnMouseEnter(object sender, MouseEventArgs e) { lbTimeTooltip.Visibility = Visibility.Visible; lbTimeTooltip.SetLeftMargin(Mouse.GetPosition(sMovieSkipSlider).X); } private void SMovieSkipSlider_OnPreviewMouseMove(object sender, MouseEventArgs e) { double simulatedPosition = SimulateTrackPosition(e.GetPosition(sMovieSkipSlider), _movieSkipSliderTrack); lbTimeTooltip.AddToLeftMargin(Mouse.GetPosition(sMovieSkipSlider).X - lbTimeTooltip.Margin.Left + 35); lbTimeTooltip.Content = TimeSpan.FromSeconds(simulatedPosition); } private void SMovieSkipSlider_OnMouseLeave(object sender, MouseEventArgs e) { lbTimeTooltip.Visibility = Visibility.Hidden; } private void SetPlayerPositionToCursor() { Point mousePosition = new Point(Mouse.GetPosition(sMovieSkipSlider).X, 0); double simulatedValue = SimulateTrackPosition(mousePosition, _movieSkipSliderTrack); SetNewPlayerPosition(TimeSpan.FromSeconds(simulatedValue)); } private double CalculateTrackDensity(Track track) { double effectivePoints = Math.Max(0, track.Maximum - track.Minimum); double effectiveLength = track.Orientation == Orientation.Horizontal ? track.ActualWidth - track.Thumb.DesiredSize.Width : track.ActualHeight - track.Thumb.DesiredSize.Height; return effectivePoints / effectiveLength; } private double SimulateTrackPosition(Point point, Track track) { var simulatedPosition = (point.X - track.Thumb.DesiredSize.Width / 2) * CalculateTrackDensity(track); return Math.Min(Math.Max(simulatedPosition, 0), sMovieSkipSlider.Maximum); } private void SetNewPlayerPosition(TimeSpan newPosition) { Player.Position = newPosition; ViewModel.AlignTimersWithSource(Player.Position, Player); } }
I would like to follow the MVVM pattern and move this code to my ViewModel, which currently has only a few properties. I read a lot of answers here and outside of StackOverflow on this topic, I downloaded some github projects to check how experienced programmers handle specific situations, but none of this seems to fix the confusion for me. I would like to see how my case can be reorganized to follow the MVVM pattern.
These are additional extension methods, as well as the ViewModel itself:
static class Extensions { public static void SetLeftMargin(this FrameworkElement target, double value) { target.Margin = new Thickness(value, target.Margin.Top, target.Margin.Right, target.Margin.Bottom); } public static void AddToLeftMargin(this FrameworkElement target, double valueToAdd) { SetLeftMargin(target, target.Margin.Left + valueToAdd); } } public class VideoPlayerViewModel : ViewModelBase { private TimeSpan _movieElapsedTime = default(TimeSpan); public TimeSpan MovieElapsedTime { get { return _movieElapsedTime; } set { if (value != _movieElapsedTime) { _movieElapsedTime = value; OnPropertyChanged(); } } } private TimeSpan _movieLeftTime = default(TimeSpan); public TimeSpan MovieLeftTime { get { return _movieLeftTime; } set { if (value != _movieLeftTime) { _movieLeftTime = value; OnPropertyChanged(); } } } public void AlignTimersWithSource(TimeSpan currentPosition, MediaElement media) { MovieLeftTime = media.NaturalDuration.TimeSpan - currentPosition; MovieElapsedTime = currentPosition; } } public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } }
I tried to copy / paste the code as requested in the comments, all controls in the view code behind are created in XAML if you want to fully reproduce it.