【发布时间】:2020-02-10 23:15:08
【问题描述】:
所以这是一个让我在圈子里跑来跑去的问题。我正在使用一个嵌入式类结构,它需要将其子对象保持私有,但应该能够从这些子对象中的数据向上传递某些 NotifyOfPropertyChange 事件。做这个的最好方式是什么。
我当前的方法是下面的代码,其中我的 SystemViewModel (SystemView) 视图有一个绑定到 CommunicationStatus 属性的元素,并且我有一个父类 SystemViewModel,它具有子类 CommunicationManager,它具有子类 Communicator,如下所示。
让事情变得困难的事情:
1) 在这种情况下,必须假设 Communicator 对 SystemViewModel 不可见,因此不应将 NotifyOfPropertyChanged(() => CommunicationStatus) 放在 Communicator 的 Connected 属性的 set 方法中......除非我错过了很明显的东西。
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}"/>
另外,我使用了SolidColorBrush 而不是string(尽管它们都绑定相同并且可以工作)。
问题在于,当通知事件从 Connected 向上传播到 CommunicationStatus 时,它会停在那里并且不会传播到 XAML 绑定(在我的代码中,CommunicationStatus 没有在 XAML 绑定中使用)。我知道绑定有效,因为通过调试我观察到当程序最初运行时,在执行 CommunicationStatus get 方法时颜色设置为红色,大概是从 XAML 绑定调用的。代码运行后,CommunicationStatus 会在 Connected 更新时更新,但 XAML 绑定不再观察到该更改。如果我手动实现NotifyOfPropertyChange(() => CommunicationStatus);,绑定元素决定更新。但是,因为我没有在CommunicationStatus 中使用任何类型的set 方法(并且通知事件不会向上传播),所以似乎没有一种直接的方式来通知 XAML 我的值变了。
粗略解决方案:注意CommunicationStatus 的更改并引发NotifyOfPropertyChange(() => CommunicationStatus); 事件,如下所示:
public class SystemViewModel : Conductor<object>
{
private CommunicationManager CommunicationManager;
private SolidColorBrush LastCommunicationStatusValue = new SolidColorBrush();
public SolidColorBrush CommunicationStatus
{
get
{
SolidColorBrush CurCommunicationStatusValue;
if (CommunicationManager.YepConnected)
{
CurCommunicationStatusValue = new SolidColorBrush(Colors.Green);
}
else
{
CurCommunicationStatusValue = new SolidColorBrush(Colors.Red);
}
if (CurCommunicationStatusValue.Color != LastCommunicationStatusValue.Color)
{
LastCommunicationStatusValue = CurCommunicationStatusValue;
NotifyOfPropertyChange(() => CommunicationStatus);
}
return CurCommunicationStatusValue;
}
}
}
是的,如果你不能完美地做到这一点,那就是即时堆栈溢出(双关语:)
每当Connected 的值发生变化时,我观察到CommunicationStatus 的get 方法会执行。通过这样做,该执行会导致 get 方法的另一次执行,只是这次 XAML 更新。
谁能解释为什么这个解决方案有效和/或提供一个更有说服力的解决方案?
【问题讨论】:
-
使用 ReactiveUI 非常简单
-
这是基本的面向对象理论——简单地包装或隐藏属性。因此,您从成员实例中捕获通知,并且只传递(传播)您特别允许的通知。
-
我想我的问题是包装机制以及通知如何传播。如果我将成员实例的属性包装在
get方法中,它的通知是否会因为它在包装器中而自动在包装器中引发?或者更确切地说,如果我得到的是ParentMethod { get {Child.A*Child.B*Child.C} },那么来自A、B、C的引发通知是否会导致ParentMethod中的引发通知? -
这个问题的答案是肯定的。这个问题更复杂。查看更新的编辑
标签: c# wpf mvvm caliburn.micro