我是 WPF 和 xaml 的新手,我正在制作视频播放器。我目前正在尝试将电影时间滑块绑定到我存储在一个TimeSpan
变量中的当前经过时间,该变量通过 a 每秒更新一次DispatcherTimer
。
这是我的 xaml:
<customControls:ThumbDragSlider x:Name="sMovieSkipSlider" Height="25" Margin="65,0,65,71" VerticalAlignment="Bottom"
Value="{Binding ElementName=_movieElapsedTime, Path = TotalSeconds, Mode=OneWay}"
DragStarted="SMovieSkipSlider_OnDragStarted"
DragCompleted="SMovieSkipSlider_OnDragCompleted"/>
这是变量的声明方式:
private TimeSpan _movieElapsedTime;
这是我得到的错误:
System.Windows.Data 错误:4:无法找到引用“ElementName=_movieElapsedTime”的绑定源。BindingExpression:Path=TotalSeconds; 数据项=空;目标元素是 'ThumbDragSlider' (Name='sMovieSkipSlider'); 目标属性是“值”(类型“双”)
ElementName
用于引用 XAML 中的元素。如果您有一个控件,例如...
<TextBox x:Name="_movieElapsedTime" />
那么你拥有它的方式就会有意义——如果它碰巧有一个名为TotalSeconds
.
你也不能绑定到一个字段;它必须是带有 get 和 set 的常规 C# 属性,或者是一种称为依赖属性的特殊属性。
但是让我们用一个视图模型来做这件事。视图模型是实现 的任何随机类INotifyPropertyChanged
,并PropertyChanged
在其属性值更改时引发事件。它跟踪您的应用程序的内部结构。它不知道存在用户界面。它公开诸如 MovieElapsedTime 之类的数据属性,并且还可以公开允许按钮或菜单项向视图模型发送命令的命令。它也可能有其父视图模型可能调用的方法。
我们将编写一个实现 的视图模型基类INotifyPropertyChanged
,并从中派生出一个简单的视图模型,代表视频播放器需要知道的内容。然后我们将在 XAML 中创建一个 UI,让用户与其交互。
您可能希望视图模型具有启动和停止视频等的命令。在谷歌上很容易找到。我建议使用 RelayCommand/DelegateCommand 类;谷歌这些,你会看到他们做什么。有很多例子你可以窃取代码。
#region ViewModelBase Class
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
#endregion INotifyPropertyChanged
}
#endregion ViewModelBase Class
#region VideopPlayerViewModel Class
public class VideopPlayerViewModel : ViewModelBase
{
#region MovieElapsedTime Property
private TimeSpan _movieElapsedTime = default(TimeSpan);
public TimeSpan MovieElapsedTime
{
get { return _movieElapsedTime; }
set
{
if (value != _movieElapsedTime)
{
_movieElapsedTime = value;
OnPropertyChanged();
}
}
}
#endregion MovieElapsedTime Property
}
#endregion VideopPlayerViewModel Class
主窗口构造函数:
public MainWindow()
{
InitializeComponent();
DataContext = new VideoPlayerViewModel();
}
XAML。因为 AVideoPlayerViewModel
是我们窗口的 DataContext,这意味着当您告诉绑定绑定到 时MovieElapsedTime
,没有关于在哪里找到它的更多信息,它将转到DataContext
它从窗口继承的对象。
<customControls:ThumbDragSlider
Value="{Binding MovieElapsedTime.TotalSeconds, Mode=OneWay}"
x:Name="sMovieSkipSlider"
Height="25"
Margin="65,0,65,71"
VerticalAlignment="Bottom"
DragStarted="SMovieSkipSlider_OnDragStarted"
DragCompleted="SMovieSkipSlider_OnDragCompleted"/>
这是依赖属性版本。这不是“正确的做法”,但并不完全糟糕。
下一个问题:MovieElapsedTime 是什么成员?窗户?什么是数据上下文?如果您在窗口上设置DataContext = this
并实现INotifyPropertyChanged
,并PropertyChanged
在MovieElapsedTime
更改时引发,由于其他原因,这是一个坏主意,但您的绑定将MovieElapsedTime
作为常规属性使用。如果没有,你需要这个:
<customControls:ThumbDragSlider
Value="{Binding MovieElapsedTime.TotalSeconds, Mode=OneWay, RelativeSource={RelativeSource AncestorType=Window}}"
x:Name="sMovieSkipSlider"
Height="25"
Margin="65,0,65,71"
VerticalAlignment="Bottom"
DragStarted="SMovieSkipSlider_OnDragStarted"
DragCompleted="SMovieSkipSlider_OnDragCompleted"/>
窗口代码隐藏:
public TimeSpan MovieElapsedTime
{
get { return (TimeSpan)GetValue(MovieElapsedTimeProperty); }
set { SetValue(MovieElapsedTimeProperty, value); }
}
public static readonly DependencyProperty MovieElapsedTimeProperty =
DependencyProperty.Register(nameof(MovieElapsedTime), typeof(TimeSpan), typeof(MainWindow),
new PropertyMetadata(null));
以这种方式定义属性而不是您拥有的属性。有了所有这些东西,当您将属性设置为新值时,控件将自动接收通知。
您应该真正编写一个视图模型,它实现INotifyPropertyChanged
并使其成为视图模型的属性。如果您有兴趣,我们可以通过它。
但是,如果您希望更新顺利进行,我认为您需要每秒进行多次轮询。更有可能每 500 毫秒甚至 250 毫秒。尝试 500,看看它看起来如何。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句