gpt4 book ai didi

c# - 将方法从 View 移动到 View 模型 - WPF MVVM

转载 作者:太空狗 更新时间:2023-10-29 23:36:23 25 4
gpt4 key购买 nike

我的代码后面有以下代码:

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));
}
}

我已尝试按照评论中的要求准备好代码复制/粘贴,如果您想完全复制它,View 代码后面的所有控件都是在 XAML 中创建的。

最佳答案

我们的想法是在您的 VM 中为您想要更新的 UI 的每个区域或需要处理的事件分别拥有一个属性和命令。

只要看一眼您当前的代码,我认为如果您直接 Hook 到 slider 的 Value 属性并绑定(bind)它(双向),您将有更轻松的时间(您将能够删除一些事件处理程序) ) 到您的 VM 上的属性。每当用户拖动时,您将能够看到值何时更新,并可以进行相应处理。

就滑动条的“隐藏”效果而言,您可能更容易进入 slider 的视觉状态。 Here are the styles and visual states.

编辑:

public class VideoPlayerViewModel : ViewModelBase
{
// your existing properties here, if you decide that you still need them

// this could also be long/double, if you'd like to use it with your underlying type (DateTime.TotalTicks, TimeSpan.TotalSeconds, etc.)
private uint _elapsedTime = 0; //or default(uint), whichever you prefer
public uint ElapsedTime
{
get { return _elapsedTime; }
set
{
if (_elapsedTime != value)
{
_elapsedTime = value;
//additional "time changed" logic here, if needed
//if you want to skip programmatically, all you need to do is set this property!
OnPropertyChanged();
}
}
}

private double _maxTime = 0;
public double MaxTime
{
// you get the idea, you'll be binding to the media's end time in whatever unit you're using (i.e. if I have a 120 second clip, this value would be 120 and my elapsed time would be hooked into an underlying TimeSpan.TotalSeconds)
}
}

在你的 slider 上:

Value={Binding ElapsedTime, Mode=TwoWay}
Maximum={Binding MaxTime, Mode=OneWay} //could also be OneTime, depending on the lifecycle of the control

关于c# - 将方法从 View 移动到 View 模型 - WPF MVVM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47000033/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com