C# 绑定到嵌套属性WPF C时缺少通知#

C# 绑定到嵌套属性WPF C时缺少通知#,c#,wpf,xaml,binding,inotifypropertychanged,C#,Wpf,Xaml,Binding,Inotifypropertychanged,我正在尝试将按钮的属性绑定到自定义类的布尔属性,但无法获取任何通知 我的viewmodel中有以下属性: public MediaPlayerModel MediaPlayer { get; set; } 其中,类型的书写方式如下: public class MediaPlayerModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private

我正在尝试将按钮的
属性绑定到自定义类的布尔属性,但无法获取任何通知

我的viewmodel中有以下属性:

public MediaPlayerModel MediaPlayer { get; set; }
其中,类型的书写方式如下:

public class MediaPlayerModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private MediaPlayerState _currentState;
    public MediaPlayerState CurrentState
    {
        get => _currentState;
        protected set
        {
            if (!Equals(value, _currentState))
            {
                _currentState = value;
                OnPropertyChanged();
            }
        }
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}
[Serializable]
public sealed class MediaPlayerState : BaseState
{
    public bool IsRunning { get; }

    //..
}

public class BaseState : IEquatable<BaseState> {..}
[ValueConversion(typeof(MediaPlayerState), typeof(Visibility))]
public class TestConverter : BaseConverter, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        var running = ((MediaPlayerState)value).IsRunning;
        if (running)
        {
            return Visibility.Visible;
        }
        return Visibility.Hidden;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        return null;
    }
}
private void MediaPlayerOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(MediaPlayer.CurrentState))
    {
        OnPropertyChanged(nameof(MediaPlayer));
    }
}
MediaPlayerState的声明如下:

public class MediaPlayerModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private MediaPlayerState _currentState;
    public MediaPlayerState CurrentState
    {
        get => _currentState;
        protected set
        {
            if (!Equals(value, _currentState))
            {
                _currentState = value;
                OnPropertyChanged();
            }
        }
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}
[Serializable]
public sealed class MediaPlayerState : BaseState
{
    public bool IsRunning { get; }

    //..
}

public class BaseState : IEquatable<BaseState> {..}
[ValueConversion(typeof(MediaPlayerState), typeof(Visibility))]
public class TestConverter : BaseConverter, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        var running = ((MediaPlayerState)value).IsRunning;
        if (running)
        {
            return Visibility.Visible;
        }
        return Visibility.Hidden;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        return null;
    }
}
private void MediaPlayerOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(MediaPlayer.CurrentState))
    {
        OnPropertyChanged(nameof(MediaPlayer));
    }
}
按钮的可见性永远不会改变,转换器的方法也永远不会被调用

我确实提出了一个替代解决方案,但对我来说,这似乎是一个黑客攻击,不是一个正确的修复,它为其他潜在的bug打开了一扇门

我将可见性属性绑定到
MediaPlayer
属性本身,而不是嵌套属性:

Visibility=“{Binding MediaPlayer…unchanged}

在主窗口的
加载事件期间,我从
MediaPlayerModel
类订阅
PropertyChanged
事件:

MediaPlayer.PropertyChanged+=MediaPlayerPropertyChanged;

其中,事件处理程序的实现如下所示:

public class MediaPlayerModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private MediaPlayerState _currentState;
    public MediaPlayerState CurrentState
    {
        get => _currentState;
        protected set
        {
            if (!Equals(value, _currentState))
            {
                _currentState = value;
                OnPropertyChanged();
            }
        }
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}
[Serializable]
public sealed class MediaPlayerState : BaseState
{
    public bool IsRunning { get; }

    //..
}

public class BaseState : IEquatable<BaseState> {..}
[ValueConversion(typeof(MediaPlayerState), typeof(Visibility))]
public class TestConverter : BaseConverter, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        var running = ((MediaPlayerState)value).IsRunning;
        if (running)
        {
            return Visibility.Visible;
        }
        return Visibility.Hidden;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        return null;
    }
}
private void MediaPlayerOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(MediaPlayer.CurrentState))
    {
        OnPropertyChanged(nameof(MediaPlayer));
    }
}
这使得它可以工作,但这很奇怪,因为这证明事件实际上是在正确的时间触发的,但是绑定似乎不起作用


造成这种情况的原因是什么?为什么我无法绑定到一个嵌套属性,该属性有一个有效的
INotifyPropertyChanged
事件触发?它的修复方法是什么?

您发布的对我有效的实现是:

<Window ... xmlns:vm="clr-namespace:MyApp.ViewModels" ... >
    <Window.DataContext>
        <vm:ViewModelContainingMediaPlayer />
    </Window.DataContext>
        ...
        <Button Visibility="{Binding MediaPlayer.CurrentState, Converter={StaticResource TestConverter}}" ... />
        ...
</Window>

...
...

您可以发布您的
INotifyPropertyChanged
实现吗?它是否适用于任何其他绑定?以及
OnPropertyChanged()
正在被调用,即值是否确实正在更改/设置?@ChrisMack我包含了实现细节,是的,但这不应该是问题。如果您还没有这样做,我会尝试一些更基本的方法,例如向类添加布尔属性,并查看它是否会成功绑定到该属性。这将确认
>DataContext
设置正确。
MediaPlayer.CurrentState
需要实现INPC。您需要使用布尔到可见性转换器绑定到
MediaPlayer.CurrentState.IsRunning
。不要太聪明。只需1)命名将在绑定路径中更改的属性,以便绑定知道要侦听的内容;2)使用拥有更改的属性的e类必须实现INPC并为更改的属性引发PropertyChanged。如果您试图智胜框架,您可能会成功——祝贺您!但如果您愿意,请不要抱怨。我刚刚构建了您的解决方案,它在当前状态下对我有效。我会在
se中设置一个断点t
并确保它确实被调用。这正是我所拥有的。嗯,根据您在上面写的最后一条评论,是否确实是ViewModel上的MediaPlayer正在更改?您似乎有多个?即,我上面的实现不需要注册任何依赖属性。是的,我只设置了一次在开始时,我使用thr vm afterOk中的一个,我已经实现了,它仍然对我有效。当调用
set
访问器时,您是否尝试检查
IsRunning
的值?