【发布时间】:2014-09-01 08:59:04
【问题描述】:
我的应用程序使用 MVVM 架构,而 ViewModel 不了解 View。当 ViewModel 对象需要显示新视图时,它会公开一个公共 ShowNewView 属性,该属性是一个对象,其类基于我的 ViewModel 基类。 WPF 视图将自定义的 DependencyProperty 绑定到此,并使用 PropertyChangedCallback 构造和显示适当的窗口。
这在第一次设置ShowNewView 属性时运行良好。但是,如果用户关闭窗口然后尝试重新打开它,则在引发 PropertyChanged 事件并且不调用 PropertyChangedCallback 时,ShowNewView 属性的值没有改变。
为了“欺骗”DependencyProperty 检测值已更改(即使存储在 ViewModel 属性中的值可能实际上并未更改),我使用了 Window 类公开的 SetCurrentValue 方法来强制DependencyProperty 的值为null。
#region ShowNewViewProperty
private static readonly DependencyProperty _ShowNewViewProperty =
DependencyProperty.RegisterAttached
(
"ShowNewView",
typeof(IRootViewModel),
typeof(WpfViewWindow),
new PropertyMetadata(ShowNewViewPropertyChanged)
);
public static DependencyProperty ShowNewViewProperty { get { return _ShowNewViewProperty; } }
public static IRootViewModel GetShowNewView(Window source)
{
return (IRootViewModel)source.GetValue(ShowNewViewProperty);
}
public static void SetShowNewView(Window target, IRootViewModel value)
{
target.SetValue(ShowNewViewProperty, value);
}
private static void ShowNewViewPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
WpfViewWindow window = d as WpfViewWindow;
IRootViewModel newValue = e.NewValue as IRootViewModel;
if ((null != window) && (null != newValue))
{
// Create a child WpfViewWindow. This method is part of my
// framework that uses ResourceDictionary entries, imported by MEF
// to locate the View class corresponding to the ViewModel parameter's
// class.
WpfViewWindow modelessWindow = window.CreateWpfViewWindow(newValue);
if (null != modelessWindow)
{
// Show the new WpfViewWindow.
modelessWindow.Show();
}
// Clear the current value so that the next PropertyChanged event
// is processed even if the underlying value has not actually changed.
window.SetCurrentValue(ShowNewViewProperty, null);
}
}
#endregion
从技术上讲,这是可行的,因为它会导致在 PropertyChanged 事件触发时运行回调,而不管值是否实际更改。但是,它会导致每次更新 ViewModel 的属性时调用(递归)两次回调:一次响应 ViewModel 的事件,一次响应调用的 SetCurrentValue 方法。
这里有许多与在其他情况下未调用或未多次调用 PropertyChangedCallback 相关的问题。
- PropertyChangedCallback on DependencyProperty Only Firing Once 涵盖了属性是集合,集合内容发生变化,而集合本身没有变化的情况。但是,我的财产不是收藏品,一切都按照记录在工作。
- WPF dependency property setter not firing when PropertyChanged is fired, but source value is not changed 看起来很有希望,但答案只建议使用我已经使用的回调。
是否有更优雅的方法来实现这一点,不会导致来自 ViewModel 的每个 PropertyChanged 事件运行两次回调? IE。有没有办法绕过框架的检查来验证新旧值是否不同?
澄清
正在创建的视图不一定总是 WPF 窗口,例如,在我的单元测试中它是一个模拟,而在项目的后期它可能是一个单独的日志程序集。也不是所有 ViewModel 对象都来自同一个程序集,众所周知,未来将需要额外的功能,但具体细节目前尚未定义。该应用程序允许用户通过简单的网络连接设备。最初网络是 RS-485 上的 ModbusRTU,但是,最终客户可能想要使用 CANOpen 或 Profinet 或其他一些传输层,我必须提供一种插件机制,允许在不更改现有功能的情况下添加新功能代码。
公平地说,我可以使用几种替代机制来实现相同的结果(即让 ViewModel 请求创建一个新视图),但我很想知道是否有办法制作 DependencyPropety '忘记'它之前的值是什么。
【问题讨论】: