【发布时间】:2014-02-05 08:52:28
【问题描述】:
我遇到了一个问题,让我大吃一惊。
我们从ButtonBase来看这些方法:
private void HookCommand(ICommand command)
{
CanExecuteChangedEventManager.AddHandler(command, OnCanExecuteChanged);
UpdateCanExecute();
}
private void OnCanExecuteChanged(object sender, EventArgs e)
{
UpdateCanExecute();
}
private void UpdateCanExecute()
{
if (Command != null)
{
CanExecute = MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource(this);
}
else
{
CanExecute = true;
}
}
HookCommand 在您为按钮分配新命令时被调用。它通过弱事件管理器订阅CommandManager.RequerySuggested 并更新按钮状态(启用/禁用)。
OnCanExecuteChanged 只是一个事件处理程序,当您使用与RoutedCommand 不同的东西时,UpdateCanExecute 最终会调用您的ICommand.CanExecute。当您使用任何 MVVM 框架时都是这种情况。
现在,问题来了。
我的一个数据模板应用于ContentControl 以显示一些数据:
<ContentControl Grid.Row="0" Content="{Binding}" ContentTemplate="{StaticResource TemplateState}"/>
此模板包含在另一个ContentControl 内相当复杂的可视化树中,该树托管在ElementHost 中(这是WinForms MDI 应用程序中的一个WPF 组件)。
此模板中有几个按钮,其Command 属性绑定到RelayCommands。
当我关闭包含使用此数据模板呈现的视觉效果的 MDI 子级时,按钮会尝试更新其状态并调用 OnCanExecuteChanged。这是个大问题,因为CanExecute 调用了一些一次性对象,该对象已经被释放了。
我知道:
1)此时窗口(WinForms窗体)关闭,因为CanExecute是在处理完Form.Closed事件后调用的;
2) 没有内存泄漏 - 如果我模拟 CanExecute,内存分析器显示,我的包含命令的视图模型被 GC 收集并且不再存在。
问题。
如果按钮不可见,检查CanExecute 的目的是什么?
是否有任何选项可以防止这种行为?
附:
我看到的唯一解决方法是在我的视图模型中的某处保留一个标志,这将显示一次性已处理,并从CanExecute 返回false。
有更好的想法吗?
【问题讨论】:
-
想知道为什么一些 Microsoft 开发人员以他们的方式开发东西有什么意义……他们只是出于某种原因这样做。在尝试使用
disposableObject之前先使用旧的if (disposableObject != null)怎么样? -
@Sheridan:这种行为可能是有原因的,我做错了什么。
disposableObject不是空的,它只是被处理掉了,检查一些标志是我建议的解决方法。 -
“它订阅了 CommandManager.RequerySuggested”,我猜这就是问题所在,因为你的所有命令都与这个事件挂钩,当你调用 InvalidateRequerySuggested() 时,它们都会被重新评估,当你关闭你的窗口。
-
@Dtex:没错。但是当按钮不可见时,我想不出一个理由来检查影响视觉状态的东西。
-
我的建议与您的解决方法基本相同,如果您的视图模型被处置,则返回 false。
标签: c# wpf mvvm weak-references