[英]Why ButtonBase doesn't check its Visibility before testing `ICommand.CanExecute`?
我遇到了一個問題,這讓我大吃一驚。
讓我們從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
內的相當復雜的可視樹中,該ContentControl
托管在ElementHost
(這是WinForms MDI應用程序中的WPF組件)。 該模板內有幾個按鈕,其Command
屬性綁定到RelayCommand
。
當我關閉使用此數據模板渲染的包含視覺效果的MDI子項時,按鈕會嘗試更新其狀態並調用OnCanExecuteChanged
。 這是一個很大的問題,因為CanExecute
調用了一些已經被丟棄的一次性對象。
我知道,認為:1)的窗口(WinForms的形式)此時關閉,因為CanExecute
后稱為Form.Closed
事件被處理; 2)沒有內存泄漏-如果我模擬CanExecute
,內存事件探查器顯示,包含命令的視圖模型是由GC收集的,不再存在。
問題。
如果按鈕不可見,檢查CanExecute
的目的是什么? 有什么選擇可以防止這種行為?
PS我看到的唯一解決方法是在視圖模型中的某個位置保留一個標志,該標志將顯示已處理了一次性物品,並從CanExecute
返回false
。 還有更好的主意嗎?
我將給出四個可能的答案,並對如何以這種方式實現它進行猜測:
在處置所有內容之前,將要拆除的窗口的DataContext
設置為null
。 該按鈕在對象上沒有引用,因此永遠不會引發異常。
將對一次性對象的調用包裝在try / catch中,該對象過濾ObjectDisposedException
並返回false。
將IsDisposed
屬性添加到一次性對象,並事先檢查。 如果您在非UI或終結器線程上執行任何操作,似乎這里可能存在爭用情況。
如果正在等待終結器調用Dispose
,則將WeakReference
保持為可拋棄對象,或者在調用Dispose()
之后將引用設置為null
,並在調用它之前檢查其是否為null
。
至於為什么即使在不可見的情況下也要查詢命令,請考慮命令的結果可以控制可見性。 想象以下情況:
<!-- This would probably have to be done in some more complicated way, like
passing IsEnabled to a converter with CanExecute as the parameter, or
by just binding to IsEnabled. -->
<Button Visibility="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=CanExecute}"
Command="{Binding TheCommand" Content="Do it" />
如果不查詢按鈕的狀態是隱藏的,則一旦禁用它就永遠不會顯示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.