【发布时间】:2018-04-10 12:49:36
【问题描述】:
我的代码后面有以下代码:
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);
}
}
我想遵循 MVVM 模式,并将这段代码移到我的 ViewModel 中,目前它只有很少的属性。我已经在这里和 StackOverflow 之外阅读了很多关于该主题的答案,我已经下载了一些 github 项目以检查有经验的程序员如何处理特定情况,但这些似乎都没有为我消除困惑。我想看看如何重构我的案例以遵循 MVVM 模式。
这些是额外的扩展方法,也是 ViewModel 本身:
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));
}
}
我已尝试按照 cmets 中的要求准备好代码复制/粘贴,如果您想完全复制它,则视图后面代码中的所有控件都是在 XAML 中创建的。
【问题讨论】:
-
看起来大多数方法应该被视图模型中的属性替换,并且视图应该绑定到这些属性
-
@ASh 这不会违反 MVVM 模式吗?我直接引用了视图中的一些项目。
-
@ASh 你能否详细说明,也许是一个答案,我对使用属性的解决方案非常感兴趣,我也准备好为这个问题提供赏金。
-
我想到的是:视图模型类,它使用属性实现 INotifyPropertyChanged,例如:
public class Vm:INotifyPropertyChanged { public bool State {get;set;} public string MovieElapsedTimeString {get;set;} }(所有属性都会引发更改事件)。并且视图使用绑定:IsEnabled="{Binding Path=State}"、Content="{Binding MovieElapsedTimeString}"。不确定 MediaElement 属性是否可绑定,但有针对这种情况的解决方法。附言未经测试,因为我无法复制您的代码示例并运行,它不会编译
标签: c# wpf mvvm view viewmodel