【发布时间】:2014-05-27 13:25:08
【问题描述】:
我们当前的应用程序将每个View 包装成一个Window(这只是一个原型应用程序)。每个View/Window 都有一个ViewModel 分配为DataContext。现在我的问题是,当Window/View 关闭时,释放ViewModel 的做法是什么?
我尝试处理Window 的关闭事件,并将DataContext 设置为NULL。我的 ViewModelBase 类实现 IDisposable 接口。但是在调试的时候,发现没有调用 Dispose() 函数。当我使用内存分析器时,我看到ViewModel 从未被释放。
那么释放ViewModel的正确做法是什么
更新:
两个潜在的内存泄漏源:
- 我正在使用
IEventAggregator进行事件发布/订阅。我正在使用 Prism 4.1 中的EventAggregator类,但只是将其包装在一个 Singleton 类中(它实现了 IEventAggregator 接口,因为我们还不想使用依赖注入)。
在ViewModel/View 内部,我只使用(VB.NET 中的代码)
_ea.GetEvent(Of MyEventType).Publish(MyEventObject)
_ea.GetEvent(Of MyEventType).Subscribe(AddressOr MyEventHandler)
- 我正在使用一些 ActiveX 控件。我正在测试的一个是使用来自 OWC(Office Web 组件)的数据透视表。而且我承认我不知道如何在 MVVM 世界中处理这种控制。我通常有
ViewModel直接持有这样一个控件的成员,我认为这违反了MVVM的规则,这也是我目前只能在@987654339的代码隐藏中对ViewModel进行硬编码的原因@。
例如,在代码隐藏中,我有这样一行:
Me.DataContext = New MyViewModel(Me.pTable)
初始化DataContext
而在ViewModel的构造函数中,我通常会做两件事:
a) 设置/更改(在构造函数或函数中)ActiveX 控件的属性,如下所示:
Me.pTable.DisplayDesignTimeUI = False
b) 处理来自ActiveX Control 的事件
AddHandler pTable.DblClick, AddressOf DblClickHandler
AddHandler pTable.SelectionChange, AddressOf PivotTableSelectionChangedHandler
我承认这种“让 ViewModel 处理 ActiveX 控件”的用法对我来说似乎并不好。但这些控制对我们来说是必要的。
【问题讨论】:
-
您是在代码中将 DataContext 分配为硬引用 (myView.DataContext = new ViewModel();) 还是通过 Binding 提供它?绑定应该允许 ViewModel 被删除,第一个可能有问题。仍然处理 Closing-Event 应该可以工作。任何所有 VM 都使用的单例?
-
我遇到了同样的问题,并通过让 VM 从指定关闭事件委托的接口继承来解决它。
-
@Gope 对于一些
View(以及我正在测试的那个),我确实在代码隐藏中使用了硬引用(最终目标是删除这种做法,但目前我们必须使用它)。是的,我们在ViewModel中确实有一些单身人士。一些ServiceLocator和EvengAggregator我们只是使用 Singleton 实现的。它如何影响参考? -
@Gope 更糟糕的是,我从内存分析器中看到的根路径可能会阻止内存被释放,它链接到一些 .net ActiveX 控件(VM 作为成员)。这可能是一团糟,但这是我发现处理此类控件的唯一方式
-
@GayotFow 让虚拟机直接处理此类事件是个好主意吗?因为以后可能会改代码所以没有关闭事件/
Window,部分地区只有UserControl