WPF无法找到与引用绑定的源 - xaml

时间:2017-10-20 16:47:57

标签: c# wpf xaml

我是WPF和xaml的新手,我正在制作视频播放器。我目前正在尝试将电影时间滑块绑定到当前经过的时间,该时间存储在TimeSpan变量中,该变量每秒更新一次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:路径= TotalSeconds;的DataItem = NULL; target元素是'ThumbDragSlider'(Name ='sMovieSkipSlider'); target属性为'Value'(类型'Double')

1 个答案:

答案 0 :(得分:1)

ElementName用于指代XAML中的元素。如果您有控件,例如......

<TextBox x:Name="_movieElapsedTime" />

然后,如果碰巧有一个名为TotalSeconds的属性,它就会有意义。

您也无法绑定到某个字段;它必须是带有get和可能的set的常规C#属性,或者是一种称为依赖属性的特殊属性。

但是让我们用viewmodel来做这个。 viewmodel是实现INotifyPropertyChanged的任何随机类,并在其属性值更改时引发PropertyChanged事件。它跟踪您的应用程序的内部。它不知道存在用户界面。它公开了像MovieElapsedTime这样的数据属性,并且可以公开命令,允许按钮或菜单项将命令发送到视图模型。它也可能具有其父视图模型可能调用的方法。

我们将编写一个实现INotifyPropertyChanged的viewmodel基类,并从中派生一个简单的视图模型,表示视频播放器需要知道的事物。然后我们将在XAML中创建一个允许用户与之交互的UI。

您可能希望viewmodel具有启动和停止视频的命令,依此类推。这很容易在谷歌上找到。我建议使用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时,没有关于在哪里找到它的更多信息,它将转到{{1}它从窗口继承的对象。

DataContext

非MVVM版本

这是依赖属性版本。这不是“正确的做法”,但并不是完全可怕的。

下一个问题: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"/> 实施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)); 的viewmodel,并使其成为viewmodel的一个属性。如果你有兴趣,我们可以通过。

但是,如果您希望更新顺利,我认为您需要每秒轮询一次以上。更有可能每500毫秒甚至250.尝试500,看看它的外观。