【问题标题】:Why is the binding on my custom control not working?为什么我的自定义控件上的绑定不起作用?
【发布时间】:2020-01-04 22:22:14
【问题描述】:

我有一个 MainView,我在其中使用我创建的名为 VideoPlayer 的组件。 VideoPlayer 是一个 Grid,它有一个 MediaElement 以及一些按钮和一个滑块来控制视频播放。
我正在尝试通过将 VideoPlayer 中的属性绑定到 MainView 中的属性来设置要在 MainView 中播放的视频的路径。

相关部分代码如下:


来自 VideoPlayer.xaml 的片段:

<MediaElement 
    Name="MediaElement" 
    Grid.Row="0" 
    LoadedBehavior="Manual"
    Stretch="Uniform" 
    Source="{Binding VideoLocation}" />



来自 VideoPlayer.xaml.cs 的片段:

public string VideoLocation
{
    get { return (string)GetValue(VideoLocationProperty); }
    set { SetValue(VideoLocationProperty, value); }
}
public static readonly DependencyProperty VideoLocationProperty
    = DependencyProperty.Register("VideoLocation", typeof(string), typeof(VideoPlayer), new PropertyMetadata(null));



VideoPlayer用在MainView.xaml中,跟在MVVM后面:

<ReuseableComponents:VideoPlayer VideoLocation="{Binding VideoPath}"/>



这是 MainViewModel.cs 中的绑定属性 VideoPath:

private string _videoPath;
public string VideoPath
{
    get => _videoPath;
    set => SetProperty(ref _videoPath, value);
}



如果我删除 VideoLocation 绑定并在 MainView.xaml 中硬编码路径,视频将正常播放:

<ReuseableComponents:VideoPlayer VideoLocation="C:\Movies\FightClub.mp4"/>

所以,我认为问题在于 MainView 绑定而不是 VideoPlayer 绑定。


我在 MainView 中的所有其他属性绑定都有效,它们都遵循这种模式:

<ComponentName PropertyName="{Binding ViewModelPropertyName}">

其中 ViewModelPropertyName 在 MainView 中使用支持字段定义,并且 setter 调用 SetProperty()




编辑
我犯的错误是:在 VideoPlayer 的构造函数中,我有一行 DataContext = this; 我想我在某个教程的某个地方看到了它。无论如何,根据@Magnus 的建议,我删除了该行并将 VideoPlayer.xaml 更改为

<UserControl x:Name="TheControl" ...>
    <Grid DataContext={Binding ElementName=TheControl} ...>
    ...
    </Grid>
</UserControl>

以前 UserControl 没有设置 name 属性,而 Grid 没有设置 DataContext 属性。

【问题讨论】:

    标签: c# wpf mvvm data-binding


    【解决方案1】:

    问题可能是您在顶层将 VideoPlayer UserControl 的 DataContext 设置为自身。这意味着您覆盖了控件应继承的 MainView DataContext,即此绑定:

    <ReuseableComponents:VideoPlayer VideoLocation="{Binding VideoPath}"/>
    

    尝试绑定到 VideoPlayer 控件而不是 MainView DataContext。

    您可以改为在包含的元素上设置 VideoPlayer 的内部 DataContext,如下所示:

    <UserControl x:Name="TheControl" ...>
        <Grid DataContext={Binding ElementName=TheControl} ...>
            ...
        </Grid>
    </UserControl>
    

    【讨论】:

    • 做到了。我删除了“DataContext = this;”并使用了第二个 sn-p。现在一切都很好。谢谢你和@Mark Feldman!
    【解决方案2】:

    绑定是相对于您可能尚未设置的控件的 DataContext 完成的。您需要将其设置为相对于控件。给你的控件起一个这样的名字:

    <UserControl x:Class="YourApp.YourUserControl"
        ... etc ...
        x:Name="_this">
    

    然后直接绑定到那个:

    Source="{Binding ElementName=_this, Path=VideoLocation}"
    

    或者,您也可以使用将 AncestorType 设置为您的用户控件类型的 RelativeSource 绑定。

    【讨论】:

    • 那行不通。我在 VideoPlayer.xaml 和 MainView.xaml 中都试过了,我不确定你认为它应该进入哪一个。另外,我在 VideoPlayer 的构造函数中调用了DataContext = this;。 Idk 如果这算作设置 DataContext。
    • 那应该可以工作,对我来说当然可以。我注意到您将LoadedBehavior 设置为Manual,您实际上是在调用MediaElement.Play(),是吗?
    • 是的,我这样做是为了让视频不会自动播放。我有一个调用 .Play() 的按钮和另一个调用 .Pause()
    • 我可以建议的唯一另一件事是将您的属性更改为 Uri 类型而不是字符串。您绑定的 MediaElement 属性实际上是 Uri 类型; string 可以在我正在使用的 NET 版本上找到,但您使用的版本可能较旧?如果这不起作用,请在此处发布mcve,我会再为您寻找。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-25
    • 2021-02-18
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    相关资源
    最近更新 更多