Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 带嵌入类的冒泡NotifyPropertyChange_C#_Wpf_Mvvm_Caliburn.micro - Fatal编程技术网

C# 带嵌入类的冒泡NotifyPropertyChange

C# 带嵌入类的冒泡NotifyPropertyChange,c#,wpf,mvvm,caliburn.micro,C#,Wpf,Mvvm,Caliburn.micro,所以这里有一个问题让我绕圈子。我正在使用一个嵌入式类结构,它需要保持其子对象的私有性,但应该能够从这些子对象中的数据向上传递某些NotifyOfPropertyChange事件。最好的方法是什么 我当前的方法是下面的代码,其中我的SystemViewModel视图(SystemView)有一个绑定到CommunicationStatus属性的元素,我有一个父类SystemViewModel,它有一个子类CommunicationManager,它有子类Communicator,如下所示 困难的事

所以这里有一个问题让我绕圈子。我正在使用一个嵌入式类结构,它需要保持其子对象的私有性,但应该能够从这些子对象中的数据向上传递某些NotifyOfPropertyChange事件。最好的方法是什么

我当前的方法是下面的代码,其中我的SystemViewModel视图(SystemView)有一个绑定到
CommunicationStatus
属性的元素,我有一个父类SystemViewModel,它有一个子类CommunicationManager,它有子类Communicator,如下所示

困难的事情:

1) 在这种情况下,必须假设通信器没有系统视图模型的可见性,因此在通信器的
Connected
属性的
set
方法中放置
NotifyOfPropertyChanged(()=>CommunicationStatus)
。。。除非我遗漏了一些明显的东西

2) SystemViewModel不能直接访问Communicator,因此无法从
SystemView.xaml
绑定到连接的
Connected

在我看来,
Connected
中的NotifyOfPropertyChanged事件应该会出现在父类中,因为在所有类中都实现了
PropertyChangedBase
,但这并没有发生。我愿意帮忙

public class SystemViewModel : PropertyChangedBase
{
    private CommunicationManager CommunicationManager;
    public string CommunicationStatus
    {
        get
        {
            if (CommunicationManager.YepConnected)
            {
                return "Green";
            }
            else
            {
                return "Red";
            }
        }
    }
}

public class CommunicationManager : PropertyChangedBase
{
    private Communicator Communicator;
    public bool YepConnected { get { return Communicator.Connected; } }
}

public class Communicator: PropertyChangedBase
{
    private bool _connected;

    public bool Connected
    {
        get { return _connected; }
        set 
        {
            _connected = value;
            NotifyOfPropertyChange(() => Connected);
        }
    }
}
编辑

因此,它似乎工作正常,并按预期将事件从子类传播到父类。真正的问题是WPF绑定与属性之间的关系,这一点更为隐蔽。仅供参考,我使用的XAML如下所示:

<TextBlock Text="Status" Background="{Binding CommunicationStatus}"/>
是的,如果你做得不完美,那就是即时堆栈溢出(双关语:) 每当
Connected
的值改变时,我观察到
CommunicationStatus
get
方法就会执行。通过这样做,该执行将导致另一次执行
get
方法,只是这次XAML会更新


有人能解释为什么这个解决方案有效和/或提供一个更雄辩的解决方案吗?

下面是一个如何使用ReactiveUI实现这一点的示例

public class SystemViewModel : ReactiveObject
{
    private readonly CommunicationManager communicationManager;
    private readonly ObservableAsPropertyHelper<string> connectionStatus;

    public SystemViewModel( CommunicationManager communicationManager )
    {
        this.communicationManager = communicationManager ?? throw new ArgumentNullException(nameof(communicationManager));
        this.communicationManager
            .WhenAnyValue( e => e.YepConnected, state => state ? "Green" : "Red" )
            .ToProperty( this, e => e.ConnectionStatus, out connectionStatus );
    }
    public string ConnectionStatus => connectionStatus.Value;
}
简单测试

var communicator = new Communicator();
var manager = new CommunicationManager(communicator);
var vm = new SystemViewModel( manager );

vm.PropertyChanged += (s,e) => Console.WriteLine( "SystemViewModel.{0} changed", e.PropertyName );

communicator.Connected = true;
communicator.Connected = false;
生成输出

SystemViewModel.ConnectionStatus changed SystemViewModel.ConnectionStatus changed SystemViewModel.ConnectionStatus已更改 SystemViewModel.ConnectionStatus已更改
这是一个基本的类OO理论——简单地包装或隐藏属性。因此,您捕获来自成员实例的通知,并且只传递(传播)您特别允许的通知。我想我的问题是包装机制以及通知如何传播。如果我在
get
方法中包装一个成员实例的属性,那么它的通知是否仅仅因为在包装器中而在包装器中自动发出?或者更确切地说,如果我的get是
ParentMethod{get{Child.A*Child.B*Child.C}
,那么从
A
B
C
引发的通知是否会导致在
ParentMethod
中引发通知?这个问题的答案是肯定的。这个问题更为复杂。请参阅更新的编辑
public class Communicator : ReactiveObject
{
    private bool _connected;
    public bool Connected
    {
        get { return _connected; }
        set { this.RaiseAndSetIfChanged( ref _connected, value); }
    }
}
var communicator = new Communicator();
var manager = new CommunicationManager(communicator);
var vm = new SystemViewModel( manager );

vm.PropertyChanged += (s,e) => Console.WriteLine( "SystemViewModel.{0} changed", e.PropertyName );

communicator.Connected = true;
communicator.Connected = false;
SystemViewModel.ConnectionStatus changed SystemViewModel.ConnectionStatus changed