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
的值?