【问题标题】:WPF Cant find source for binding with reference - xamlWPF 找不到与参考绑定的源 - xaml
【发布时间】:2018-04-01 21:33:20
【问题描述】:

我是 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”的绑定源。绑定表达式:路径=TotalSeconds;数据项=空;目标元素是'ThumbDragSlider'(名称='sMovieSkipSlider');目标属性是“值”(类型“双”)

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    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 看看它的样子。

    【讨论】:

    • 该字段包含在 xaml sn-p 所在的同一类中。
    • @Deadzone 那是什么类?您的窗口还是 UserControl?
    • 是的,这是窗口类。
    • @Deadzone 在这种情况下,我答案中的最后一个版本的代码应该适合你。
    • 我正在尝试将 xaml 版本与相对源一起使用,其中绑定是您包含的属性,但它似乎不起作用。我会对INotifyPropertyChanged 模型更感兴趣。
    猜你喜欢
    • 2011-10-21
    • 2013-03-07
    • 1970-01-01
    • 1970-01-01
    • 2012-12-31
    • 2011-05-24
    • 2011-02-28
    • 1970-01-01
    • 2020-05-14
    相关资源
    最近更新 更多