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
MainWindow 构造函数:
public MainWindow()
{
InitializeComponent();
DataContext = new VideoPlayerViewModel();
}
XAML。因为 A VideoPlayerViewModel 是我们窗口的 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"/>
非 MVVM 版本
这是依赖属性版本。这不是“正确的做法”,但也不是很糟糕。
下一个问题:MovieElapsedTime 是什么成员?窗户?什么是数据上下文?如果您设置DataContext = this 并且在您的窗口上实现INotifyPropertyChanged,并且在MovieElapsedTime更改时提高PropertyChanged,由于其他原因,这是一个坏主意,但是您的绑定将使用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 看看它的样子。